Merge pull request #38541 from Microsoft/jjh/containerd
Windows: Experimental: ContainerD runtime
This commit is contained in:
commit
a3eda72f71
111 changed files with 4787 additions and 1780 deletions
|
@ -54,7 +54,7 @@ type Config struct {
|
|||
Env []string // List of environment variable to set in the container
|
||||
Cmd strslice.StrSlice // Command to run when starting the container
|
||||
Healthcheck *HealthConfig `json:",omitempty"` // Healthcheck describes how to check the container is healthy
|
||||
ArgsEscaped bool `json:",omitempty"` // True if command is already escaped (Windows specific)
|
||||
ArgsEscaped bool `json:",omitempty"` // True if command is already escaped (meaning treat as a command line) (Windows specific).
|
||||
Image string // Name of the image as it was passed by the operator (e.g. could be symbolic)
|
||||
Volumes map[string]struct{} // List of volumes (mounts) used for the container
|
||||
WorkingDir string // Current directory (PWD) in the command will be launched
|
||||
|
|
|
@ -60,8 +60,8 @@ type ImageBackend interface {
|
|||
type ExecBackend interface {
|
||||
// ContainerAttachRaw attaches to container.
|
||||
ContainerAttachRaw(cID string, stdin io.ReadCloser, stdout, stderr io.Writer, stream bool, attached chan struct{}) error
|
||||
// ContainerCreate creates a new Docker container and returns potential warnings
|
||||
ContainerCreate(config types.ContainerCreateConfig) (container.ContainerCreateCreatedBody, error)
|
||||
// ContainerCreateIgnoreImagesArgsEscaped creates a new Docker container and returns potential warnings
|
||||
ContainerCreateIgnoreImagesArgsEscaped(config types.ContainerCreateConfig) (container.ContainerCreateCreatedBody, error)
|
||||
// ContainerRm removes a container specified by `id`.
|
||||
ContainerRm(name string, config *types.ContainerRmConfig) error
|
||||
// ContainerKill stops the container execution abruptly.
|
||||
|
|
|
@ -29,7 +29,7 @@ func newContainerManager(docker builder.ExecBackend) *containerManager {
|
|||
|
||||
// Create a container
|
||||
func (c *containerManager) Create(runConfig *container.Config, hostConfig *container.HostConfig) (container.ContainerCreateCreatedBody, error) {
|
||||
container, err := c.backend.ContainerCreate(types.ContainerCreateConfig{
|
||||
container, err := c.backend.ContainerCreateIgnoreImagesArgsEscaped(types.ContainerCreateConfig{
|
||||
Config: runConfig,
|
||||
HostConfig: hostConfig,
|
||||
})
|
||||
|
|
|
@ -16,7 +16,6 @@ import (
|
|||
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/strslice"
|
||||
"github.com/docker/docker/builder"
|
||||
"github.com/docker/docker/errdefs"
|
||||
|
@ -330,14 +329,6 @@ func dispatchWorkdir(d dispatchRequest, c *instructions.WorkdirCommand) error {
|
|||
return d.builder.commitContainer(d.state, containerID, runConfigWithCommentCmd)
|
||||
}
|
||||
|
||||
func resolveCmdLine(cmd instructions.ShellDependantCmdLine, runConfig *container.Config, os string) []string {
|
||||
result := cmd.CmdLine
|
||||
if cmd.PrependShell && result != nil {
|
||||
result = append(getShell(runConfig, os), result...)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// RUN some command yo
|
||||
//
|
||||
// run a command and commit the image. Args are automatically prepended with
|
||||
|
@ -353,7 +344,7 @@ func dispatchRun(d dispatchRequest, c *instructions.RunCommand) error {
|
|||
return system.ErrNotSupportedOperatingSystem
|
||||
}
|
||||
stateRunConfig := d.state.runConfig
|
||||
cmdFromArgs := resolveCmdLine(c.ShellDependantCmdLine, stateRunConfig, d.state.operatingSystem)
|
||||
cmdFromArgs, argsEscaped := resolveCmdLine(c.ShellDependantCmdLine, stateRunConfig, d.state.operatingSystem, c.Name(), c.String())
|
||||
buildArgs := d.state.buildArgs.FilterAllowed(stateRunConfig.Env)
|
||||
|
||||
saveCmd := cmdFromArgs
|
||||
|
@ -363,6 +354,7 @@ func dispatchRun(d dispatchRequest, c *instructions.RunCommand) error {
|
|||
|
||||
runConfigForCacheProbe := copyRunConfig(stateRunConfig,
|
||||
withCmd(saveCmd),
|
||||
withArgsEscaped(argsEscaped),
|
||||
withEntrypointOverride(saveCmd, nil))
|
||||
if hit, err := d.builder.probeCache(d.state, runConfigForCacheProbe); err != nil || hit {
|
||||
return err
|
||||
|
@ -370,13 +362,11 @@ func dispatchRun(d dispatchRequest, c *instructions.RunCommand) error {
|
|||
|
||||
runConfig := copyRunConfig(stateRunConfig,
|
||||
withCmd(cmdFromArgs),
|
||||
withArgsEscaped(argsEscaped),
|
||||
withEnv(append(stateRunConfig.Env, buildArgs...)),
|
||||
withEntrypointOverride(saveCmd, strslice.StrSlice{""}),
|
||||
withoutHealthcheck())
|
||||
|
||||
// set config as already being escaped, this prevents double escaping on windows
|
||||
runConfig.ArgsEscaped = true
|
||||
|
||||
cID, err := d.builder.create(runConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -399,6 +389,12 @@ func dispatchRun(d dispatchRequest, c *instructions.RunCommand) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// Don't persist the argsEscaped value in the committed image. Use the original
|
||||
// from previous build steps (only CMD and ENTRYPOINT persist this).
|
||||
if d.state.operatingSystem == "windows" {
|
||||
runConfigForCacheProbe.ArgsEscaped = stateRunConfig.ArgsEscaped
|
||||
}
|
||||
|
||||
return d.builder.commitContainer(d.state, cID, runConfigForCacheProbe)
|
||||
}
|
||||
|
||||
|
@ -434,15 +430,23 @@ func prependEnvOnCmd(buildArgs *BuildArgs, buildArgVars []string, cmd strslice.S
|
|||
//
|
||||
func dispatchCmd(d dispatchRequest, c *instructions.CmdCommand) error {
|
||||
runConfig := d.state.runConfig
|
||||
cmd := resolveCmdLine(c.ShellDependantCmdLine, runConfig, d.state.operatingSystem)
|
||||
cmd, argsEscaped := resolveCmdLine(c.ShellDependantCmdLine, runConfig, d.state.operatingSystem, c.Name(), c.String())
|
||||
|
||||
// We warn here as Windows shell processing operates differently to Linux.
|
||||
// Linux: /bin/sh -c "echo hello" world --> hello
|
||||
// Windows: cmd /s /c "echo hello" world --> hello world
|
||||
if d.state.operatingSystem == "windows" &&
|
||||
len(runConfig.Entrypoint) > 0 &&
|
||||
d.state.runConfig.ArgsEscaped != argsEscaped {
|
||||
fmt.Fprintf(d.builder.Stderr, " ---> [Warning] Shell-form ENTRYPOINT and exec-form CMD may have unexpected results\n")
|
||||
}
|
||||
|
||||
runConfig.Cmd = cmd
|
||||
// set config as already being escaped, this prevents double escaping on windows
|
||||
runConfig.ArgsEscaped = true
|
||||
runConfig.ArgsEscaped = argsEscaped
|
||||
|
||||
if err := d.builder.commit(d.state, fmt.Sprintf("CMD %q", cmd)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(c.ShellDependantCmdLine.CmdLine) != 0 {
|
||||
d.state.cmdSet = true
|
||||
}
|
||||
|
@ -477,8 +481,22 @@ func dispatchHealthcheck(d dispatchRequest, c *instructions.HealthCheckCommand)
|
|||
//
|
||||
func dispatchEntrypoint(d dispatchRequest, c *instructions.EntrypointCommand) error {
|
||||
runConfig := d.state.runConfig
|
||||
cmd := resolveCmdLine(c.ShellDependantCmdLine, runConfig, d.state.operatingSystem)
|
||||
cmd, argsEscaped := resolveCmdLine(c.ShellDependantCmdLine, runConfig, d.state.operatingSystem, c.Name(), c.String())
|
||||
|
||||
// This warning is a little more complex than in dispatchCmd(), as the Windows base images (similar
|
||||
// universally to almost every Linux image out there) have a single .Cmd field populated so that
|
||||
// `docker run --rm image` starts the default shell which would typically be sh on Linux,
|
||||
// or cmd on Windows. The catch to this is that if a dockerfile had `CMD ["c:\\windows\\system32\\cmd.exe"]`,
|
||||
// we wouldn't be able to tell the difference. However, that would be highly unlikely, and besides, this
|
||||
// is only trying to give a helpful warning of possibly unexpected results.
|
||||
if d.state.operatingSystem == "windows" &&
|
||||
d.state.runConfig.ArgsEscaped != argsEscaped &&
|
||||
((len(runConfig.Cmd) == 1 && strings.ToLower(runConfig.Cmd[0]) != `c:\windows\system32\cmd.exe` && len(runConfig.Shell) == 0) || (len(runConfig.Cmd) > 1)) {
|
||||
fmt.Fprintf(d.builder.Stderr, " ---> [Warning] Shell-form CMD and exec-form ENTRYPOINT may have unexpected results\n")
|
||||
}
|
||||
|
||||
runConfig.Entrypoint = cmd
|
||||
runConfig.ArgsEscaped = argsEscaped
|
||||
if !d.state.cmdSet {
|
||||
runConfig.Cmd = nil
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
|
@ -15,6 +16,7 @@ import (
|
|||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/moby/buildkit/frontend/dockerfile/instructions"
|
||||
"github.com/moby/buildkit/frontend/dockerfile/parser"
|
||||
"github.com/moby/buildkit/frontend/dockerfile/shell"
|
||||
"gotest.tools/assert"
|
||||
is "gotest.tools/assert/cmp"
|
||||
|
@ -436,7 +438,14 @@ func TestRunWithBuildArgs(t *testing.T) {
|
|||
|
||||
runConfig := &container.Config{}
|
||||
origCmd := strslice.StrSlice([]string{"cmd", "in", "from", "image"})
|
||||
cmdWithShell := strslice.StrSlice(append(getShell(runConfig, runtime.GOOS), "echo foo"))
|
||||
|
||||
var cmdWithShell strslice.StrSlice
|
||||
if runtime.GOOS == "windows" {
|
||||
cmdWithShell = strslice.StrSlice([]string{strings.Join(append(getShell(runConfig, runtime.GOOS), []string{"echo foo"}...), " ")})
|
||||
} else {
|
||||
cmdWithShell = strslice.StrSlice(append(getShell(runConfig, runtime.GOOS), "echo foo"))
|
||||
}
|
||||
|
||||
envVars := []string{"|1", "one=two"}
|
||||
cachedCmd := strslice.StrSlice(append(envVars, cmdWithShell...))
|
||||
|
||||
|
@ -478,13 +487,24 @@ func TestRunWithBuildArgs(t *testing.T) {
|
|||
err := initializeStage(sb, from)
|
||||
assert.NilError(t, err)
|
||||
sb.state.buildArgs.AddArg("one", strPtr("two"))
|
||||
run := &instructions.RunCommand{
|
||||
ShellDependantCmdLine: instructions.ShellDependantCmdLine{
|
||||
CmdLine: strslice.StrSlice{"echo foo"},
|
||||
PrependShell: true,
|
||||
},
|
||||
|
||||
// This is hugely annoying. On the Windows side, it relies on the
|
||||
// RunCommand being able to emit String() and Name() (as implemented by
|
||||
// withNameAndCode). Unfortunately, that is internal, and no way to directly
|
||||
// set. However, we can fortunately use ParseInstruction in the instructions
|
||||
// package to parse a fake node which can be used as our instructions.RunCommand
|
||||
// instead.
|
||||
node := &parser.Node{
|
||||
Original: `RUN echo foo`,
|
||||
Value: "run",
|
||||
}
|
||||
assert.NilError(t, dispatch(sb, run))
|
||||
runint, err := instructions.ParseInstruction(node)
|
||||
assert.NilError(t, err)
|
||||
runinst := runint.(*instructions.RunCommand)
|
||||
runinst.CmdLine = strslice.StrSlice{"echo foo"}
|
||||
runinst.PrependShell = true
|
||||
|
||||
assert.NilError(t, dispatch(sb, runinst))
|
||||
|
||||
// Check that runConfig.Cmd has not been modified by run
|
||||
assert.Check(t, is.DeepEqual(origCmd, sb.state.runConfig.Cmd))
|
||||
|
|
|
@ -6,6 +6,9 @@ import (
|
|||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/moby/buildkit/frontend/dockerfile/instructions"
|
||||
)
|
||||
|
||||
// normalizeWorkdir normalizes a user requested working directory in a
|
||||
|
@ -21,3 +24,13 @@ func normalizeWorkdir(_ string, current string, requested string) (string, error
|
|||
}
|
||||
return requested, nil
|
||||
}
|
||||
|
||||
// resolveCmdLine takes a command line arg set and optionally prepends a platform-specific
|
||||
// shell in front of it.
|
||||
func resolveCmdLine(cmd instructions.ShellDependantCmdLine, runConfig *container.Config, os, _, _ string) ([]string, bool) {
|
||||
result := cmd.CmdLine
|
||||
if cmd.PrependShell && result != nil {
|
||||
result = append(getShell(runConfig, os), result...)
|
||||
}
|
||||
return result, false
|
||||
}
|
||||
|
|
|
@ -9,7 +9,9 @@ import (
|
|||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/moby/buildkit/frontend/dockerfile/instructions"
|
||||
)
|
||||
|
||||
var pattern = regexp.MustCompile(`^[a-zA-Z]:\.$`)
|
||||
|
@ -93,3 +95,47 @@ func normalizeWorkdirWindows(current string, requested string) (string, error) {
|
|||
// Upper-case drive letter
|
||||
return (strings.ToUpper(string(requested[0])) + requested[1:]), nil
|
||||
}
|
||||
|
||||
// resolveCmdLine takes a command line arg set and optionally prepends a platform-specific
|
||||
// shell in front of it. It returns either an array of arguments and an indication that
|
||||
// the arguments are not yet escaped; Or, an array containing a single command line element
|
||||
// along with an indication that the arguments are escaped so the runtime shouldn't escape.
|
||||
//
|
||||
// A better solution could be made, but it would be exceptionally invasive throughout
|
||||
// many parts of the daemon which are coded assuming Linux args array only only, not taking
|
||||
// account of Windows-natural command line semantics and it's argv handling. Put another way,
|
||||
// while what is here is good-enough, it could be improved, but would be highly invasive.
|
||||
//
|
||||
// The commands when this function is called are RUN, ENTRYPOINT and CMD.
|
||||
func resolveCmdLine(cmd instructions.ShellDependantCmdLine, runConfig *container.Config, os, command, original string) ([]string, bool) {
|
||||
|
||||
// Make sure we return an empty array if there is no cmd.CmdLine
|
||||
if len(cmd.CmdLine) == 0 {
|
||||
return []string{}, runConfig.ArgsEscaped
|
||||
}
|
||||
|
||||
if os == "windows" { // ie WCOW
|
||||
if cmd.PrependShell {
|
||||
// WCOW shell-form. Return a single-element array containing the original command line prepended with the shell.
|
||||
// Also indicate that it has not been escaped (so will be passed through directly to HCS). Note that
|
||||
// we go back to the original un-parsed command line in the dockerfile line, strip off both the command part of
|
||||
// it (RUN/ENTRYPOINT/CMD), and also strip any leading white space. IOW, we deliberately ignore any prior parsing
|
||||
// so as to ensure it is treated exactly as a command line. For those interested, `RUN mkdir "c:/foo"` is a particularly
|
||||
// good example of why this is necessary if you fancy debugging how cmd.exe and its builtin mkdir works. (Windows
|
||||
// doesn't have a mkdir.exe, and I'm guessing cmd.exe has some very long unavoidable and unchangeable historical
|
||||
// design decisions over how both its built-in echo and mkdir are coded. Probably more too.)
|
||||
original = original[len(command):] // Strip off the command
|
||||
original = strings.TrimLeft(original, " \t\v\n") // Strip of leading whitespace
|
||||
return []string{strings.Join(getShell(runConfig, os), " ") + " " + original}, true
|
||||
}
|
||||
|
||||
// WCOW JSON/"exec" form.
|
||||
return cmd.CmdLine, false
|
||||
}
|
||||
|
||||
// LCOW - use args as an array, same as LCOL.
|
||||
if cmd.PrependShell && cmd.CmdLine != nil {
|
||||
return append(getShell(runConfig, os), cmd.CmdLine...), false
|
||||
}
|
||||
return cmd.CmdLine, false
|
||||
}
|
||||
|
|
|
@ -308,6 +308,12 @@ func withCmd(cmd []string) runConfigModifier {
|
|||
}
|
||||
}
|
||||
|
||||
func withArgsEscaped(argsEscaped bool) runConfigModifier {
|
||||
return func(runConfig *container.Config) {
|
||||
runConfig.ArgsEscaped = argsEscaped
|
||||
}
|
||||
}
|
||||
|
||||
// withCmdComment sets Cmd to a nop comment string. See withCmdCommentString for
|
||||
// why there are two almost identical versions of this.
|
||||
func withCmdComment(comment string, platform string) runConfigModifier {
|
||||
|
|
|
@ -83,7 +83,6 @@ func lookupNTAccount(builder *Builder, accountName string, state *dispatchState)
|
|||
runConfig := copyRunConfig(state.runConfig,
|
||||
withCmdCommentString("internal run to obtain NT account information.", optionsPlatform.OS))
|
||||
|
||||
runConfig.ArgsEscaped = true
|
||||
runConfig.Cmd = []string{targetExecutable, "getaccountsid", accountName}
|
||||
|
||||
hostConfig := &container.HostConfig{Mounts: []mount.Mount{
|
||||
|
|
|
@ -28,7 +28,7 @@ func (m *MockBackend) ContainerAttachRaw(cID string, stdin io.ReadCloser, stdout
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *MockBackend) ContainerCreate(config types.ContainerCreateConfig) (container.ContainerCreateCreatedBody, error) {
|
||||
func (m *MockBackend) ContainerCreateIgnoreImagesArgsEscaped(config types.ContainerCreateConfig) (container.ContainerCreateCreatedBody, error) {
|
||||
if m.containerCreateFunc != nil {
|
||||
return m.containerCreateFunc(config)
|
||||
}
|
||||
|
|
|
@ -163,31 +163,9 @@ func (cli *DaemonCli) start(opts *daemonOptions) (err error) {
|
|||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
if cli.Config.ContainerdAddr == "" && runtime.GOOS != "windows" {
|
||||
systemContainerdAddr, ok, err := systemContainerdRunning(cli.Config.IsRootless())
|
||||
if err != nil {
|
||||
cancel()
|
||||
return errors.Wrap(err, "could not determine whether the system containerd is running")
|
||||
}
|
||||
if !ok {
|
||||
opts, err := cli.getContainerdDaemonOpts()
|
||||
if err != nil {
|
||||
cancel()
|
||||
return errors.Wrap(err, "failed to generate containerd options")
|
||||
}
|
||||
|
||||
r, err := supervisor.Start(ctx, filepath.Join(cli.Config.Root, "containerd"), filepath.Join(cli.Config.ExecRoot, "containerd"), opts...)
|
||||
if err != nil {
|
||||
cancel()
|
||||
return errors.Wrap(err, "failed to start containerd")
|
||||
}
|
||||
cli.Config.ContainerdAddr = r.Address()
|
||||
|
||||
// Try to wait for containerd to shutdown
|
||||
defer r.WaitTimeout(10 * time.Second)
|
||||
} else {
|
||||
cli.Config.ContainerdAddr = systemContainerdAddr
|
||||
}
|
||||
if err := cli.initContainerD(ctx); err != nil {
|
||||
cancel()
|
||||
return err
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
|
|
|
@ -3,12 +3,14 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/runtime/v1/linux"
|
||||
"github.com/docker/docker/cmd/dockerd/hack"
|
||||
|
@ -18,6 +20,7 @@ import (
|
|||
"github.com/docker/docker/pkg/homedir"
|
||||
"github.com/docker/docker/rootless"
|
||||
"github.com/docker/libnetwork/portallocator"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
|
@ -141,3 +144,31 @@ func newCgroupParent(config *config.Config) string {
|
|||
}
|
||||
return cgroupParent
|
||||
}
|
||||
|
||||
func (cli *DaemonCli) initContainerD(ctx context.Context) error {
|
||||
if cli.Config.ContainerdAddr == "" {
|
||||
systemContainerdAddr, ok, err := systemContainerdRunning(cli.Config.IsRootless())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not determine whether the system containerd is running")
|
||||
}
|
||||
if !ok {
|
||||
opts, err := cli.getContainerdDaemonOpts()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to generate containerd options")
|
||||
}
|
||||
|
||||
r, err := supervisor.Start(ctx, filepath.Join(cli.Config.Root, "containerd"), filepath.Join(cli.Config.ExecRoot, "containerd"), opts...)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to start containerd")
|
||||
}
|
||||
cli.Config.ContainerdAddr = r.Address()
|
||||
|
||||
// Try to wait for containerd to shutdown
|
||||
defer r.WaitTimeout(10 * time.Second)
|
||||
} else {
|
||||
cli.Config.ContainerdAddr = systemContainerdAddr
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"github.com/docker/docker/daemon/config"
|
||||
"github.com/docker/docker/libcontainerd/supervisor"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
@ -85,3 +87,8 @@ func wrapListeners(proto string, ls []net.Listener) []net.Listener {
|
|||
func newCgroupParent(config *config.Config) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (cli *DaemonCli) initContainerD(_ context.Context) error {
|
||||
system.InitContainerdRuntime(cli.Config.Experimental, cli.Config.ContainerdAddr)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package main
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/daemon/config"
|
||||
|
@ -70,13 +69,7 @@ func main() {
|
|||
// Set terminal emulation based on platform as required.
|
||||
_, stdout, stderr := term.StdStreams()
|
||||
|
||||
// @jhowardmsft - maybe there is a historic reason why on non-Windows, stderr is used
|
||||
// here. However, on Windows it makes no sense and there is no need.
|
||||
if runtime.GOOS == "windows" {
|
||||
logrus.SetOutput(stdout)
|
||||
} else {
|
||||
logrus.SetOutput(stderr)
|
||||
}
|
||||
initLogging(stdout, stderr)
|
||||
|
||||
onError := func(err error) {
|
||||
fmt.Fprintf(stderr, "%s\n", err)
|
||||
|
|
|
@ -2,7 +2,17 @@
|
|||
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func runDaemon(opts *daemonOptions) error {
|
||||
daemonCli := NewDaemonCli()
|
||||
return daemonCli.start(opts)
|
||||
}
|
||||
|
||||
func initLogging(_, stderr io.Writer) {
|
||||
logrus.SetOutput(stderr)
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/Microsoft/go-winio/pkg/etwlogrus"
|
||||
_ "github.com/docker/docker/autogen/winresources/dockerd"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
@ -36,3 +38,17 @@ func runDaemon(opts *daemonOptions) error {
|
|||
notifyShutdown(err)
|
||||
return err
|
||||
}
|
||||
|
||||
func initLogging(stdout, _ io.Writer) {
|
||||
// Maybe there is a historic reason why on non-Windows, stderr is used
|
||||
// for output. However, on Windows it makes no sense and there is no need.
|
||||
logrus.SetOutput(stdout)
|
||||
|
||||
// Provider ID: {6996f090-c5de-5082-a81e-5841acc3a635}
|
||||
// Hook isn't closed explicitly, as it will exist until process exit.
|
||||
// GUID is generated based on name - see Microsoft/go-winio/tools/etw-provider-gen.
|
||||
if hook, err := etwlogrus.NewHook("Moby"); err == nil {
|
||||
logrus.AddHook(hook)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -68,7 +68,6 @@ func merge(userConf, imageConf *containertypes.Config) error {
|
|||
if len(userConf.Entrypoint) == 0 {
|
||||
if len(userConf.Cmd) == 0 {
|
||||
userConf.Cmd = imageConf.Cmd
|
||||
userConf.ArgsEscaped = imageConf.ArgsEscaped
|
||||
}
|
||||
|
||||
if userConf.Entrypoint == nil {
|
||||
|
|
|
@ -21,25 +21,46 @@ import (
|
|||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type createOpts struct {
|
||||
params types.ContainerCreateConfig
|
||||
managed bool
|
||||
ignoreImagesArgsEscaped bool
|
||||
}
|
||||
|
||||
// CreateManagedContainer creates a container that is managed by a Service
|
||||
func (daemon *Daemon) CreateManagedContainer(params types.ContainerCreateConfig) (containertypes.ContainerCreateCreatedBody, error) {
|
||||
return daemon.containerCreate(params, true)
|
||||
return daemon.containerCreate(createOpts{
|
||||
params: params,
|
||||
managed: true,
|
||||
ignoreImagesArgsEscaped: false})
|
||||
}
|
||||
|
||||
// ContainerCreate creates a regular container
|
||||
func (daemon *Daemon) ContainerCreate(params types.ContainerCreateConfig) (containertypes.ContainerCreateCreatedBody, error) {
|
||||
return daemon.containerCreate(params, false)
|
||||
return daemon.containerCreate(createOpts{
|
||||
params: params,
|
||||
managed: false,
|
||||
ignoreImagesArgsEscaped: false})
|
||||
}
|
||||
|
||||
func (daemon *Daemon) containerCreate(params types.ContainerCreateConfig, managed bool) (containertypes.ContainerCreateCreatedBody, error) {
|
||||
// ContainerCreateIgnoreImagesArgsEscaped creates a regular container. This is called from the builder RUN case
|
||||
// and ensures that we do not take the images ArgsEscaped
|
||||
func (daemon *Daemon) ContainerCreateIgnoreImagesArgsEscaped(params types.ContainerCreateConfig) (containertypes.ContainerCreateCreatedBody, error) {
|
||||
return daemon.containerCreate(createOpts{
|
||||
params: params,
|
||||
managed: false,
|
||||
ignoreImagesArgsEscaped: true})
|
||||
}
|
||||
|
||||
func (daemon *Daemon) containerCreate(opts createOpts) (containertypes.ContainerCreateCreatedBody, error) {
|
||||
start := time.Now()
|
||||
if params.Config == nil {
|
||||
if opts.params.Config == nil {
|
||||
return containertypes.ContainerCreateCreatedBody{}, errdefs.InvalidParameter(errors.New("Config cannot be empty in order to create a container"))
|
||||
}
|
||||
|
||||
os := runtime.GOOS
|
||||
if params.Config.Image != "" {
|
||||
img, err := daemon.imageService.GetImage(params.Config.Image)
|
||||
if opts.params.Config.Image != "" {
|
||||
img, err := daemon.imageService.GetImage(opts.params.Config.Image)
|
||||
if err == nil {
|
||||
os = img.OS
|
||||
}
|
||||
|
@ -51,25 +72,25 @@ func (daemon *Daemon) containerCreate(params types.ContainerCreateConfig, manage
|
|||
}
|
||||
}
|
||||
|
||||
warnings, err := daemon.verifyContainerSettings(os, params.HostConfig, params.Config, false)
|
||||
warnings, err := daemon.verifyContainerSettings(os, opts.params.HostConfig, opts.params.Config, false)
|
||||
if err != nil {
|
||||
return containertypes.ContainerCreateCreatedBody{Warnings: warnings}, errdefs.InvalidParameter(err)
|
||||
}
|
||||
|
||||
err = verifyNetworkingConfig(params.NetworkingConfig)
|
||||
err = verifyNetworkingConfig(opts.params.NetworkingConfig)
|
||||
if err != nil {
|
||||
return containertypes.ContainerCreateCreatedBody{Warnings: warnings}, errdefs.InvalidParameter(err)
|
||||
}
|
||||
|
||||
if params.HostConfig == nil {
|
||||
params.HostConfig = &containertypes.HostConfig{}
|
||||
if opts.params.HostConfig == nil {
|
||||
opts.params.HostConfig = &containertypes.HostConfig{}
|
||||
}
|
||||
err = daemon.adaptContainerSettings(params.HostConfig, params.AdjustCPUShares)
|
||||
err = daemon.adaptContainerSettings(opts.params.HostConfig, opts.params.AdjustCPUShares)
|
||||
if err != nil {
|
||||
return containertypes.ContainerCreateCreatedBody{Warnings: warnings}, errdefs.InvalidParameter(err)
|
||||
}
|
||||
|
||||
container, err := daemon.create(params, managed)
|
||||
container, err := daemon.create(opts)
|
||||
if err != nil {
|
||||
return containertypes.ContainerCreateCreatedBody{Warnings: warnings}, err
|
||||
}
|
||||
|
@ -79,7 +100,7 @@ func (daemon *Daemon) containerCreate(params types.ContainerCreateConfig, manage
|
|||
}
|
||||
|
||||
// Create creates a new container from the given configuration with a given name.
|
||||
func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) (retC *container.Container, retErr error) {
|
||||
func (daemon *Daemon) create(opts createOpts) (retC *container.Container, retErr error) {
|
||||
var (
|
||||
container *container.Container
|
||||
img *image.Image
|
||||
|
@ -88,8 +109,8 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) (
|
|||
)
|
||||
|
||||
os := runtime.GOOS
|
||||
if params.Config.Image != "" {
|
||||
img, err = daemon.imageService.GetImage(params.Config.Image)
|
||||
if opts.params.Config.Image != "" {
|
||||
img, err = daemon.imageService.GetImage(opts.params.Config.Image)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -112,15 +133,23 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) (
|
|||
}
|
||||
}
|
||||
|
||||
if err := daemon.mergeAndVerifyConfig(params.Config, img); err != nil {
|
||||
// On WCOW, if are not being invoked by the builder to create this container (where
|
||||
// ignoreImagesArgEscaped will be true) - if the image already has its arguments escaped,
|
||||
// ensure that this is replicated across to the created container to avoid double-escaping
|
||||
// of the arguments/command line when the runtime attempts to run the container.
|
||||
if os == "windows" && !opts.ignoreImagesArgsEscaped && img != nil && img.RunConfig().ArgsEscaped {
|
||||
opts.params.Config.ArgsEscaped = true
|
||||
}
|
||||
|
||||
if err := daemon.mergeAndVerifyConfig(opts.params.Config, img); err != nil {
|
||||
return nil, errdefs.InvalidParameter(err)
|
||||
}
|
||||
|
||||
if err := daemon.mergeAndVerifyLogConfig(¶ms.HostConfig.LogConfig); err != nil {
|
||||
if err := daemon.mergeAndVerifyLogConfig(&opts.params.HostConfig.LogConfig); err != nil {
|
||||
return nil, errdefs.InvalidParameter(err)
|
||||
}
|
||||
|
||||
if container, err = daemon.newContainer(params.Name, os, params.Config, params.HostConfig, imgID, managed); err != nil {
|
||||
if container, err = daemon.newContainer(opts.params.Name, os, opts.params.Config, opts.params.HostConfig, imgID, opts.managed); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
|
@ -131,11 +160,11 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) (
|
|||
}
|
||||
}()
|
||||
|
||||
if err := daemon.setSecurityOptions(container, params.HostConfig); err != nil {
|
||||
if err := daemon.setSecurityOptions(container, opts.params.HostConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
container.HostConfig.StorageOpt = params.HostConfig.StorageOpt
|
||||
container.HostConfig.StorageOpt = opts.params.HostConfig.StorageOpt
|
||||
|
||||
// Fixes: https://github.com/moby/moby/issues/34074 and
|
||||
// https://github.com/docker/for-win/issues/999.
|
||||
|
@ -170,17 +199,17 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) (
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err := daemon.setHostConfig(container, params.HostConfig); err != nil {
|
||||
if err := daemon.setHostConfig(container, opts.params.HostConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := daemon.createContainerOSSpecificSettings(container, params.Config, params.HostConfig); err != nil {
|
||||
if err := daemon.createContainerOSSpecificSettings(container, opts.params.Config, opts.params.HostConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var endpointsConfigs map[string]*networktypes.EndpointSettings
|
||||
if params.NetworkingConfig != nil {
|
||||
endpointsConfigs = params.NetworkingConfig.EndpointsConfig
|
||||
if opts.params.NetworkingConfig != nil {
|
||||
endpointsConfigs = opts.params.NetworkingConfig.EndpointsConfig
|
||||
}
|
||||
// Make sure NetworkMode has an acceptable value. We do this to ensure
|
||||
// backwards API compatibility.
|
||||
|
|
|
@ -42,6 +42,7 @@ import (
|
|||
"github.com/moby/buildkit/util/resolver"
|
||||
"github.com/moby/buildkit/util/tracing"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
// register graph drivers
|
||||
_ "github.com/docker/docker/daemon/graphdriver/register"
|
||||
"github.com/docker/docker/daemon/stats"
|
||||
|
@ -50,6 +51,7 @@ import (
|
|||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/libcontainerd"
|
||||
libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/locker"
|
||||
"github.com/docker/docker/pkg/plugingetter"
|
||||
|
@ -105,7 +107,7 @@ type Daemon struct {
|
|||
pluginManager *plugin.Manager
|
||||
linkIndex *linkIndex
|
||||
containerdCli *containerd.Client
|
||||
containerd libcontainerd.Client
|
||||
containerd libcontainerdtypes.Client
|
||||
defaultIsolation containertypes.Isolation // Default isolation mode on Windows
|
||||
clusterProvider cluster.Provider
|
||||
cluster Cluster
|
||||
|
@ -351,11 +353,11 @@ func (daemon *Daemon) restore() error {
|
|||
logrus.WithField("container", c.ID).WithField("state", s).
|
||||
Info("restored container paused")
|
||||
switch s {
|
||||
case libcontainerd.StatusPaused, libcontainerd.StatusPausing:
|
||||
case libcontainerdtypes.StatusPaused, libcontainerdtypes.StatusPausing:
|
||||
// nothing to do
|
||||
case libcontainerd.StatusStopped:
|
||||
case libcontainerdtypes.StatusStopped:
|
||||
alive = false
|
||||
case libcontainerd.StatusUnknown:
|
||||
case libcontainerdtypes.StatusUnknown:
|
||||
logrus.WithField("container", c.ID).
|
||||
Error("Unknown status for container during restore")
|
||||
default:
|
||||
|
|
|
@ -502,6 +502,7 @@ func (daemon *Daemon) runAsHyperVContainer(hostConfig *containertypes.HostConfig
|
|||
// conditionalMountOnStart is a platform specific helper function during the
|
||||
// container start to call mount.
|
||||
func (daemon *Daemon) conditionalMountOnStart(container *container.Container) error {
|
||||
|
||||
// Bail out now for Linux containers. We cannot mount the containers filesystem on the
|
||||
// host as it is a non-Windows filesystem.
|
||||
if system.LCOWSupported() && container.OS != "windows" {
|
||||
|
@ -519,6 +520,7 @@ func (daemon *Daemon) conditionalMountOnStart(container *container.Container) er
|
|||
// conditionalUnmountOnCleanup is a platform specific helper function called
|
||||
// during the cleanup of a container to unmount.
|
||||
func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container) error {
|
||||
|
||||
// Bail out now for Linux containers
|
||||
if system.LCOWSupported() && container.OS != "windows" {
|
||||
return nil
|
||||
|
|
|
@ -144,7 +144,8 @@ func translateContainerdStartErr(cmd string, setExitCode func(int), err error) e
|
|||
if contains(errDesc, cmd) &&
|
||||
(contains(errDesc, "executable file not found") ||
|
||||
contains(errDesc, "no such file or directory") ||
|
||||
contains(errDesc, "system cannot find the file specified")) {
|
||||
contains(errDesc, "system cannot find the file specified") ||
|
||||
contains(errDesc, "failed to run runc create/exec call")) {
|
||||
setExitCode(127)
|
||||
retErr = startInvalidConfigError(errDesc)
|
||||
}
|
||||
|
|
|
@ -7,9 +7,7 @@ import (
|
|||
)
|
||||
|
||||
func (daemon *Daemon) execSetPlatformOpt(c *container.Container, ec *exec.Config, p *specs.Process) error {
|
||||
// Process arguments need to be escaped before sending to OCI.
|
||||
if c.OS == "windows" {
|
||||
p.Args = escapeArgs(p.Args)
|
||||
p.User.Username = ec.User
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -31,22 +31,10 @@
|
|||
// -- Possible values: Any local path that is not a mapped drive
|
||||
// -- Default if omitted: %ProgramFiles%\Linux Containers
|
||||
//
|
||||
// * lcow.kernel - Specifies a custom kernel file located in the `lcow.kirdpath` path
|
||||
// -- Possible values: Any valid filename
|
||||
// -- Default if omitted: bootx64.efi
|
||||
//
|
||||
// * lcow.initrd - Specifies a custom initrd file located in the `lcow.kirdpath` path
|
||||
// -- Possible values: Any valid filename
|
||||
// -- Default if omitted: initrd.img
|
||||
//
|
||||
// * lcow.bootparameters - Specifies additional boot parameters for booting in kernel+initrd mode
|
||||
// -- Possible values: Any valid linux kernel boot options
|
||||
// -- Default if omitted: <nil>
|
||||
//
|
||||
// * lcow.vhdx - Specifies a custom vhdx file to boot (instead of a kernel+initrd)
|
||||
// -- Possible values: Any valid filename
|
||||
// -- Default if omitted: uvm.vhdx under `lcow.kirdpath`
|
||||
//
|
||||
// * lcow.timeout - Specifies a timeout for utility VM operations in seconds
|
||||
// -- Possible values: >=0
|
||||
// -- Default if omitted: 300
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
|
||||
containerpkg "github.com/docker/docker/container"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/libcontainerd"
|
||||
libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
@ -177,5 +177,5 @@ func (daemon *Daemon) killPossiblyDeadProcess(container *containerpkg.Container,
|
|||
}
|
||||
|
||||
func (daemon *Daemon) kill(c *containerpkg.Container, sig int) error {
|
||||
return daemon.containerd.SignalProcess(context.Background(), c.ID, libcontainerd.InitProcessName, sig)
|
||||
return daemon.containerd.SignalProcess(context.Background(), c.ID, libcontainerdtypes.InitProcessName, sig)
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/libcontainerd"
|
||||
libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
|
||||
"github.com/docker/docker/restartmanager"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
@ -27,14 +27,14 @@ func (daemon *Daemon) setStateCounter(c *container.Container) {
|
|||
}
|
||||
|
||||
// ProcessEvent is called by libcontainerd whenever an event occurs
|
||||
func (daemon *Daemon) ProcessEvent(id string, e libcontainerd.EventType, ei libcontainerd.EventInfo) error {
|
||||
func (daemon *Daemon) ProcessEvent(id string, e libcontainerdtypes.EventType, ei libcontainerdtypes.EventInfo) error {
|
||||
c, err := daemon.GetContainer(id)
|
||||
if c == nil || err != nil {
|
||||
return fmt.Errorf("no such container: %s", id)
|
||||
}
|
||||
|
||||
switch e {
|
||||
case libcontainerd.EventOOM:
|
||||
case libcontainerdtypes.EventOOM:
|
||||
// StateOOM is Linux specific and should never be hit on Windows
|
||||
if runtime.GOOS == "windows" {
|
||||
return errors.New("received StateOOM from libcontainerd on Windows. This should never happen")
|
||||
|
@ -48,7 +48,7 @@ func (daemon *Daemon) ProcessEvent(id string, e libcontainerd.EventType, ei libc
|
|||
}
|
||||
|
||||
daemon.LogContainerEvent(c, "oom")
|
||||
case libcontainerd.EventExit:
|
||||
case libcontainerdtypes.EventExit:
|
||||
if int(ei.Pid) == c.Pid {
|
||||
c.Lock()
|
||||
_, _, err := daemon.containerd.DeleteTask(context.Background(), c.ID)
|
||||
|
@ -143,7 +143,7 @@ func (daemon *Daemon) ProcessEvent(id string, e libcontainerd.EventType, ei libc
|
|||
"exec-pid": ei.Pid,
|
||||
}).Warn("Ignoring Exit Event, no such exec command found")
|
||||
}
|
||||
case libcontainerd.EventStart:
|
||||
case libcontainerdtypes.EventStart:
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
|
@ -162,7 +162,7 @@ func (daemon *Daemon) ProcessEvent(id string, e libcontainerd.EventType, ei libc
|
|||
daemon.LogContainerEvent(c, "start")
|
||||
}
|
||||
|
||||
case libcontainerd.EventPaused:
|
||||
case libcontainerdtypes.EventPaused:
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
|
@ -175,7 +175,7 @@ func (daemon *Daemon) ProcessEvent(id string, e libcontainerd.EventType, ei libc
|
|||
}
|
||||
daemon.LogContainerEvent(c, "pause")
|
||||
}
|
||||
case libcontainerd.EventResumed:
|
||||
case libcontainerdtypes.EventResumed:
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
|
|
|
@ -688,13 +688,7 @@ func (daemon *Daemon) populateCommonSpec(s *specs.Spec, c *container.Container)
|
|||
s.Process.Terminal = c.Config.Tty
|
||||
|
||||
s.Hostname = c.Config.Hostname
|
||||
// There isn't a field in the OCI for the NIS domainname, but luckily there
|
||||
// is a sysctl which has an identical effect to setdomainname(2) so there's
|
||||
// no explicit need for runtime support.
|
||||
s.Linux.Sysctl = make(map[string]string)
|
||||
if c.Config.Domainname != "" {
|
||||
s.Linux.Sysctl["kernel.domainname"] = c.Config.Domainname
|
||||
}
|
||||
setLinuxDomainname(c, s)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
16
daemon/oci_utils.go
Normal file
16
daemon/oci_utils.go
Normal file
|
@ -0,0 +1,16 @@
|
|||
package daemon // import "github.com/docker/docker/daemon"
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
func setLinuxDomainname(c *container.Container, s *specs.Spec) {
|
||||
// There isn't a field in the OCI for the NIS domainname, but luckily there
|
||||
// is a sysctl which has an identical effect to setdomainname(2) so there's
|
||||
// no explicit need for runtime support.
|
||||
s.Linux.Sysctl = make(map[string]string)
|
||||
if c.Config.Domainname != "" {
|
||||
s.Linux.Sysctl["kernel.domainname"] = c.Config.Domainname
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package daemon // import "github.com/docker/docker/daemon"
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
@ -16,7 +17,7 @@ import (
|
|||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/windows"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/windows/registry"
|
||||
)
|
||||
|
||||
|
@ -26,6 +27,7 @@ const (
|
|||
)
|
||||
|
||||
func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
|
||||
|
||||
img, err := daemon.imageService.GetImage(string(c.ImageID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -42,9 +44,6 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
|
|||
// this is done in VMCompute. Further, we couldn't do it for Hyper-V
|
||||
// containers anyway.
|
||||
|
||||
// In base spec
|
||||
s.Hostname = c.FullHostname()
|
||||
|
||||
if err := daemon.setupSecretDir(c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -125,15 +124,11 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
|
|||
}
|
||||
|
||||
// In s.Process
|
||||
s.Process.Args = append([]string{c.Path}, c.Args...)
|
||||
if !c.Config.ArgsEscaped && img.OS == "windows" {
|
||||
s.Process.Args = escapeArgs(s.Process.Args)
|
||||
}
|
||||
|
||||
s.Process.Cwd = c.Config.WorkingDir
|
||||
s.Process.Env = c.CreateDaemonEnvironment(c.Config.Tty, linkedEnv)
|
||||
s.Process.Terminal = c.Config.Tty
|
||||
|
||||
if c.Config.Tty {
|
||||
s.Process.Terminal = c.Config.Tty
|
||||
s.Process.ConsoleSize = &specs.Box{
|
||||
Height: c.HostConfig.ConsoleSize[0],
|
||||
Width: c.HostConfig.ConsoleSize[1],
|
||||
|
@ -220,11 +215,20 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
|
|||
return nil, fmt.Errorf("Unsupported platform %q", img.OS)
|
||||
}
|
||||
|
||||
if logrus.IsLevelEnabled(logrus.DebugLevel) {
|
||||
if b, err := json.Marshal(&s); err == nil {
|
||||
logrus.Debugf("Generated spec: %s", string(b))
|
||||
}
|
||||
}
|
||||
|
||||
return (*specs.Spec)(&s), nil
|
||||
}
|
||||
|
||||
// Sets the Windows-specific fields of the OCI spec
|
||||
func (daemon *Daemon) createSpecWindowsFields(c *container.Container, s *specs.Spec, isHyperV bool) error {
|
||||
|
||||
s.Hostname = c.FullHostname()
|
||||
|
||||
if len(s.Process.Cwd) == 0 {
|
||||
// We default to C:\ to workaround the oddity of the case that the
|
||||
// default directory for cmd running as LocalSystem (or
|
||||
|
@ -236,6 +240,14 @@ func (daemon *Daemon) createSpecWindowsFields(c *container.Container, s *specs.S
|
|||
s.Process.Cwd = `C:\`
|
||||
}
|
||||
|
||||
if c.Config.ArgsEscaped {
|
||||
s.Process.CommandLine = c.Path
|
||||
if len(c.Args) > 0 {
|
||||
s.Process.CommandLine += " " + system.EscapeArgs(c.Args)
|
||||
}
|
||||
} else {
|
||||
s.Process.Args = append([]string{c.Path}, c.Args...)
|
||||
}
|
||||
s.Root.Readonly = false // Windows does not support a read-only root filesystem
|
||||
if !isHyperV {
|
||||
if c.BaseFS == nil {
|
||||
|
@ -361,12 +373,20 @@ func (daemon *Daemon) setWindowsCredentialSpec(c *container.Container, s *specs.
|
|||
// TODO: @jhowardmsft LCOW Support. We need to do a lot more pulling in what can
|
||||
// be pulled in from oci_linux.go.
|
||||
func (daemon *Daemon) createSpecLinuxFields(c *container.Container, s *specs.Spec) error {
|
||||
s.Root = &specs.Root{
|
||||
Path: "rootfs",
|
||||
Readonly: c.HostConfig.ReadonlyRootfs,
|
||||
}
|
||||
|
||||
s.Hostname = c.Config.Hostname
|
||||
setLinuxDomainname(c, s)
|
||||
|
||||
if len(s.Process.Cwd) == 0 {
|
||||
s.Process.Cwd = `/`
|
||||
}
|
||||
s.Root.Path = "rootfs"
|
||||
s.Root.Readonly = c.HostConfig.ReadonlyRootfs
|
||||
s.Process.Args = append([]string{c.Path}, c.Args...)
|
||||
|
||||
// Note these are against the UVM.
|
||||
setResourcesInSpec(c, s, true) // LCOW is Hyper-V only
|
||||
|
||||
capabilities, err := caps.TweakCapabilities(oci.DefaultCapabilities(), c.HostConfig.CapAdd, c.HostConfig.CapDrop, c.HostConfig.Capabilities, c.HostConfig.Privileged)
|
||||
|
@ -409,31 +429,39 @@ func setResourcesInSpec(c *container.Container, s *specs.Spec, isHyperV bool) {
|
|||
}
|
||||
}
|
||||
}
|
||||
memoryLimit := uint64(c.HostConfig.Memory)
|
||||
s.Windows.Resources = &specs.WindowsResources{
|
||||
CPU: &specs.WindowsCPUResources{
|
||||
|
||||
if cpuMaximum != 0 || cpuShares != 0 || cpuCount != 0 {
|
||||
if s.Windows.Resources == nil {
|
||||
s.Windows.Resources = &specs.WindowsResources{}
|
||||
}
|
||||
s.Windows.Resources.CPU = &specs.WindowsCPUResources{
|
||||
Maximum: &cpuMaximum,
|
||||
Shares: &cpuShares,
|
||||
Count: &cpuCount,
|
||||
},
|
||||
Memory: &specs.WindowsMemoryResources{
|
||||
}
|
||||
}
|
||||
|
||||
memoryLimit := uint64(c.HostConfig.Memory)
|
||||
if memoryLimit != 0 {
|
||||
if s.Windows.Resources == nil {
|
||||
s.Windows.Resources = &specs.WindowsResources{}
|
||||
}
|
||||
s.Windows.Resources.Memory = &specs.WindowsMemoryResources{
|
||||
Limit: &memoryLimit,
|
||||
},
|
||||
Storage: &specs.WindowsStorageResources{
|
||||
}
|
||||
}
|
||||
|
||||
if c.HostConfig.IOMaximumBandwidth != 0 || c.HostConfig.IOMaximumIOps != 0 {
|
||||
if s.Windows.Resources == nil {
|
||||
s.Windows.Resources = &specs.WindowsResources{}
|
||||
}
|
||||
s.Windows.Resources.Storage = &specs.WindowsStorageResources{
|
||||
Bps: &c.HostConfig.IOMaximumBandwidth,
|
||||
Iops: &c.HostConfig.IOMaximumIOps,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func escapeArgs(args []string) []string {
|
||||
escapedArgs := make([]string, len(args))
|
||||
for i, a := range args {
|
||||
escapedArgs[i] = windows.EscapeArg(a)
|
||||
}
|
||||
return escapedArgs
|
||||
}
|
||||
|
||||
// mergeUlimits merge the Ulimits from HostConfig with daemon defaults, and update HostConfig
|
||||
// It will do nothing on non-Linux platform
|
||||
func (daemon *Daemon) mergeUlimits(c *containertypes.HostConfig) {
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/libcontainerd"
|
||||
libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
|
||||
)
|
||||
|
||||
// ContainerResize changes the size of the TTY of the process running
|
||||
|
@ -20,7 +20,7 @@ func (daemon *Daemon) ContainerResize(name string, height, width int) error {
|
|||
return errNotRunning(container.ID)
|
||||
}
|
||||
|
||||
if err = daemon.containerd.ResizeTerminal(context.Background(), container.ID, libcontainerd.InitProcessName, width, height); err == nil {
|
||||
if err = daemon.containerd.ResizeTerminal(context.Background(), container.ID, libcontainerdtypes.InitProcessName, width, height); err == nil {
|
||||
attributes := map[string]string{
|
||||
"height": fmt.Sprintf("%d", height),
|
||||
"width": fmt.Sprintf("%d", width),
|
||||
|
|
|
@ -1,11 +1,23 @@
|
|||
package daemon // import "github.com/docker/docker/daemon"
|
||||
|
||||
import (
|
||||
"github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options"
|
||||
"github.com/Microsoft/opengcs/client"
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
)
|
||||
|
||||
func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Container) (interface{}, error) {
|
||||
|
||||
// Set the runtime options to debug regardless of current logging level.
|
||||
if system.ContainerdRuntimeSupported() {
|
||||
opts := &options.Options{Debug: true}
|
||||
return opts, nil
|
||||
}
|
||||
|
||||
// TODO @jhowardmsft (containerd) - Probably need to revisit LCOW options here
|
||||
// rather than blindly ignoring them.
|
||||
|
||||
// LCOW options.
|
||||
if container.OS == "linux" {
|
||||
config := &client.Config{}
|
||||
|
@ -17,12 +29,6 @@ func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Contain
|
|||
switch k {
|
||||
case "lcow.kirdpath":
|
||||
config.KirdPath = v
|
||||
case "lcow.kernel":
|
||||
config.KernelFile = v
|
||||
case "lcow.initrd":
|
||||
config.InitrdFile = v
|
||||
case "lcow.vhdx":
|
||||
config.Vhdx = v
|
||||
case "lcow.bootparameters":
|
||||
config.BootParameters = v
|
||||
}
|
||||
|
|
|
@ -143,6 +143,10 @@ func (s *Collector) Run() {
|
|||
|
||||
default:
|
||||
logrus.Errorf("collecting stats for %s: %v", pair.container.ID, err)
|
||||
pair.publisher.Publish(types.StatsJSON{
|
||||
Name: pair.container.Name,
|
||||
ID: pair.container.ID,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,10 +51,10 @@ func (daemon *Daemon) ContainerTop(name string, psArgs string) (*containertypes.
|
|||
procList.Titles = []string{"Name", "PID", "CPU", "Private Working Set"}
|
||||
|
||||
for _, j := range s {
|
||||
d := time.Duration((j.KernelTime100ns + j.UserTime100ns) * 100) // Combined time in nanoseconds
|
||||
d := time.Duration((j.KernelTime_100Ns + j.UserTime_100Ns) * 100) // Combined time in nanoseconds
|
||||
procList.Processes = append(procList.Processes, []string{
|
||||
j.ImageName,
|
||||
fmt.Sprint(j.ProcessId),
|
||||
fmt.Sprint(j.ProcessID),
|
||||
fmt.Sprintf("%02d:%02d:%02d.%03d", int(d.Hours()), int(d.Minutes())%60, int(d.Seconds())%60, int(d.Nanoseconds()/1000000)%1000),
|
||||
units.HumanSize(float64(j.MemoryWorkingSetPrivateBytes))})
|
||||
}
|
||||
|
|
|
@ -4,12 +4,12 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/libcontainerd"
|
||||
libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
func toContainerdResources(resources container.Resources) *libcontainerd.Resources {
|
||||
var r libcontainerd.Resources
|
||||
func toContainerdResources(resources container.Resources) *libcontainerdtypes.Resources {
|
||||
var r libcontainerdtypes.Resources
|
||||
|
||||
r.BlockIO = &specs.LinuxBlockIO{
|
||||
Weight: &resources.BlkioWeight,
|
||||
|
|
|
@ -2,10 +2,10 @@ package daemon // import "github.com/docker/docker/daemon"
|
|||
|
||||
import (
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/libcontainerd"
|
||||
libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
|
||||
)
|
||||
|
||||
func toContainerdResources(resources container.Resources) *libcontainerd.Resources {
|
||||
func toContainerdResources(resources container.Resources) *libcontainerdtypes.Resources {
|
||||
// We don't support update, so do nothing
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/docker/docker/libcontainerd"
|
||||
libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
|
@ -18,19 +18,19 @@ type MockContainerdClient struct {
|
|||
func (c *MockContainerdClient) Version(ctx context.Context) (containerd.Version, error) {
|
||||
return containerd.Version{}, nil
|
||||
}
|
||||
func (c *MockContainerdClient) Restore(ctx context.Context, containerID string, attachStdio libcontainerd.StdioCallback) (alive bool, pid int, err error) {
|
||||
func (c *MockContainerdClient) Restore(ctx context.Context, containerID string, attachStdio libcontainerdtypes.StdioCallback) (alive bool, pid int, err error) {
|
||||
return false, 0, nil
|
||||
}
|
||||
func (c *MockContainerdClient) Create(ctx context.Context, containerID string, spec *specs.Spec, runtimeOptions interface{}) error {
|
||||
return nil
|
||||
}
|
||||
func (c *MockContainerdClient) Start(ctx context.Context, containerID, checkpointDir string, withStdin bool, attachStdio libcontainerd.StdioCallback) (pid int, err error) {
|
||||
func (c *MockContainerdClient) Start(ctx context.Context, containerID, checkpointDir string, withStdin bool, attachStdio libcontainerdtypes.StdioCallback) (pid int, err error) {
|
||||
return 0, nil
|
||||
}
|
||||
func (c *MockContainerdClient) SignalProcess(ctx context.Context, containerID, processID string, signal int) error {
|
||||
return nil
|
||||
}
|
||||
func (c *MockContainerdClient) Exec(ctx context.Context, containerID, processID string, spec *specs.Process, withStdin bool, attachStdio libcontainerd.StdioCallback) (int, error) {
|
||||
func (c *MockContainerdClient) Exec(ctx context.Context, containerID, processID string, spec *specs.Process, withStdin bool, attachStdio libcontainerdtypes.StdioCallback) (int, error) {
|
||||
return 0, nil
|
||||
}
|
||||
func (c *MockContainerdClient) ResizeTerminal(ctx context.Context, containerID, processID string, width, height int) error {
|
||||
|
@ -41,23 +41,23 @@ func (c *MockContainerdClient) CloseStdin(ctx context.Context, containerID, proc
|
|||
}
|
||||
func (c *MockContainerdClient) Pause(ctx context.Context, containerID string) error { return nil }
|
||||
func (c *MockContainerdClient) Resume(ctx context.Context, containerID string) error { return nil }
|
||||
func (c *MockContainerdClient) Stats(ctx context.Context, containerID string) (*libcontainerd.Stats, error) {
|
||||
func (c *MockContainerdClient) Stats(ctx context.Context, containerID string) (*libcontainerdtypes.Stats, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (c *MockContainerdClient) ListPids(ctx context.Context, containerID string) ([]uint32, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (c *MockContainerdClient) Summary(ctx context.Context, containerID string) ([]libcontainerd.Summary, error) {
|
||||
func (c *MockContainerdClient) Summary(ctx context.Context, containerID string) ([]libcontainerdtypes.Summary, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (c *MockContainerdClient) DeleteTask(ctx context.Context, containerID string) (uint32, time.Time, error) {
|
||||
return 0, time.Time{}, nil
|
||||
}
|
||||
func (c *MockContainerdClient) Delete(ctx context.Context, containerID string) error { return nil }
|
||||
func (c *MockContainerdClient) Status(ctx context.Context, containerID string) (libcontainerd.Status, error) {
|
||||
func (c *MockContainerdClient) Status(ctx context.Context, containerID string) (libcontainerdtypes.Status, error) {
|
||||
return "null", nil
|
||||
}
|
||||
func (c *MockContainerdClient) UpdateResources(ctx context.Context, containerID string, resources *libcontainerd.Resources) error {
|
||||
func (c *MockContainerdClient) UpdateResources(ctx context.Context, containerID string, resources *libcontainerdtypes.Resources) error {
|
||||
return nil
|
||||
}
|
||||
func (c *MockContainerdClient) CreateCheckpoint(ctx context.Context, containerID, checkpointDir string, exit bool) error {
|
||||
|
|
|
@ -144,7 +144,7 @@ type ChildConfig struct {
|
|||
}
|
||||
|
||||
// NewChildImage creates a new Image as a child of this image.
|
||||
func NewChildImage(img *Image, child ChildConfig, platform string) *Image {
|
||||
func NewChildImage(img *Image, child ChildConfig, os string) *Image {
|
||||
isEmptyLayer := layer.IsEmpty(child.DiffID)
|
||||
var rootFS *RootFS
|
||||
if img.RootFS != nil {
|
||||
|
@ -167,7 +167,7 @@ func NewChildImage(img *Image, child ChildConfig, platform string) *Image {
|
|||
DockerVersion: dockerversion.Version,
|
||||
Config: child.Config,
|
||||
Architecture: img.BaseImgArch(),
|
||||
OS: platform,
|
||||
OS: os,
|
||||
Container: child.ContainerID,
|
||||
ContainerConfig: *child.ContainerConfig,
|
||||
Author: child.Author,
|
||||
|
|
|
@ -3203,7 +3203,7 @@ func (s *DockerSuite) TestBuildCmdShDashC(c *check.C) {
|
|||
res := inspectFieldJSON(c, name, "Config.Cmd")
|
||||
expected := `["/bin/sh","-c","echo cmd"]`
|
||||
if testEnv.OSType == "windows" {
|
||||
expected = `["cmd","/S","/C","echo cmd"]`
|
||||
expected = `["cmd /S /C echo cmd"]`
|
||||
}
|
||||
if res != expected {
|
||||
c.Fatalf("Expected value %s not in Config.Cmd: %s", expected, res)
|
||||
|
@ -3276,7 +3276,7 @@ func (s *DockerSuite) TestBuildEntrypointCanBeOverriddenByChildInspect(c *check.
|
|||
)
|
||||
|
||||
if testEnv.OSType == "windows" {
|
||||
expected = `["cmd","/S","/C","echo quux"]`
|
||||
expected = `["cmd /S /C echo quux"]`
|
||||
}
|
||||
|
||||
buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nENTRYPOINT /foo/bar"))
|
||||
|
@ -3362,8 +3362,8 @@ func (s *DockerSuite) TestBuildWithTabs(c *check.C) {
|
|||
expected1 := `["/bin/sh","-c","echo\tone\t\ttwo"]`
|
||||
expected2 := `["/bin/sh","-c","echo\u0009one\u0009\u0009two"]` // syntactically equivalent, and what Go 1.3 generates
|
||||
if testEnv.OSType == "windows" {
|
||||
expected1 = `["cmd","/S","/C","echo\tone\t\ttwo"]`
|
||||
expected2 = `["cmd","/S","/C","echo\u0009one\u0009\u0009two"]` // syntactically equivalent, and what Go 1.3 generates
|
||||
expected1 = `["cmd /S /C echo\tone\t\ttwo"]`
|
||||
expected2 = `["cmd /S /C echo\u0009one\u0009\u0009two"]` // syntactically equivalent, and what Go 1.3 generates
|
||||
}
|
||||
if res != expected1 && res != expected2 {
|
||||
c.Fatalf("Missing tabs.\nGot: %s\nExp: %s or %s", res, expected1, expected2)
|
||||
|
@ -5335,25 +5335,45 @@ func (s *DockerSuite) TestBuildEscapeNotBackslashWordTest(c *check.C) {
|
|||
})
|
||||
}
|
||||
|
||||
// #22868. Make sure shell-form CMD is marked as escaped in the config of the image
|
||||
// #22868. Make sure shell-form CMD is not marked as escaped in the config of the image,
|
||||
// but an exec-form CMD is marked.
|
||||
func (s *DockerSuite) TestBuildCmdShellArgsEscaped(c *check.C) {
|
||||
testRequires(c, DaemonIsWindows)
|
||||
name := "testbuildcmdshellescaped"
|
||||
buildImageSuccessfully(c, name, build.WithDockerfile(`
|
||||
name1 := "testbuildcmdshellescapedshellform"
|
||||
buildImageSuccessfully(c, name1, build.WithDockerfile(`
|
||||
FROM `+minimalBaseImage()+`
|
||||
CMD "ipconfig"
|
||||
`))
|
||||
res := inspectFieldJSON(c, name, "Config.ArgsEscaped")
|
||||
res := inspectFieldJSON(c, name1, "Config.ArgsEscaped")
|
||||
if res != "true" {
|
||||
c.Fatalf("CMD did not update Config.ArgsEscaped on image: %v", res)
|
||||
}
|
||||
dockerCmd(c, "run", "--name", "inspectme", name)
|
||||
dockerCmd(c, "wait", "inspectme")
|
||||
res = inspectFieldJSON(c, name, "Config.Cmd")
|
||||
dockerCmd(c, "run", "--name", "inspectme1", name1)
|
||||
dockerCmd(c, "wait", "inspectme1")
|
||||
res = inspectFieldJSON(c, name1, "Config.Cmd")
|
||||
|
||||
if res != `["cmd","/S","/C","\"ipconfig\""]` {
|
||||
c.Fatalf("CMD was not escaped Config.Cmd: got %v", res)
|
||||
if res != `["cmd /S /C \"ipconfig\""]` {
|
||||
c.Fatalf("CMD incorrect in Config.Cmd: got %v", res)
|
||||
}
|
||||
|
||||
// Now in JSON/exec-form
|
||||
name2 := "testbuildcmdshellescapedexecform"
|
||||
buildImageSuccessfully(c, name2, build.WithDockerfile(`
|
||||
FROM `+minimalBaseImage()+`
|
||||
CMD ["ipconfig"]
|
||||
`))
|
||||
res = inspectFieldJSON(c, name2, "Config.ArgsEscaped")
|
||||
if res != "false" {
|
||||
c.Fatalf("CMD set Config.ArgsEscaped on image: %v", res)
|
||||
}
|
||||
dockerCmd(c, "run", "--name", "inspectme2", name2)
|
||||
dockerCmd(c, "wait", "inspectme2")
|
||||
res = inspectFieldJSON(c, name2, "Config.Cmd")
|
||||
|
||||
if res != `["ipconfig"]` {
|
||||
c.Fatalf("CMD incorrect in Config.Cmd: got %v", res)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Test case for #24912.
|
||||
|
@ -6150,7 +6170,11 @@ CMD echo foo
|
|||
`))
|
||||
|
||||
out, _ := dockerCmd(c, "inspect", "--format", "{{ json .Config.Cmd }}", "build2")
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, `["/bin/sh","-c","echo foo"]`)
|
||||
expected := `["/bin/sh","-c","echo foo"]`
|
||||
if testEnv.OSType == "windows" {
|
||||
expected = `["/bin/sh -c echo foo"]`
|
||||
}
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, expected)
|
||||
}
|
||||
|
||||
// FIXME(vdemeester) should migrate to docker/cli tests
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
package libcontainerd // import "github.com/docker/docker/libcontainerd"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/containerd/containerd/cio"
|
||||
"github.com/containerd/containerd/windows/hcsshimtypes"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func summaryFromInterface(i interface{}) (*Summary, error) {
|
||||
switch pd := i.(type) {
|
||||
case *hcsshimtypes.ProcessDetails:
|
||||
return &Summary{
|
||||
CreateTimestamp: pd.CreatedAt,
|
||||
ImageName: pd.ImageName,
|
||||
KernelTime100ns: pd.KernelTime_100Ns,
|
||||
MemoryCommitBytes: pd.MemoryCommitBytes,
|
||||
MemoryWorkingSetPrivateBytes: pd.MemoryWorkingSetPrivateBytes,
|
||||
MemoryWorkingSetSharedBytes: pd.MemoryWorkingSetSharedBytes,
|
||||
ProcessId: pd.ProcessID,
|
||||
UserTime100ns: pd.UserTime_100Ns,
|
||||
}, nil
|
||||
default:
|
||||
return nil, errors.Errorf("Unknown process details type %T", pd)
|
||||
}
|
||||
}
|
||||
|
||||
func prepareBundleDir(bundleDir string, ociSpec *specs.Spec) (string, error) {
|
||||
return bundleDir, nil
|
||||
}
|
||||
|
||||
func pipeName(containerID, processID, name string) string {
|
||||
return fmt.Sprintf(`\\.\pipe\containerd-%s-%s-%s`, containerID, processID, name)
|
||||
}
|
||||
|
||||
func newFIFOSet(bundleDir, processID string, withStdin, withTerminal bool) *cio.FIFOSet {
|
||||
containerID := filepath.Base(bundleDir)
|
||||
config := cio.Config{
|
||||
Terminal: withTerminal,
|
||||
Stdout: pipeName(containerID, processID, "stdout"),
|
||||
}
|
||||
|
||||
if withStdin {
|
||||
config.Stdin = pipeName(containerID, processID, "stdin")
|
||||
}
|
||||
|
||||
if !config.Terminal {
|
||||
config.Stderr = pipeName(containerID, processID, "stderr")
|
||||
}
|
||||
|
||||
return cio.NewFIFOSet(config, nil)
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package libcontainerd // import "github.com/docker/docker/libcontainerd"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/docker/docker/errdefs"
|
||||
)
|
||||
|
||||
func newNotFoundError(err string) error { return errdefs.NotFound(errors.New(err)) }
|
||||
|
||||
func newInvalidParameterError(err string) error { return errdefs.InvalidParameter(errors.New(err)) }
|
||||
|
||||
func newConflictError(err string) error { return errdefs.Conflict(errors.New(err)) }
|
14
libcontainerd/libcontainerd_linux.go
Normal file
14
libcontainerd/libcontainerd_linux.go
Normal file
|
@ -0,0 +1,14 @@
|
|||
package libcontainerd // import "github.com/docker/docker/libcontainerd"
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/docker/docker/libcontainerd/remote"
|
||||
libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
|
||||
)
|
||||
|
||||
// NewClient creates a new libcontainerd client from a containerd client
|
||||
func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, b libcontainerdtypes.Backend) (libcontainerdtypes.Client, error) {
|
||||
return remote.NewClient(ctx, cli, stateDir, ns, b)
|
||||
}
|
19
libcontainerd/libcontainerd_windows.go
Normal file
19
libcontainerd/libcontainerd_windows.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
package libcontainerd // import "github.com/docker/docker/libcontainerd"
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/docker/docker/libcontainerd/local"
|
||||
"github.com/docker/docker/libcontainerd/remote"
|
||||
libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
)
|
||||
|
||||
// NewClient creates a new libcontainerd client from a containerd client
|
||||
func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, b libcontainerdtypes.Backend) (libcontainerdtypes.Client, error) {
|
||||
if !system.ContainerdRuntimeSupported() {
|
||||
return local.NewClient(ctx, cli, stateDir, ns, b)
|
||||
}
|
||||
return remote.NewClient(ctx, cli, stateDir, ns, b)
|
||||
}
|
|
@ -1,4 +1,7 @@
|
|||
package libcontainerd // import "github.com/docker/docker/libcontainerd"
|
||||
package local // import "github.com/docker/docker/libcontainerd/local"
|
||||
|
||||
// This package contains the legacy in-proc calls in HCS using the v1 schema
|
||||
// for Windows runtime purposes.
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -18,6 +21,10 @@ import (
|
|||
opengcs "github.com/Microsoft/opengcs/client"
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cio"
|
||||
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/libcontainerd/queue"
|
||||
libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
|
||||
"github.com/docker/docker/pkg/sysinfo"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
|
@ -26,8 +33,6 @@ import (
|
|||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
const InitProcessName = "init"
|
||||
|
||||
type process struct {
|
||||
id string
|
||||
pid int
|
||||
|
@ -46,7 +51,7 @@ type container struct {
|
|||
hcsContainer hcsshim.Container
|
||||
|
||||
id string
|
||||
status Status
|
||||
status libcontainerdtypes.Status
|
||||
exitedAt time.Time
|
||||
exitCode uint32
|
||||
waitCh chan struct{}
|
||||
|
@ -74,14 +79,14 @@ type client struct {
|
|||
sync.Mutex
|
||||
|
||||
stateDir string
|
||||
backend Backend
|
||||
backend libcontainerdtypes.Backend
|
||||
logger *logrus.Entry
|
||||
eventQ queue
|
||||
eventQ queue.Queue
|
||||
containers map[string]*container
|
||||
}
|
||||
|
||||
// NewClient creates a new local executor for windows
|
||||
func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, b Backend) (Client, error) {
|
||||
func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, b libcontainerdtypes.Backend) (libcontainerdtypes.Client, error) {
|
||||
c := &client{
|
||||
stateDir: stateDir,
|
||||
backend: b,
|
||||
|
@ -149,20 +154,35 @@ func (c *client) Version(ctx context.Context) (containerd.Version, error) {
|
|||
//}
|
||||
func (c *client) Create(_ context.Context, id string, spec *specs.Spec, runtimeOptions interface{}) error {
|
||||
if ctr := c.getContainer(id); ctr != nil {
|
||||
return errors.WithStack(newConflictError("id already in use"))
|
||||
return errors.WithStack(errdefs.Conflict(errors.New("id already in use")))
|
||||
}
|
||||
|
||||
// spec.Linux must be nil for Windows containers, but spec.Windows
|
||||
// will be filled in regardless of container platform. This is a
|
||||
// temporary workaround due to LCOW requiring layer folder paths,
|
||||
// which are stored under spec.Windows.
|
||||
//
|
||||
// TODO: @darrenstahlmsft fix this once the OCI spec is updated to
|
||||
// support layer folder paths for LCOW
|
||||
var err error
|
||||
if spec.Linux == nil {
|
||||
return c.createWindows(id, spec, runtimeOptions)
|
||||
err = c.createWindows(id, spec, runtimeOptions)
|
||||
} else {
|
||||
err = c.createLinux(id, spec, runtimeOptions)
|
||||
}
|
||||
return c.createLinux(id, spec, runtimeOptions)
|
||||
|
||||
if err == nil {
|
||||
c.eventQ.Append(id, func() {
|
||||
ei := libcontainerdtypes.EventInfo{
|
||||
ContainerID: id,
|
||||
}
|
||||
c.logger.WithFields(logrus.Fields{
|
||||
"container": id,
|
||||
"event": libcontainerdtypes.EventCreate,
|
||||
}).Info("sending event")
|
||||
err := c.backend.ProcessEvent(id, libcontainerdtypes.EventCreate, ei)
|
||||
if err != nil {
|
||||
c.logger.WithError(err).WithFields(logrus.Fields{
|
||||
"container": id,
|
||||
"event": libcontainerdtypes.EventCreate,
|
||||
}).Error("failed to process event")
|
||||
}
|
||||
})
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *client) createWindows(id string, spec *specs.Spec, runtimeOptions interface{}) error {
|
||||
|
@ -328,7 +348,7 @@ func (c *client) createWindows(id string, spec *specs.Spec, runtimeOptions inter
|
|||
isWindows: true,
|
||||
ociSpec: spec,
|
||||
hcsContainer: hcsContainer,
|
||||
status: StatusCreated,
|
||||
status: libcontainerdtypes.StatusCreated,
|
||||
waitCh: make(chan struct{}),
|
||||
}
|
||||
|
||||
|
@ -373,21 +393,12 @@ func (c *client) createLinux(id string, spec *specs.Spec, runtimeOptions interfa
|
|||
ContainerType: "linux",
|
||||
Owner: defaultOwner,
|
||||
TerminateOnLastHandleClosed: true,
|
||||
}
|
||||
|
||||
if lcowConfig.ActualMode == opengcs.ModeActualVhdx {
|
||||
configuration.HvRuntime = &hcsshim.HvRuntime{
|
||||
ImagePath: lcowConfig.Vhdx,
|
||||
BootSource: "Vhd",
|
||||
WritableBootSource: false,
|
||||
}
|
||||
} else {
|
||||
configuration.HvRuntime = &hcsshim.HvRuntime{
|
||||
HvRuntime: &hcsshim.HvRuntime{
|
||||
ImagePath: lcowConfig.KirdPath,
|
||||
LinuxKernelFile: lcowConfig.KernelFile,
|
||||
LinuxInitrdFile: lcowConfig.InitrdFile,
|
||||
LinuxBootParameters: lcowConfig.BootParameters,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
if spec.Windows == nil {
|
||||
|
@ -532,7 +543,7 @@ func (c *client) createLinux(id string, spec *specs.Spec, runtimeOptions interfa
|
|||
isWindows: false,
|
||||
ociSpec: spec,
|
||||
hcsContainer: hcsContainer,
|
||||
status: StatusCreated,
|
||||
status: libcontainerdtypes.StatusCreated,
|
||||
waitCh: make(chan struct{}),
|
||||
}
|
||||
|
||||
|
@ -556,23 +567,6 @@ func (c *client) createLinux(id string, spec *specs.Spec, runtimeOptions interfa
|
|||
c.containers[id] = ctr
|
||||
c.Unlock()
|
||||
|
||||
c.eventQ.append(id, func() {
|
||||
ei := EventInfo{
|
||||
ContainerID: id,
|
||||
}
|
||||
c.logger.WithFields(logrus.Fields{
|
||||
"container": ctr.id,
|
||||
"event": EventCreate,
|
||||
}).Info("sending event")
|
||||
err := c.backend.ProcessEvent(id, EventCreate, ei)
|
||||
if err != nil {
|
||||
c.logger.WithError(err).WithFields(logrus.Fields{
|
||||
"container": id,
|
||||
"event": EventCreate,
|
||||
}).Error("failed to process event")
|
||||
}
|
||||
})
|
||||
|
||||
logger.Debug("createLinux() completed successfully")
|
||||
return nil
|
||||
}
|
||||
|
@ -607,13 +601,13 @@ func (c *client) extractResourcesFromSpec(spec *specs.Spec, configuration *hcssh
|
|||
}
|
||||
}
|
||||
|
||||
func (c *client) Start(_ context.Context, id, _ string, withStdin bool, attachStdio StdioCallback) (int, error) {
|
||||
func (c *client) Start(_ context.Context, id, _ string, withStdin bool, attachStdio libcontainerdtypes.StdioCallback) (int, error) {
|
||||
ctr := c.getContainer(id)
|
||||
switch {
|
||||
case ctr == nil:
|
||||
return -1, errors.WithStack(newNotFoundError("no such container"))
|
||||
return -1, errors.WithStack(errdefs.NotFound(errors.New("no such container")))
|
||||
case ctr.init != nil:
|
||||
return -1, errors.WithStack(newConflictError("container already started"))
|
||||
return -1, errors.WithStack(errdefs.Conflict(errors.New("container already started")))
|
||||
}
|
||||
|
||||
logger := c.logger.WithField("container", id)
|
||||
|
@ -647,11 +641,13 @@ func (c *client) Start(_ context.Context, id, _ string, withStdin bool, attachSt
|
|||
|
||||
// Configure the environment for the process
|
||||
createProcessParms.Environment = setupEnvironmentVariables(ctr.ociSpec.Process.Env)
|
||||
|
||||
// Configure the CommandLine/CommandArgs
|
||||
setCommandLineAndArgs(ctr.isWindows, ctr.ociSpec.Process, createProcessParms)
|
||||
if ctr.isWindows {
|
||||
createProcessParms.CommandLine = strings.Join(ctr.ociSpec.Process.Args, " ")
|
||||
} else {
|
||||
createProcessParms.CommandArgs = ctr.ociSpec.Process.Args
|
||||
logger.Debugf("start commandLine: %s", createProcessParms.CommandLine)
|
||||
}
|
||||
|
||||
createProcessParms.User = ctr.ociSpec.Process.User.Username
|
||||
|
||||
// LCOW requires the raw OCI spec passed through HCS and onwards to
|
||||
|
@ -666,14 +662,31 @@ func (c *client) Start(_ context.Context, id, _ string, withStdin bool, attachSt
|
|||
}
|
||||
|
||||
ctr.Lock()
|
||||
defer ctr.Unlock()
|
||||
|
||||
// Start the command running in the container.
|
||||
newProcess, err := ctr.hcsContainer.CreateProcess(createProcessParms)
|
||||
if err != nil {
|
||||
logger.WithError(err).Error("CreateProcess() failed")
|
||||
// Fix for https://github.com/moby/moby/issues/38719.
|
||||
// If the init process failed to launch, we still need to reap the
|
||||
// container to avoid leaking it.
|
||||
//
|
||||
// Note we use the explicit exit code of 127 which is the
|
||||
// Linux shell equivalent of "command not found". Windows cannot
|
||||
// know ahead of time whether or not the command exists, especially
|
||||
// in the case of Hyper-V containers.
|
||||
ctr.Unlock()
|
||||
exitedAt := time.Now()
|
||||
p := &process{
|
||||
id: libcontainerdtypes.InitProcessName,
|
||||
pid: 0,
|
||||
}
|
||||
c.reapContainer(ctr, p, 127, exitedAt, nil, logger)
|
||||
return -1, err
|
||||
}
|
||||
|
||||
defer ctr.Unlock()
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if err := newProcess.Kill(); err != nil {
|
||||
|
@ -691,44 +704,47 @@ func (c *client) Start(_ context.Context, id, _ string, withStdin bool, attachSt
|
|||
}()
|
||||
p := &process{
|
||||
hcsProcess: newProcess,
|
||||
id: InitProcessName,
|
||||
id: libcontainerdtypes.InitProcessName,
|
||||
pid: newProcess.Pid(),
|
||||
}
|
||||
logger.WithField("pid", p.pid).Debug("init process started")
|
||||
|
||||
dio, err := newIOFromProcess(newProcess, ctr.ociSpec.Process.Terminal)
|
||||
ctr.status = libcontainerdtypes.StatusRunning
|
||||
ctr.init = p
|
||||
|
||||
// Spin up a go routine waiting for exit to handle cleanup
|
||||
go c.reapProcess(ctr, p)
|
||||
|
||||
// Don't shadow err here due to our deferred clean-up.
|
||||
var dio *cio.DirectIO
|
||||
dio, err = newIOFromProcess(newProcess, ctr.ociSpec.Process.Terminal)
|
||||
if err != nil {
|
||||
logger.WithError(err).Error("failed to get stdio pipes")
|
||||
return -1, err
|
||||
}
|
||||
_, err = attachStdio(dio)
|
||||
if err != nil {
|
||||
logger.WithError(err).Error("failed to attache stdio")
|
||||
logger.WithError(err).Error("failed to attach stdio")
|
||||
return -1, err
|
||||
}
|
||||
ctr.status = StatusRunning
|
||||
ctr.init = p
|
||||
|
||||
// Spin up a go routine waiting for exit to handle cleanup
|
||||
go c.reapProcess(ctr, p)
|
||||
|
||||
// Generate the associated event
|
||||
c.eventQ.append(id, func() {
|
||||
ei := EventInfo{
|
||||
c.eventQ.Append(id, func() {
|
||||
ei := libcontainerdtypes.EventInfo{
|
||||
ContainerID: id,
|
||||
ProcessID: InitProcessName,
|
||||
ProcessID: libcontainerdtypes.InitProcessName,
|
||||
Pid: uint32(p.pid),
|
||||
}
|
||||
c.logger.WithFields(logrus.Fields{
|
||||
"container": ctr.id,
|
||||
"event": EventStart,
|
||||
"event": libcontainerdtypes.EventStart,
|
||||
"event-info": ei,
|
||||
}).Info("sending event")
|
||||
err := c.backend.ProcessEvent(ei.ContainerID, EventStart, ei)
|
||||
err := c.backend.ProcessEvent(ei.ContainerID, libcontainerdtypes.EventStart, ei)
|
||||
if err != nil {
|
||||
c.logger.WithError(err).WithFields(logrus.Fields{
|
||||
"container": id,
|
||||
"event": EventStart,
|
||||
"event": libcontainerdtypes.EventStart,
|
||||
"event-info": ei,
|
||||
}).Error("failed to process event")
|
||||
}
|
||||
|
@ -737,6 +753,19 @@ func (c *client) Start(_ context.Context, id, _ string, withStdin bool, attachSt
|
|||
return p.pid, nil
|
||||
}
|
||||
|
||||
// setCommandLineAndArgs configures the HCS ProcessConfig based on an OCI process spec
|
||||
func setCommandLineAndArgs(isWindows bool, process *specs.Process, createProcessParms *hcsshim.ProcessConfig) {
|
||||
if isWindows {
|
||||
if process.CommandLine != "" {
|
||||
createProcessParms.CommandLine = process.CommandLine
|
||||
} else {
|
||||
createProcessParms.CommandLine = system.EscapeArgs(process.Args)
|
||||
}
|
||||
} else {
|
||||
createProcessParms.CommandArgs = process.Args
|
||||
}
|
||||
}
|
||||
|
||||
func newIOFromProcess(newProcess hcsshim.Process, terminal bool) (*cio.DirectIO, error) {
|
||||
stdin, stdout, stderr, err := newProcess.Stdio()
|
||||
if err != nil {
|
||||
|
@ -756,15 +785,15 @@ func newIOFromProcess(newProcess hcsshim.Process, terminal bool) (*cio.DirectIO,
|
|||
}
|
||||
|
||||
// Exec adds a process in an running container
|
||||
func (c *client) Exec(ctx context.Context, containerID, processID string, spec *specs.Process, withStdin bool, attachStdio StdioCallback) (int, error) {
|
||||
func (c *client) Exec(ctx context.Context, containerID, processID string, spec *specs.Process, withStdin bool, attachStdio libcontainerdtypes.StdioCallback) (int, error) {
|
||||
ctr := c.getContainer(containerID)
|
||||
switch {
|
||||
case ctr == nil:
|
||||
return -1, errors.WithStack(newNotFoundError("no such container"))
|
||||
return -1, errors.WithStack(errdefs.NotFound(errors.New("no such container")))
|
||||
case ctr.hcsContainer == nil:
|
||||
return -1, errors.WithStack(newInvalidParameterError("container is not running"))
|
||||
return -1, errors.WithStack(errdefs.InvalidParameter(errors.New("container is not running")))
|
||||
case ctr.execs != nil && ctr.execs[processID] != nil:
|
||||
return -1, errors.WithStack(newConflictError("id already in use"))
|
||||
return -1, errors.WithStack(errdefs.Conflict(errors.New("id already in use")))
|
||||
}
|
||||
logger := c.logger.WithFields(logrus.Fields{
|
||||
"container": containerID,
|
||||
|
@ -776,7 +805,7 @@ func (c *client) Exec(ctx context.Context, containerID, processID string, spec *
|
|||
// docker can always grab the output through logs. We also tell HCS to always
|
||||
// create stdin, even if it's not used - it will be closed shortly. Stderr
|
||||
// is only created if it we're not -t.
|
||||
createProcessParms := hcsshim.ProcessConfig{
|
||||
createProcessParms := &hcsshim.ProcessConfig{
|
||||
CreateStdInPipe: true,
|
||||
CreateStdOutPipe: true,
|
||||
CreateStdErrPipe: !spec.Terminal,
|
||||
|
@ -799,17 +828,15 @@ func (c *client) Exec(ctx context.Context, containerID, processID string, spec *
|
|||
|
||||
// Configure the environment for the process
|
||||
createProcessParms.Environment = setupEnvironmentVariables(spec.Env)
|
||||
if ctr.isWindows {
|
||||
createProcessParms.CommandLine = strings.Join(spec.Args, " ")
|
||||
} else {
|
||||
createProcessParms.CommandArgs = spec.Args
|
||||
}
|
||||
createProcessParms.User = spec.User.Username
|
||||
|
||||
// Configure the CommandLine/CommandArgs
|
||||
setCommandLineAndArgs(ctr.isWindows, spec, createProcessParms)
|
||||
logger.Debugf("exec commandLine: %s", createProcessParms.CommandLine)
|
||||
|
||||
createProcessParms.User = spec.User.Username
|
||||
|
||||
// Start the command running in the container.
|
||||
newProcess, err := ctr.hcsContainer.CreateProcess(&createProcessParms)
|
||||
newProcess, err := ctr.hcsContainer.CreateProcess(createProcessParms)
|
||||
if err != nil {
|
||||
logger.WithError(err).Errorf("exec's CreateProcess() failed")
|
||||
return -1, err
|
||||
|
@ -856,30 +883,30 @@ func (c *client) Exec(ctx context.Context, containerID, processID string, spec *
|
|||
// Spin up a go routine waiting for exit to handle cleanup
|
||||
go c.reapProcess(ctr, p)
|
||||
|
||||
c.eventQ.append(ctr.id, func() {
|
||||
ei := EventInfo{
|
||||
c.eventQ.Append(ctr.id, func() {
|
||||
ei := libcontainerdtypes.EventInfo{
|
||||
ContainerID: ctr.id,
|
||||
ProcessID: p.id,
|
||||
Pid: uint32(p.pid),
|
||||
}
|
||||
c.logger.WithFields(logrus.Fields{
|
||||
"container": ctr.id,
|
||||
"event": EventExecAdded,
|
||||
"event": libcontainerdtypes.EventExecAdded,
|
||||
"event-info": ei,
|
||||
}).Info("sending event")
|
||||
err := c.backend.ProcessEvent(ctr.id, EventExecAdded, ei)
|
||||
err := c.backend.ProcessEvent(ctr.id, libcontainerdtypes.EventExecAdded, ei)
|
||||
if err != nil {
|
||||
c.logger.WithError(err).WithFields(logrus.Fields{
|
||||
"container": ctr.id,
|
||||
"event": EventExecAdded,
|
||||
"event": libcontainerdtypes.EventExecAdded,
|
||||
"event-info": ei,
|
||||
}).Error("failed to process event")
|
||||
}
|
||||
err = c.backend.ProcessEvent(ctr.id, EventExecStarted, ei)
|
||||
err = c.backend.ProcessEvent(ctr.id, libcontainerdtypes.EventExecStarted, ei)
|
||||
if err != nil {
|
||||
c.logger.WithError(err).WithFields(logrus.Fields{
|
||||
"container": ctr.id,
|
||||
"event": EventExecStarted,
|
||||
"event": libcontainerdtypes.EventExecStarted,
|
||||
"event-info": ei,
|
||||
}).Error("failed to process event")
|
||||
}
|
||||
|
@ -905,7 +932,7 @@ func (c *client) SignalProcess(_ context.Context, containerID, processID string,
|
|||
})
|
||||
logger.Debug("Signal()")
|
||||
|
||||
if processID == InitProcessName {
|
||||
if processID == libcontainerdtypes.InitProcessName {
|
||||
if syscall.Signal(signal) == syscall.SIGKILL {
|
||||
// Terminate the compute system
|
||||
ctr.Lock()
|
||||
|
@ -961,7 +988,7 @@ func (c *client) CloseStdin(_ context.Context, containerID, processID string) er
|
|||
|
||||
// Pause handles pause requests for containers
|
||||
func (c *client) Pause(_ context.Context, containerID string) error {
|
||||
ctr, _, err := c.getProcess(containerID, InitProcessName)
|
||||
ctr, _, err := c.getProcess(containerID, libcontainerdtypes.InitProcessName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -977,21 +1004,21 @@ func (c *client) Pause(_ context.Context, containerID string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
ctr.status = StatusPaused
|
||||
ctr.status = libcontainerdtypes.StatusPaused
|
||||
|
||||
c.eventQ.append(containerID, func() {
|
||||
err := c.backend.ProcessEvent(containerID, EventPaused, EventInfo{
|
||||
c.eventQ.Append(containerID, func() {
|
||||
err := c.backend.ProcessEvent(containerID, libcontainerdtypes.EventPaused, libcontainerdtypes.EventInfo{
|
||||
ContainerID: containerID,
|
||||
ProcessID: InitProcessName,
|
||||
ProcessID: libcontainerdtypes.InitProcessName,
|
||||
})
|
||||
c.logger.WithFields(logrus.Fields{
|
||||
"container": ctr.id,
|
||||
"event": EventPaused,
|
||||
"event": libcontainerdtypes.EventPaused,
|
||||
}).Info("sending event")
|
||||
if err != nil {
|
||||
c.logger.WithError(err).WithFields(logrus.Fields{
|
||||
"container": containerID,
|
||||
"event": EventPaused,
|
||||
"event": libcontainerdtypes.EventPaused,
|
||||
}).Error("failed to process event")
|
||||
}
|
||||
})
|
||||
|
@ -1001,7 +1028,7 @@ func (c *client) Pause(_ context.Context, containerID string) error {
|
|||
|
||||
// Resume handles resume requests for containers
|
||||
func (c *client) Resume(_ context.Context, containerID string) error {
|
||||
ctr, _, err := c.getProcess(containerID, InitProcessName)
|
||||
ctr, _, err := c.getProcess(containerID, libcontainerdtypes.InitProcessName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1017,21 +1044,21 @@ func (c *client) Resume(_ context.Context, containerID string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
ctr.status = StatusRunning
|
||||
ctr.status = libcontainerdtypes.StatusRunning
|
||||
|
||||
c.eventQ.append(containerID, func() {
|
||||
err := c.backend.ProcessEvent(containerID, EventResumed, EventInfo{
|
||||
c.eventQ.Append(containerID, func() {
|
||||
err := c.backend.ProcessEvent(containerID, libcontainerdtypes.EventResumed, libcontainerdtypes.EventInfo{
|
||||
ContainerID: containerID,
|
||||
ProcessID: InitProcessName,
|
||||
ProcessID: libcontainerdtypes.InitProcessName,
|
||||
})
|
||||
c.logger.WithFields(logrus.Fields{
|
||||
"container": ctr.id,
|
||||
"event": EventResumed,
|
||||
"event": libcontainerdtypes.EventResumed,
|
||||
}).Info("sending event")
|
||||
if err != nil {
|
||||
c.logger.WithError(err).WithFields(logrus.Fields{
|
||||
"container": containerID,
|
||||
"event": EventResumed,
|
||||
"event": libcontainerdtypes.EventResumed,
|
||||
}).Error("failed to process event")
|
||||
}
|
||||
})
|
||||
|
@ -1040,8 +1067,8 @@ func (c *client) Resume(_ context.Context, containerID string) error {
|
|||
}
|
||||
|
||||
// Stats handles stats requests for containers
|
||||
func (c *client) Stats(_ context.Context, containerID string) (*Stats, error) {
|
||||
ctr, _, err := c.getProcess(containerID, InitProcessName)
|
||||
func (c *client) Stats(_ context.Context, containerID string) (*libcontainerdtypes.Stats, error) {
|
||||
ctr, _, err := c.getProcess(containerID, libcontainerdtypes.InitProcessName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1051,14 +1078,14 @@ func (c *client) Stats(_ context.Context, containerID string) (*Stats, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Stats{
|
||||
return &libcontainerdtypes.Stats{
|
||||
Read: readAt,
|
||||
HCSStats: &s,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Restore is the handler for restoring a container
|
||||
func (c *client) Restore(ctx context.Context, id string, attachStdio StdioCallback) (bool, int, error) {
|
||||
func (c *client) Restore(ctx context.Context, id string, attachStdio libcontainerdtypes.StdioCallback) (bool, int, error) {
|
||||
c.logger.WithField("container", id).Debug("restore()")
|
||||
|
||||
// TODO Windows: On RS1, a re-attach isn't possible.
|
||||
|
@ -1098,8 +1125,8 @@ func (c *client) ListPids(_ context.Context, _ string) ([]uint32, error) {
|
|||
// the containers could be Hyper-V containers, they would not be
|
||||
// visible on the container host. However, libcontainerd does have
|
||||
// that information.
|
||||
func (c *client) Summary(_ context.Context, containerID string) ([]Summary, error) {
|
||||
ctr, _, err := c.getProcess(containerID, InitProcessName)
|
||||
func (c *client) Summary(_ context.Context, containerID string) ([]libcontainerdtypes.Summary, error) {
|
||||
ctr, _, err := c.getProcess(containerID, libcontainerdtypes.InitProcessName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1109,9 +1136,19 @@ func (c *client) Summary(_ context.Context, containerID string) ([]Summary, erro
|
|||
return nil, err
|
||||
}
|
||||
|
||||
pl := make([]Summary, len(p))
|
||||
pl := make([]libcontainerdtypes.Summary, len(p))
|
||||
for i := range p {
|
||||
pl[i] = Summary(p[i])
|
||||
pl[i] = libcontainerdtypes.Summary{
|
||||
ImageName: p[i].ImageName,
|
||||
CreatedAt: p[i].CreateTimestamp,
|
||||
KernelTime_100Ns: p[i].KernelTime100ns,
|
||||
MemoryCommitBytes: p[i].MemoryCommitBytes,
|
||||
MemoryWorkingSetPrivateBytes: p[i].MemoryWorkingSetPrivateBytes,
|
||||
MemoryWorkingSetSharedBytes: p[i].MemoryWorkingSetSharedBytes,
|
||||
ProcessID: p[i].ProcessId,
|
||||
UserTime_100Ns: p[i].UserTime100ns,
|
||||
ExecID: "",
|
||||
}
|
||||
}
|
||||
return pl, nil
|
||||
}
|
||||
|
@ -1120,7 +1157,7 @@ func (c *client) DeleteTask(ctx context.Context, containerID string) (uint32, ti
|
|||
ec := -1
|
||||
ctr := c.getContainer(containerID)
|
||||
if ctr == nil {
|
||||
return uint32(ec), time.Now(), errors.WithStack(newNotFoundError("no such container"))
|
||||
return uint32(ec), time.Now(), errors.WithStack(errdefs.NotFound(errors.New("no such container")))
|
||||
}
|
||||
|
||||
select {
|
||||
|
@ -1141,32 +1178,32 @@ func (c *client) Delete(_ context.Context, containerID string) error {
|
|||
defer c.Unlock()
|
||||
ctr := c.containers[containerID]
|
||||
if ctr == nil {
|
||||
return errors.WithStack(newNotFoundError("no such container"))
|
||||
return errors.WithStack(errdefs.NotFound(errors.New("no such container")))
|
||||
}
|
||||
|
||||
ctr.Lock()
|
||||
defer ctr.Unlock()
|
||||
|
||||
switch ctr.status {
|
||||
case StatusCreated:
|
||||
case libcontainerdtypes.StatusCreated:
|
||||
if err := c.shutdownContainer(ctr); err != nil {
|
||||
return err
|
||||
}
|
||||
fallthrough
|
||||
case StatusStopped:
|
||||
case libcontainerdtypes.StatusStopped:
|
||||
delete(c.containers, containerID)
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.WithStack(newInvalidParameterError("container is not stopped"))
|
||||
return errors.WithStack(errdefs.InvalidParameter(errors.New("container is not stopped")))
|
||||
}
|
||||
|
||||
func (c *client) Status(ctx context.Context, containerID string) (Status, error) {
|
||||
func (c *client) Status(ctx context.Context, containerID string) (libcontainerdtypes.Status, error) {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
ctr := c.containers[containerID]
|
||||
if ctr == nil {
|
||||
return StatusUnknown, errors.WithStack(newNotFoundError("no such container"))
|
||||
return libcontainerdtypes.StatusUnknown, errors.WithStack(errdefs.NotFound(errors.New("no such container")))
|
||||
}
|
||||
|
||||
ctr.Lock()
|
||||
|
@ -1174,7 +1211,7 @@ func (c *client) Status(ctx context.Context, containerID string) (Status, error)
|
|||
return ctr.status, nil
|
||||
}
|
||||
|
||||
func (c *client) UpdateResources(ctx context.Context, containerID string, resources *Resources) error {
|
||||
func (c *client) UpdateResources(ctx context.Context, containerID string, resources *libcontainerdtypes.Resources) error {
|
||||
// Updating resource isn't supported on Windows
|
||||
// but we should return nil for enabling updating container
|
||||
return nil
|
||||
|
@ -1196,22 +1233,22 @@ func (c *client) getProcess(containerID, processID string) (*container, *process
|
|||
ctr := c.getContainer(containerID)
|
||||
switch {
|
||||
case ctr == nil:
|
||||
return nil, nil, errors.WithStack(newNotFoundError("no such container"))
|
||||
return nil, nil, errors.WithStack(errdefs.NotFound(errors.New("no such container")))
|
||||
case ctr.init == nil:
|
||||
return nil, nil, errors.WithStack(newNotFoundError("container is not running"))
|
||||
case processID == InitProcessName:
|
||||
return nil, nil, errors.WithStack(errdefs.NotFound(errors.New("container is not running")))
|
||||
case processID == libcontainerdtypes.InitProcessName:
|
||||
return ctr, ctr.init, nil
|
||||
default:
|
||||
ctr.Lock()
|
||||
defer ctr.Unlock()
|
||||
if ctr.execs == nil {
|
||||
return nil, nil, errors.WithStack(newNotFoundError("no execs"))
|
||||
return nil, nil, errors.WithStack(errdefs.NotFound(errors.New("no execs")))
|
||||
}
|
||||
}
|
||||
|
||||
p := ctr.execs[processID]
|
||||
if p == nil {
|
||||
return nil, nil, errors.WithStack(newNotFoundError("no such exec"))
|
||||
return nil, nil, errors.WithStack(errdefs.NotFound(errors.New("no such exec")))
|
||||
}
|
||||
|
||||
return ctr, p, nil
|
||||
|
@ -1309,42 +1346,12 @@ func (c *client) reapProcess(ctr *container, p *process) int {
|
|||
eventErr = fmt.Errorf("hcsProcess.Close() failed %s", err)
|
||||
}
|
||||
|
||||
if p.id == InitProcessName {
|
||||
// Update container status
|
||||
ctr.Lock()
|
||||
ctr.status = StatusStopped
|
||||
ctr.exitedAt = exitedAt
|
||||
ctr.exitCode = uint32(exitCode)
|
||||
close(ctr.waitCh)
|
||||
|
||||
if err := c.shutdownContainer(ctr); err != nil {
|
||||
exitCode = -1
|
||||
logger.WithError(err).Warn("failed to shutdown container")
|
||||
thisErr := fmt.Errorf("failed to shutdown container: %s", err)
|
||||
if eventErr != nil {
|
||||
eventErr = fmt.Errorf("%s: %s", eventErr, thisErr)
|
||||
} else {
|
||||
eventErr = thisErr
|
||||
}
|
||||
} else {
|
||||
logger.Debug("completed container shutdown")
|
||||
}
|
||||
ctr.Unlock()
|
||||
|
||||
if err := ctr.hcsContainer.Close(); err != nil {
|
||||
exitCode = -1
|
||||
logger.WithError(err).Error("failed to clean hcs container resources")
|
||||
thisErr := fmt.Errorf("failed to terminate container: %s", err)
|
||||
if eventErr != nil {
|
||||
eventErr = fmt.Errorf("%s: %s", eventErr, thisErr)
|
||||
} else {
|
||||
eventErr = thisErr
|
||||
}
|
||||
}
|
||||
if p.id == libcontainerdtypes.InitProcessName {
|
||||
exitCode, eventErr = c.reapContainer(ctr, p, exitCode, exitedAt, eventErr, logger)
|
||||
}
|
||||
|
||||
c.eventQ.append(ctr.id, func() {
|
||||
ei := EventInfo{
|
||||
c.eventQ.Append(ctr.id, func() {
|
||||
ei := libcontainerdtypes.EventInfo{
|
||||
ContainerID: ctr.id,
|
||||
ProcessID: p.id,
|
||||
Pid: uint32(p.pid),
|
||||
|
@ -1354,18 +1361,18 @@ func (c *client) reapProcess(ctr *container, p *process) int {
|
|||
}
|
||||
c.logger.WithFields(logrus.Fields{
|
||||
"container": ctr.id,
|
||||
"event": EventExit,
|
||||
"event": libcontainerdtypes.EventExit,
|
||||
"event-info": ei,
|
||||
}).Info("sending event")
|
||||
err := c.backend.ProcessEvent(ctr.id, EventExit, ei)
|
||||
err := c.backend.ProcessEvent(ctr.id, libcontainerdtypes.EventExit, ei)
|
||||
if err != nil {
|
||||
c.logger.WithError(err).WithFields(logrus.Fields{
|
||||
"container": ctr.id,
|
||||
"event": EventExit,
|
||||
"event": libcontainerdtypes.EventExit,
|
||||
"event-info": ei,
|
||||
}).Error("failed to process event")
|
||||
}
|
||||
if p.id != InitProcessName {
|
||||
if p.id != libcontainerdtypes.InitProcessName {
|
||||
ctr.Lock()
|
||||
delete(ctr.execs, p.id)
|
||||
ctr.Unlock()
|
||||
|
@ -1374,3 +1381,40 @@ func (c *client) reapProcess(ctr *container, p *process) int {
|
|||
|
||||
return exitCode
|
||||
}
|
||||
|
||||
// reapContainer shuts down the container and releases associated resources. It returns
|
||||
// the error to be logged in the eventInfo sent back to the monitor.
|
||||
func (c *client) reapContainer(ctr *container, p *process, exitCode int, exitedAt time.Time, eventErr error, logger *logrus.Entry) (int, error) {
|
||||
// Update container status
|
||||
ctr.Lock()
|
||||
ctr.status = libcontainerdtypes.StatusStopped
|
||||
ctr.exitedAt = exitedAt
|
||||
ctr.exitCode = uint32(exitCode)
|
||||
close(ctr.waitCh)
|
||||
|
||||
if err := c.shutdownContainer(ctr); err != nil {
|
||||
exitCode = -1
|
||||
logger.WithError(err).Warn("failed to shutdown container")
|
||||
thisErr := errors.Wrap(err, "failed to shutdown container")
|
||||
if eventErr != nil {
|
||||
eventErr = errors.Wrap(eventErr, thisErr.Error())
|
||||
} else {
|
||||
eventErr = thisErr
|
||||
}
|
||||
} else {
|
||||
logger.Debug("completed container shutdown")
|
||||
}
|
||||
ctr.Unlock()
|
||||
|
||||
if err := ctr.hcsContainer.Close(); err != nil {
|
||||
exitCode = -1
|
||||
logger.WithError(err).Error("failed to clean hcs container resources")
|
||||
thisErr := errors.Wrap(err, "failed to terminate container")
|
||||
if eventErr != nil {
|
||||
eventErr = errors.Wrap(eventErr, thisErr.Error())
|
||||
} else {
|
||||
eventErr = thisErr
|
||||
}
|
||||
}
|
||||
return exitCode, eventErr
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package libcontainerd // import "github.com/docker/docker/libcontainerd"
|
||||
package local // import "github.com/docker/docker/libcontainerd/local"
|
||||
|
||||
import (
|
||||
"io"
|
|
@ -1,4 +1,4 @@
|
|||
package libcontainerd // import "github.com/docker/docker/libcontainerd"
|
||||
package local // import "github.com/docker/docker/libcontainerd/local"
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
@ -19,6 +19,11 @@ func setupEnvironmentVariables(a []string) map[string]string {
|
|||
return r
|
||||
}
|
||||
|
||||
// LCOWOption is a CreateOption required for LCOW configuration
|
||||
type LCOWOption struct {
|
||||
Config *opengcs.Config
|
||||
}
|
||||
|
||||
// Apply for the LCOW option is a no-op.
|
||||
func (s *LCOWOption) Apply(interface{}) error {
|
||||
return nil
|
|
@ -1,4 +1,4 @@
|
|||
package libcontainerd // import "github.com/docker/docker/libcontainerd"
|
||||
package local // import "github.com/docker/docker/libcontainerd/local"
|
||||
|
||||
import (
|
||||
"testing"
|
|
@ -1,13 +1,15 @@
|
|||
package libcontainerd // import "github.com/docker/docker/libcontainerd"
|
||||
package queue // import "github.com/docker/docker/libcontainerd/queue"
|
||||
|
||||
import "sync"
|
||||
|
||||
type queue struct {
|
||||
// Queue is the structure used for holding functions in a queue.
|
||||
type Queue struct {
|
||||
sync.Mutex
|
||||
fns map[string]chan struct{}
|
||||
}
|
||||
|
||||
func (q *queue) append(id string, f func()) {
|
||||
// Append adds an item to a queue.
|
||||
func (q *Queue) Append(id string, f func()) {
|
||||
q.Lock()
|
||||
defer q.Unlock()
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package libcontainerd // import "github.com/docker/docker/libcontainerd"
|
||||
package queue // import "github.com/docker/docker/libcontainerd/queue"
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
@ -9,21 +9,21 @@ import (
|
|||
|
||||
func TestSerialization(t *testing.T) {
|
||||
var (
|
||||
q queue
|
||||
q Queue
|
||||
serialization = 1
|
||||
)
|
||||
|
||||
q.append("aaa", func() {
|
||||
q.Append("aaa", func() {
|
||||
//simulate a long time task
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
assert.Equal(t, serialization, 1)
|
||||
serialization = 2
|
||||
})
|
||||
q.append("aaa", func() {
|
||||
q.Append("aaa", func() {
|
||||
assert.Equal(t, serialization, 2)
|
||||
serialization = 3
|
||||
})
|
||||
q.append("aaa", func() {
|
||||
q.Append("aaa", func() {
|
||||
assert.Equal(t, serialization, 3)
|
||||
serialization = 4
|
||||
})
|
|
@ -1,11 +1,8 @@
|
|||
// +build !windows
|
||||
|
||||
package libcontainerd // import "github.com/docker/docker/libcontainerd"
|
||||
package remote // import "github.com/docker/docker/libcontainerd/remote"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -16,6 +13,7 @@ import (
|
|||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options"
|
||||
"github.com/containerd/containerd"
|
||||
apievents "github.com/containerd/containerd/api/events"
|
||||
"github.com/containerd/containerd/api/types"
|
||||
|
@ -28,6 +26,9 @@ import (
|
|||
"github.com/containerd/containerd/runtime/linux/runctypes"
|
||||
"github.com/containerd/typeurl"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/libcontainerd/queue"
|
||||
libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
|
||||
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
|
@ -37,10 +38,6 @@ import (
|
|||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// InitProcessName is the name given to the first process of a
|
||||
// container
|
||||
const InitProcessName = "init"
|
||||
|
||||
type container struct {
|
||||
mu sync.Mutex
|
||||
|
||||
|
@ -107,13 +104,13 @@ type client struct {
|
|||
logger *logrus.Entry
|
||||
ns string
|
||||
|
||||
backend Backend
|
||||
eventQ queue
|
||||
backend libcontainerdtypes.Backend
|
||||
eventQ queue.Queue
|
||||
containers map[string]*container
|
||||
}
|
||||
|
||||
// NewClient creates a new libcontainerd client from a containerd client
|
||||
func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, b Backend) (Client, error) {
|
||||
func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, b libcontainerdtypes.Backend) (libcontainerdtypes.Client, error) {
|
||||
c := &client{
|
||||
client: cli,
|
||||
stateDir: stateDir,
|
||||
|
@ -134,12 +131,12 @@ func (c *client) Version(ctx context.Context) (containerd.Version, error) {
|
|||
|
||||
// Restore loads the containerd container.
|
||||
// It should not be called concurrently with any other operation for the given ID.
|
||||
func (c *client) Restore(ctx context.Context, id string, attachStdio StdioCallback) (alive bool, pid int, err error) {
|
||||
func (c *client) Restore(ctx context.Context, id string, attachStdio libcontainerdtypes.StdioCallback) (alive bool, pid int, err error) {
|
||||
c.Lock()
|
||||
_, ok := c.containers[id]
|
||||
if ok {
|
||||
c.Unlock()
|
||||
return false, 0, errors.WithStack(newConflictError("id already in use"))
|
||||
return false, 0, errors.WithStack(errdefs.Conflict(errors.New("id already in use")))
|
||||
}
|
||||
|
||||
cntr := &container{}
|
||||
|
@ -174,7 +171,8 @@ func (c *client) Restore(ctx context.Context, id string, attachStdio StdioCallba
|
|||
attachIO := func(fifos *cio.FIFOSet) (cio.IO, error) {
|
||||
// dio must be assigned to the previously defined dio for the defer above
|
||||
// to handle cleanup
|
||||
dio, err = cio.NewDirectIO(ctx, fifos)
|
||||
|
||||
dio, err = c.newDirectIO(ctx, fifos)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -211,7 +209,7 @@ func (c *client) Restore(ctx context.Context, id string, attachStdio StdioCallba
|
|||
|
||||
func (c *client) Create(ctx context.Context, id string, ociSpec *specs.Spec, runtimeOptions interface{}) error {
|
||||
if ctr := c.getContainer(id); ctr != nil {
|
||||
return errors.WithStack(newConflictError("id already in use"))
|
||||
return errors.WithStack(errdefs.Conflict(errors.New("id already in use")))
|
||||
}
|
||||
|
||||
bdir, err := prepareBundleDir(filepath.Join(c.stateDir, id), ociSpec)
|
||||
|
@ -223,8 +221,7 @@ func (c *client) Create(ctx context.Context, id string, ociSpec *specs.Spec, run
|
|||
|
||||
cdCtr, err := c.client.NewContainer(ctx, id,
|
||||
containerd.WithSpec(ociSpec),
|
||||
// TODO(mlaventure): when containerd support lcow, revisit runtime value
|
||||
containerd.WithRuntime(fmt.Sprintf("io.containerd.runtime.v1.%s", runtime.GOOS), runtimeOptions))
|
||||
containerd.WithRuntime(runtimeName, runtimeOptions))
|
||||
if err != nil {
|
||||
return wrapError(err)
|
||||
}
|
||||
|
@ -240,13 +237,13 @@ func (c *client) Create(ctx context.Context, id string, ociSpec *specs.Spec, run
|
|||
}
|
||||
|
||||
// Start create and start a task for the specified containerd id
|
||||
func (c *client) Start(ctx context.Context, id, checkpointDir string, withStdin bool, attachStdio StdioCallback) (int, error) {
|
||||
func (c *client) Start(ctx context.Context, id, checkpointDir string, withStdin bool, attachStdio libcontainerdtypes.StdioCallback) (int, error) {
|
||||
ctr := c.getContainer(id)
|
||||
if ctr == nil {
|
||||
return -1, errors.WithStack(newNotFoundError("no such container"))
|
||||
return -1, errors.WithStack(errdefs.NotFound(errors.New("no such container")))
|
||||
}
|
||||
if t := ctr.getTask(); t != nil {
|
||||
return -1, errors.WithStack(newConflictError("container already started"))
|
||||
return -1, errors.WithStack(errdefs.Conflict(errors.New("container already started")))
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -288,17 +285,24 @@ func (c *client) Start(ctx context.Context, id, checkpointDir string, withStdin
|
|||
uid, gid := getSpecUser(spec)
|
||||
t, err = ctr.ctr.NewTask(ctx,
|
||||
func(id string) (cio.IO, error) {
|
||||
fifos := newFIFOSet(ctr.bundleDir, InitProcessName, withStdin, spec.Process.Terminal)
|
||||
fifos := newFIFOSet(ctr.bundleDir, libcontainerdtypes.InitProcessName, withStdin, spec.Process.Terminal)
|
||||
|
||||
rio, err = c.createIO(fifos, id, InitProcessName, stdinCloseSync, attachStdio)
|
||||
rio, err = c.createIO(fifos, id, libcontainerdtypes.InitProcessName, stdinCloseSync, attachStdio)
|
||||
return rio, err
|
||||
},
|
||||
func(_ context.Context, _ *containerd.Client, info *containerd.TaskInfo) error {
|
||||
info.Checkpoint = cp
|
||||
info.Options = &runctypes.CreateOptions{
|
||||
IoUid: uint32(uid),
|
||||
IoGid: uint32(gid),
|
||||
NoPivotRoot: os.Getenv("DOCKER_RAMDISK") != "",
|
||||
if runtime.GOOS != "windows" {
|
||||
info.Options = &runctypes.CreateOptions{
|
||||
IoUid: uint32(uid),
|
||||
IoGid: uint32(gid),
|
||||
NoPivotRoot: os.Getenv("DOCKER_RAMDISK") != "",
|
||||
}
|
||||
} else {
|
||||
// Make sure we set the runhcs options to debug if we are at debug level.
|
||||
if c.logger.Level == logrus.DebugLevel {
|
||||
info.Options = &options.Options{Debug: true}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
@ -335,18 +339,18 @@ func (c *client) Start(ctx context.Context, id, checkpointDir string, withStdin
|
|||
// for the container main process, the stdin fifo will be created in Create not
|
||||
// the Start call. stdinCloseSync channel should be closed after Start exec
|
||||
// process.
|
||||
func (c *client) Exec(ctx context.Context, containerID, processID string, spec *specs.Process, withStdin bool, attachStdio StdioCallback) (int, error) {
|
||||
func (c *client) Exec(ctx context.Context, containerID, processID string, spec *specs.Process, withStdin bool, attachStdio libcontainerdtypes.StdioCallback) (int, error) {
|
||||
ctr := c.getContainer(containerID)
|
||||
if ctr == nil {
|
||||
return -1, errors.WithStack(newNotFoundError("no such container"))
|
||||
return -1, errors.WithStack(errdefs.NotFound(errors.New("no such container")))
|
||||
}
|
||||
t := ctr.getTask()
|
||||
if t == nil {
|
||||
return -1, errors.WithStack(newInvalidParameterError("container is not running"))
|
||||
return -1, errors.WithStack(errdefs.InvalidParameter(errors.New("container is not running")))
|
||||
}
|
||||
|
||||
if p := ctr.getProcess(processID); p != nil {
|
||||
return -1, errors.WithStack(newConflictError("id already in use"))
|
||||
return -1, errors.WithStack(errdefs.Conflict(errors.New("id already in use")))
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -424,7 +428,7 @@ func (c *client) CloseStdin(ctx context.Context, containerID, processID string)
|
|||
}
|
||||
|
||||
func (c *client) Pause(ctx context.Context, containerID string) error {
|
||||
p, err := c.getProcess(containerID, InitProcessName)
|
||||
p, err := c.getProcess(containerID, libcontainerdtypes.InitProcessName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -433,7 +437,7 @@ func (c *client) Pause(ctx context.Context, containerID string) error {
|
|||
}
|
||||
|
||||
func (c *client) Resume(ctx context.Context, containerID string) error {
|
||||
p, err := c.getProcess(containerID, InitProcessName)
|
||||
p, err := c.getProcess(containerID, libcontainerdtypes.InitProcessName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -441,8 +445,8 @@ func (c *client) Resume(ctx context.Context, containerID string) error {
|
|||
return p.(containerd.Task).Resume(ctx)
|
||||
}
|
||||
|
||||
func (c *client) Stats(ctx context.Context, containerID string) (*Stats, error) {
|
||||
p, err := c.getProcess(containerID, InitProcessName)
|
||||
func (c *client) Stats(ctx context.Context, containerID string) (*libcontainerdtypes.Stats, error) {
|
||||
p, err := c.getProcess(containerID, libcontainerdtypes.InitProcessName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -456,11 +460,11 @@ func (c *client) Stats(ctx context.Context, containerID string) (*Stats, error)
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return interfaceToStats(m.Timestamp, v), nil
|
||||
return libcontainerdtypes.InterfaceToStats(m.Timestamp, v), nil
|
||||
}
|
||||
|
||||
func (c *client) ListPids(ctx context.Context, containerID string) ([]uint32, error) {
|
||||
p, err := c.getProcess(containerID, InitProcessName)
|
||||
p, err := c.getProcess(containerID, libcontainerdtypes.InitProcessName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -478,8 +482,8 @@ func (c *client) ListPids(ctx context.Context, containerID string) ([]uint32, er
|
|||
return pids, nil
|
||||
}
|
||||
|
||||
func (c *client) Summary(ctx context.Context, containerID string) ([]Summary, error) {
|
||||
p, err := c.getProcess(containerID, InitProcessName)
|
||||
func (c *client) Summary(ctx context.Context, containerID string) ([]libcontainerdtypes.Summary, error) {
|
||||
p, err := c.getProcess(containerID, libcontainerdtypes.InitProcessName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -489,7 +493,7 @@ func (c *client) Summary(ctx context.Context, containerID string) ([]Summary, er
|
|||
return nil, err
|
||||
}
|
||||
|
||||
var infos []Summary
|
||||
var infos []libcontainerdtypes.Summary
|
||||
for _, pi := range pis {
|
||||
i, err := typeurl.UnmarshalAny(pi.Info)
|
||||
if err != nil {
|
||||
|
@ -506,7 +510,7 @@ func (c *client) Summary(ctx context.Context, containerID string) ([]Summary, er
|
|||
}
|
||||
|
||||
func (c *client) DeleteTask(ctx context.Context, containerID string) (uint32, time.Time, error) {
|
||||
p, err := c.getProcess(containerID, InitProcessName)
|
||||
p, err := c.getProcess(containerID, libcontainerdtypes.InitProcessName)
|
||||
if err != nil {
|
||||
return 255, time.Now(), nil
|
||||
}
|
||||
|
@ -525,7 +529,7 @@ func (c *client) DeleteTask(ctx context.Context, containerID string) (uint32, ti
|
|||
func (c *client) Delete(ctx context.Context, containerID string) error {
|
||||
ctr := c.getContainer(containerID)
|
||||
if ctr == nil {
|
||||
return errors.WithStack(newNotFoundError("no such container"))
|
||||
return errors.WithStack(errdefs.NotFound(errors.New("no such container")))
|
||||
}
|
||||
|
||||
if err := ctr.ctr.Delete(ctx); err != nil {
|
||||
|
@ -546,27 +550,27 @@ func (c *client) Delete(ctx context.Context, containerID string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *client) Status(ctx context.Context, containerID string) (Status, error) {
|
||||
func (c *client) Status(ctx context.Context, containerID string) (libcontainerdtypes.Status, error) {
|
||||
ctr := c.getContainer(containerID)
|
||||
if ctr == nil {
|
||||
return StatusUnknown, errors.WithStack(newNotFoundError("no such container"))
|
||||
return libcontainerdtypes.StatusUnknown, errors.WithStack(errdefs.NotFound(errors.New("no such container")))
|
||||
}
|
||||
|
||||
t := ctr.getTask()
|
||||
if t == nil {
|
||||
return StatusUnknown, errors.WithStack(newNotFoundError("no such task"))
|
||||
return libcontainerdtypes.StatusUnknown, errors.WithStack(errdefs.NotFound(errors.New("no such task")))
|
||||
}
|
||||
|
||||
s, err := t.Status(ctx)
|
||||
if err != nil {
|
||||
return StatusUnknown, wrapError(err)
|
||||
return libcontainerdtypes.StatusUnknown, wrapError(err)
|
||||
}
|
||||
|
||||
return Status(s.Status), nil
|
||||
return libcontainerdtypes.Status(s.Status), nil
|
||||
}
|
||||
|
||||
func (c *client) CreateCheckpoint(ctx context.Context, containerID, checkpointDir string, exit bool) error {
|
||||
p, err := c.getProcess(containerID, InitProcessName)
|
||||
p, err := c.getProcess(containerID, libcontainerdtypes.InitProcessName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -648,33 +652,32 @@ func (c *client) removeContainer(id string) {
|
|||
func (c *client) getProcess(containerID, processID string) (containerd.Process, error) {
|
||||
ctr := c.getContainer(containerID)
|
||||
if ctr == nil {
|
||||
return nil, errors.WithStack(newNotFoundError("no such container"))
|
||||
return nil, errors.WithStack(errdefs.NotFound(errors.New("no such container")))
|
||||
}
|
||||
|
||||
t := ctr.getTask()
|
||||
if t == nil {
|
||||
return nil, errors.WithStack(newNotFoundError("container is not running"))
|
||||
return nil, errors.WithStack(errdefs.NotFound(errors.New("container is not running")))
|
||||
}
|
||||
if processID == InitProcessName {
|
||||
if processID == libcontainerdtypes.InitProcessName {
|
||||
return t, nil
|
||||
}
|
||||
|
||||
p := ctr.getProcess(processID)
|
||||
if p == nil {
|
||||
return nil, errors.WithStack(newNotFoundError("no such exec"))
|
||||
return nil, errors.WithStack(errdefs.NotFound(errors.New("no such exec")))
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// createIO creates the io to be used by a process
|
||||
// This needs to get a pointer to interface as upon closure the process may not have yet been registered
|
||||
func (c *client) createIO(fifos *cio.FIFOSet, containerID, processID string, stdinCloseSync chan struct{}, attachStdio StdioCallback) (cio.IO, error) {
|
||||
func (c *client) createIO(fifos *cio.FIFOSet, containerID, processID string, stdinCloseSync chan struct{}, attachStdio libcontainerdtypes.StdioCallback) (cio.IO, error) {
|
||||
var (
|
||||
io *cio.DirectIO
|
||||
err error
|
||||
)
|
||||
|
||||
io, err = cio.NewDirectIO(context.Background(), fifos)
|
||||
io, err = c.newDirectIO(context.Background(), fifos)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -713,8 +716,8 @@ func (c *client) createIO(fifos *cio.FIFOSet, containerID, processID string, std
|
|||
return rio, err
|
||||
}
|
||||
|
||||
func (c *client) processEvent(ctr *container, et EventType, ei EventInfo) {
|
||||
c.eventQ.append(ei.ContainerID, func() {
|
||||
func (c *client) processEvent(ctr *container, et libcontainerdtypes.EventType, ei libcontainerdtypes.EventInfo) {
|
||||
c.eventQ.Append(ei.ContainerID, func() {
|
||||
err := c.backend.ProcessEvent(ei.ContainerID, et, ei)
|
||||
if err != nil {
|
||||
c.logger.WithError(err).WithFields(logrus.Fields{
|
||||
|
@ -724,7 +727,7 @@ func (c *client) processEvent(ctr *container, et EventType, ei EventInfo) {
|
|||
}).Error("failed to process event")
|
||||
}
|
||||
|
||||
if et == EventExit && ei.ProcessID != ei.ContainerID {
|
||||
if et == libcontainerdtypes.EventExit && ei.ProcessID != ei.ContainerID {
|
||||
p := ctr.getProcess(ei.ProcessID)
|
||||
if p == nil {
|
||||
c.logger.WithError(errors.New("no such process")).
|
||||
|
@ -759,8 +762,8 @@ func (c *client) processEventStream(ctx context.Context, ns string) {
|
|||
var (
|
||||
err error
|
||||
ev *events.Envelope
|
||||
et EventType
|
||||
ei EventInfo
|
||||
et libcontainerdtypes.EventType
|
||||
ei libcontainerdtypes.EventInfo
|
||||
ctr *container
|
||||
)
|
||||
|
||||
|
@ -800,22 +803,22 @@ func (c *client) processEventStream(ctx context.Context, ns string) {
|
|||
|
||||
switch t := v.(type) {
|
||||
case *apievents.TaskCreate:
|
||||
et = EventCreate
|
||||
ei = EventInfo{
|
||||
et = libcontainerdtypes.EventCreate
|
||||
ei = libcontainerdtypes.EventInfo{
|
||||
ContainerID: t.ContainerID,
|
||||
ProcessID: t.ContainerID,
|
||||
Pid: t.Pid,
|
||||
}
|
||||
case *apievents.TaskStart:
|
||||
et = EventStart
|
||||
ei = EventInfo{
|
||||
et = libcontainerdtypes.EventStart
|
||||
ei = libcontainerdtypes.EventInfo{
|
||||
ContainerID: t.ContainerID,
|
||||
ProcessID: t.ContainerID,
|
||||
Pid: t.Pid,
|
||||
}
|
||||
case *apievents.TaskExit:
|
||||
et = EventExit
|
||||
ei = EventInfo{
|
||||
et = libcontainerdtypes.EventExit
|
||||
ei = libcontainerdtypes.EventInfo{
|
||||
ContainerID: t.ContainerID,
|
||||
ProcessID: t.ID,
|
||||
Pid: t.Pid,
|
||||
|
@ -823,33 +826,33 @@ func (c *client) processEventStream(ctx context.Context, ns string) {
|
|||
ExitedAt: t.ExitedAt,
|
||||
}
|
||||
case *apievents.TaskOOM:
|
||||
et = EventOOM
|
||||
ei = EventInfo{
|
||||
et = libcontainerdtypes.EventOOM
|
||||
ei = libcontainerdtypes.EventInfo{
|
||||
ContainerID: t.ContainerID,
|
||||
OOMKilled: true,
|
||||
}
|
||||
oomKilled = true
|
||||
case *apievents.TaskExecAdded:
|
||||
et = EventExecAdded
|
||||
ei = EventInfo{
|
||||
et = libcontainerdtypes.EventExecAdded
|
||||
ei = libcontainerdtypes.EventInfo{
|
||||
ContainerID: t.ContainerID,
|
||||
ProcessID: t.ExecID,
|
||||
}
|
||||
case *apievents.TaskExecStarted:
|
||||
et = EventExecStarted
|
||||
ei = EventInfo{
|
||||
et = libcontainerdtypes.EventExecStarted
|
||||
ei = libcontainerdtypes.EventInfo{
|
||||
ContainerID: t.ContainerID,
|
||||
ProcessID: t.ExecID,
|
||||
Pid: t.Pid,
|
||||
}
|
||||
case *apievents.TaskPaused:
|
||||
et = EventPaused
|
||||
ei = EventInfo{
|
||||
et = libcontainerdtypes.EventPaused
|
||||
ei = libcontainerdtypes.EventInfo{
|
||||
ContainerID: t.ContainerID,
|
||||
}
|
||||
case *apievents.TaskResumed:
|
||||
et = EventResumed
|
||||
ei = EventInfo{
|
||||
et = libcontainerdtypes.EventResumed
|
||||
ei = libcontainerdtypes.EventInfo{
|
||||
ContainerID: t.ContainerID,
|
||||
}
|
||||
default:
|
161
libcontainerd/remote/client_io_windows.go
Normal file
161
libcontainerd/remote/client_io_windows.go
Normal file
|
@ -0,0 +1,161 @@
|
|||
package remote // import "github.com/docker/docker/libcontainerd/remote"
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
winio "github.com/Microsoft/go-winio"
|
||||
"github.com/containerd/containerd/cio"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
// "golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type delayedConnection struct {
|
||||
l net.Listener
|
||||
con net.Conn
|
||||
wg sync.WaitGroup
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
func (dc *delayedConnection) Write(p []byte) (int, error) {
|
||||
dc.wg.Wait()
|
||||
if dc.con != nil {
|
||||
return dc.con.Write(p)
|
||||
}
|
||||
return 0, errors.New("use of closed network connection")
|
||||
}
|
||||
|
||||
func (dc *delayedConnection) Read(p []byte) (int, error) {
|
||||
dc.wg.Wait()
|
||||
if dc.con != nil {
|
||||
return dc.con.Read(p)
|
||||
}
|
||||
return 0, errors.New("use of closed network connection")
|
||||
}
|
||||
|
||||
func (dc *delayedConnection) unblockConnectionWaiters() {
|
||||
defer dc.once.Do(func() {
|
||||
dc.wg.Done()
|
||||
})
|
||||
}
|
||||
|
||||
func (dc *delayedConnection) Close() error {
|
||||
dc.l.Close()
|
||||
if dc.con != nil {
|
||||
return dc.con.Close()
|
||||
}
|
||||
dc.unblockConnectionWaiters()
|
||||
return nil
|
||||
}
|
||||
|
||||
type stdioPipes struct {
|
||||
stdin io.WriteCloser
|
||||
stdout io.ReadCloser
|
||||
stderr io.ReadCloser
|
||||
}
|
||||
|
||||
// newStdioPipes creates actual fifos for stdio.
|
||||
func (c *client) newStdioPipes(fifos *cio.FIFOSet) (_ *stdioPipes, err error) {
|
||||
p := &stdioPipes{}
|
||||
if fifos.Stdin != "" {
|
||||
c.logger.WithFields(logrus.Fields{"stdin": fifos.Stdin}).Debug("listen")
|
||||
l, err := winio.ListenPipe(fifos.Stdin, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to create stdin pipe %s", fifos.Stdin)
|
||||
}
|
||||
dc := &delayedConnection{
|
||||
l: l,
|
||||
}
|
||||
dc.wg.Add(1)
|
||||
defer func() {
|
||||
if err != nil {
|
||||
dc.Close()
|
||||
}
|
||||
}()
|
||||
p.stdin = dc
|
||||
|
||||
go func() {
|
||||
c.logger.WithFields(logrus.Fields{"stdin": fifos.Stdin}).Debug("accept")
|
||||
conn, err := l.Accept()
|
||||
if err != nil {
|
||||
dc.Close()
|
||||
if err != winio.ErrPipeListenerClosed {
|
||||
c.logger.WithError(err).Errorf("failed to accept stdin connection on %s", fifos.Stdin)
|
||||
}
|
||||
return
|
||||
}
|
||||
c.logger.WithFields(logrus.Fields{"stdin": fifos.Stdin}).Debug("connected")
|
||||
dc.con = conn
|
||||
dc.unblockConnectionWaiters()
|
||||
}()
|
||||
}
|
||||
|
||||
if fifos.Stdout != "" {
|
||||
c.logger.WithFields(logrus.Fields{"stdout": fifos.Stdout}).Debug("listen")
|
||||
l, err := winio.ListenPipe(fifos.Stdout, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to create stdout pipe %s", fifos.Stdout)
|
||||
}
|
||||
dc := &delayedConnection{
|
||||
l: l,
|
||||
}
|
||||
dc.wg.Add(1)
|
||||
defer func() {
|
||||
if err != nil {
|
||||
dc.Close()
|
||||
}
|
||||
}()
|
||||
p.stdout = dc
|
||||
|
||||
go func() {
|
||||
c.logger.WithFields(logrus.Fields{"stdout": fifos.Stdout}).Debug("accept")
|
||||
conn, err := l.Accept()
|
||||
if err != nil {
|
||||
dc.Close()
|
||||
if err != winio.ErrPipeListenerClosed {
|
||||
c.logger.WithError(err).Errorf("failed to accept stdout connection on %s", fifos.Stdout)
|
||||
}
|
||||
return
|
||||
}
|
||||
c.logger.WithFields(logrus.Fields{"stdout": fifos.Stdout}).Debug("connected")
|
||||
dc.con = conn
|
||||
dc.unblockConnectionWaiters()
|
||||
}()
|
||||
}
|
||||
|
||||
if fifos.Stderr != "" {
|
||||
c.logger.WithFields(logrus.Fields{"stderr": fifos.Stderr}).Debug("listen")
|
||||
l, err := winio.ListenPipe(fifos.Stderr, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to create stderr pipe %s", fifos.Stderr)
|
||||
}
|
||||
dc := &delayedConnection{
|
||||
l: l,
|
||||
}
|
||||
dc.wg.Add(1)
|
||||
defer func() {
|
||||
if err != nil {
|
||||
dc.Close()
|
||||
}
|
||||
}()
|
||||
p.stderr = dc
|
||||
|
||||
go func() {
|
||||
c.logger.WithFields(logrus.Fields{"stderr": fifos.Stderr}).Debug("accept")
|
||||
conn, err := l.Accept()
|
||||
if err != nil {
|
||||
dc.Close()
|
||||
if err != winio.ErrPipeListenerClosed {
|
||||
c.logger.WithError(err).Errorf("failed to accept stderr connection on %s", fifos.Stderr)
|
||||
}
|
||||
return
|
||||
}
|
||||
c.logger.WithFields(logrus.Fields{"stderr": fifos.Stderr}).Debug("connected")
|
||||
dc.con = conn
|
||||
dc.unblockConnectionWaiters()
|
||||
}()
|
||||
}
|
||||
return p, nil
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package libcontainerd // import "github.com/docker/docker/libcontainerd"
|
||||
package remote // import "github.com/docker/docker/libcontainerd/remote"
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -9,17 +9,20 @@ import (
|
|||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/cio"
|
||||
libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func summaryFromInterface(i interface{}) (*Summary, error) {
|
||||
return &Summary{}, nil
|
||||
const runtimeName = "io.containerd.runtime.v1.linux"
|
||||
|
||||
func summaryFromInterface(i interface{}) (*libcontainerdtypes.Summary, error) {
|
||||
return &libcontainerdtypes.Summary{}, nil
|
||||
}
|
||||
|
||||
func (c *client) UpdateResources(ctx context.Context, containerID string, resources *Resources) error {
|
||||
p, err := c.getProcess(containerID, InitProcessName)
|
||||
func (c *client) UpdateResources(ctx context.Context, containerID string, resources *libcontainerdtypes.Resources) error {
|
||||
p, err := c.getProcess(containerID, libcontainerdtypes.InitProcessName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -106,3 +109,7 @@ func newFIFOSet(bundleDir, processID string, withStdin, withTerminal bool) *cio.
|
|||
|
||||
return cio.NewFIFOSet(config, closer)
|
||||
}
|
||||
|
||||
func (c *client) newDirectIO(ctx context.Context, fifos *cio.FIFOSet) (*cio.DirectIO, error) {
|
||||
return cio.NewDirectIO(ctx, fifos)
|
||||
}
|
82
libcontainerd/remote/client_windows.go
Normal file
82
libcontainerd/remote/client_windows.go
Normal file
|
@ -0,0 +1,82 @@
|
|||
package remote // import "github.com/docker/docker/libcontainerd/remote"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options"
|
||||
"github.com/containerd/containerd/cio"
|
||||
|
||||
libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const runtimeName = "io.containerd.runhcs.v1"
|
||||
|
||||
func summaryFromInterface(i interface{}) (*libcontainerdtypes.Summary, error) {
|
||||
switch pd := i.(type) {
|
||||
case *options.ProcessDetails:
|
||||
return &libcontainerdtypes.Summary{
|
||||
ImageName: pd.ImageName,
|
||||
CreatedAt: pd.CreatedAt,
|
||||
KernelTime_100Ns: pd.KernelTime_100Ns,
|
||||
MemoryCommitBytes: pd.MemoryCommitBytes,
|
||||
MemoryWorkingSetPrivateBytes: pd.MemoryWorkingSetPrivateBytes,
|
||||
MemoryWorkingSetSharedBytes: pd.MemoryWorkingSetSharedBytes,
|
||||
ProcessID: pd.ProcessID,
|
||||
UserTime_100Ns: pd.UserTime_100Ns,
|
||||
ExecID: pd.ExecID,
|
||||
}, nil
|
||||
default:
|
||||
return nil, errors.Errorf("Unknown process details type %T", pd)
|
||||
}
|
||||
}
|
||||
|
||||
func prepareBundleDir(bundleDir string, ociSpec *specs.Spec) (string, error) {
|
||||
// TODO: (containerd) Determine if we need to use system.MkdirAllWithACL here
|
||||
return bundleDir, os.MkdirAll(bundleDir, 0755)
|
||||
}
|
||||
|
||||
func pipeName(containerID, processID, name string) string {
|
||||
return fmt.Sprintf(`\\.\pipe\containerd-%s-%s-%s`, containerID, processID, name)
|
||||
}
|
||||
|
||||
func newFIFOSet(bundleDir, processID string, withStdin, withTerminal bool) *cio.FIFOSet {
|
||||
containerID := filepath.Base(bundleDir)
|
||||
config := cio.Config{
|
||||
Terminal: withTerminal,
|
||||
Stdout: pipeName(containerID, processID, "stdout"),
|
||||
}
|
||||
|
||||
if withStdin {
|
||||
config.Stdin = pipeName(containerID, processID, "stdin")
|
||||
}
|
||||
|
||||
if !config.Terminal {
|
||||
config.Stderr = pipeName(containerID, processID, "stderr")
|
||||
}
|
||||
|
||||
return cio.NewFIFOSet(config, nil)
|
||||
}
|
||||
|
||||
func (c *client) newDirectIO(ctx context.Context, fifos *cio.FIFOSet) (*cio.DirectIO, error) {
|
||||
pipes, err := c.newStdioPipes(fifos)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cio.NewDirectIOFromFIFOSet(ctx, pipes.stdin, pipes.stdout, pipes.stderr, fifos), nil
|
||||
}
|
||||
|
||||
func (c *client) UpdateResources(ctx context.Context, containerID string, resources *libcontainerdtypes.Resources) error {
|
||||
// TODO: (containerd): Not implemented, but don't error.
|
||||
return nil
|
||||
}
|
||||
|
||||
func getSpecUser(ociSpec *specs.Spec) (int, int) {
|
||||
// TODO: (containerd): Not implemented, but don't error.
|
||||
// Not clear if we can even do this for LCOW.
|
||||
return 0, 0
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package libcontainerd // import "github.com/docker/docker/libcontainerd"
|
||||
package types // import "github.com/docker/docker/libcontainerd/types"
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -89,3 +89,6 @@ type Client interface {
|
|||
|
||||
// StdioCallback is called to connect a container or process stdio.
|
||||
type StdioCallback func(io *cio.DirectIO) (cio.IO, error)
|
||||
|
||||
// InitProcessName is the name given to the first process of a container
|
||||
const InitProcessName = "init"
|
|
@ -1,4 +1,4 @@
|
|||
package libcontainerd // import "github.com/docker/docker/libcontainerd"
|
||||
package types // import "github.com/docker/docker/libcontainerd/types"
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
@ -16,7 +16,8 @@ type Stats struct {
|
|||
Metrics *cgroups.Metrics
|
||||
}
|
||||
|
||||
func interfaceToStats(read time.Time, v interface{}) *Stats {
|
||||
// InterfaceToStats returns a stats object from the platform-specific interface.
|
||||
func InterfaceToStats(read time.Time, v interface{}) *Stats {
|
||||
return &Stats{
|
||||
Metrics: v.(*cgroups.Metrics),
|
||||
Read: read,
|
|
@ -1,14 +1,13 @@
|
|||
package libcontainerd // import "github.com/docker/docker/libcontainerd"
|
||||
package types // import "github.com/docker/docker/libcontainerd/types"
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/Microsoft/hcsshim"
|
||||
opengcs "github.com/Microsoft/opengcs/client"
|
||||
"github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options"
|
||||
)
|
||||
|
||||
// Summary contains a ProcessList item from HCS to support `top`
|
||||
type Summary hcsshim.ProcessListItem
|
||||
type Summary options.ProcessDetails
|
||||
|
||||
// Stats contains statistics from HCS
|
||||
type Stats struct {
|
||||
|
@ -16,7 +15,8 @@ type Stats struct {
|
|||
HCSStats *hcsshim.Statistics
|
||||
}
|
||||
|
||||
func interfaceToStats(read time.Time, v interface{}) *Stats {
|
||||
// InterfaceToStats returns a stats object from the platform-specific interface.
|
||||
func InterfaceToStats(read time.Time, v interface{}) *Stats {
|
||||
return &Stats{
|
||||
HCSStats: v.(*hcsshim.Statistics),
|
||||
Read: read,
|
||||
|
@ -26,11 +26,6 @@ func interfaceToStats(read time.Time, v interface{}) *Stats {
|
|||
// Resources defines updatable container resource values.
|
||||
type Resources struct{}
|
||||
|
||||
// LCOWOption is a CreateOption required for LCOW configuration
|
||||
type LCOWOption struct {
|
||||
Config *opengcs.Config
|
||||
}
|
||||
|
||||
// Checkpoint holds the details of a checkpoint (not supported in windows)
|
||||
type Checkpoint struct {
|
||||
Name string
|
16
pkg/system/args_windows.go
Normal file
16
pkg/system/args_windows.go
Normal file
|
@ -0,0 +1,16 @@
|
|||
package system // import "github.com/docker/docker/pkg/system"
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// EscapeArgs makes a Windows-style escaped command line from a set of arguments
|
||||
func EscapeArgs(args []string) string {
|
||||
escapedArgs := make([]string, len(args))
|
||||
for i, a := range args {
|
||||
escapedArgs[i] = windows.EscapeArg(a)
|
||||
}
|
||||
return strings.Join(escapedArgs, " ")
|
||||
}
|
|
@ -5,3 +5,8 @@ package system // import "github.com/docker/docker/pkg/system"
|
|||
// InitLCOW does nothing since LCOW is a windows only feature
|
||||
func InitLCOW(experimental bool) {
|
||||
}
|
||||
|
||||
// ContainerdRuntimeSupported returns true if the use of ContainerD runtime is supported.
|
||||
func ContainerdRuntimeSupported(_ bool, _ string) bool {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -1,7 +1,19 @@
|
|||
package system // import "github.com/docker/docker/pkg/system"
|
||||
|
||||
// lcowSupported determines if Linux Containers on Windows are supported.
|
||||
var lcowSupported = false
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var (
|
||||
// lcowSupported determines if Linux Containers on Windows are supported.
|
||||
lcowSupported = false
|
||||
|
||||
// containerdRuntimeSupported determines if ContainerD should be the runtime.
|
||||
// As of March 2019, this is an experimental feature.
|
||||
containerdRuntimeSupported = false
|
||||
)
|
||||
|
||||
// InitLCOW sets whether LCOW is supported or not
|
||||
func InitLCOW(experimental bool) {
|
||||
|
@ -10,3 +22,19 @@ func InitLCOW(experimental bool) {
|
|||
lcowSupported = true
|
||||
}
|
||||
}
|
||||
|
||||
// InitContainerdRuntime sets whether to use ContainerD for runtime
|
||||
// on Windows. This is an experimental feature still in development, and
|
||||
// also requires an environment variable to be set (so as not to turn the
|
||||
// feature on from simply experimental which would also mean LCOW.
|
||||
func InitContainerdRuntime(experimental bool, cdPath string) {
|
||||
if experimental && len(cdPath) > 0 && len(os.Getenv("DOCKER_WINDOWS_CONTAINERD_RUNTIME")) > 0 {
|
||||
logrus.Warnf("Using ContainerD runtime. This feature is experimental")
|
||||
containerdRuntimeSupported = true
|
||||
}
|
||||
}
|
||||
|
||||
// ContainerdRuntimeSupported returns true if the use of ContainerD runtime is supported.
|
||||
func ContainerdRuntimeSupported() bool {
|
||||
return containerdRuntimeSupported
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/containerd/containerd/runtime/linux/runctypes"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/libcontainerd"
|
||||
libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
@ -30,11 +31,11 @@ type ExitHandler interface {
|
|||
// However right now this whole package is tied to github.com/docker/docker/libcontainerd
|
||||
type Client interface {
|
||||
Create(ctx context.Context, containerID string, spec *specs.Spec, runtimeOptions interface{}) error
|
||||
Restore(ctx context.Context, containerID string, attachStdio libcontainerd.StdioCallback) (alive bool, pid int, err error)
|
||||
Status(ctx context.Context, containerID string) (libcontainerd.Status, error)
|
||||
Restore(ctx context.Context, containerID string, attachStdio libcontainerdtypes.StdioCallback) (alive bool, pid int, err error)
|
||||
Status(ctx context.Context, containerID string) (libcontainerdtypes.Status, error)
|
||||
Delete(ctx context.Context, containerID string) error
|
||||
DeleteTask(ctx context.Context, containerID string) (uint32, time.Time, error)
|
||||
Start(ctx context.Context, containerID, checkpointDir string, withStdin bool, attachStdio libcontainerd.StdioCallback) (pid int, err error)
|
||||
Start(ctx context.Context, containerID, checkpointDir string, withStdin bool, attachStdio libcontainerdtypes.StdioCallback) (pid int, err error)
|
||||
SignalProcess(ctx context.Context, containerID, processID string, signal int) error
|
||||
}
|
||||
|
||||
|
@ -87,7 +88,7 @@ func (e *Executor) Create(id string, spec specs.Spec, stdout, stderr io.WriteClo
|
|||
logrus.WithError(err2).WithField("id", id).Warn("Received an error while attempting to read plugin status")
|
||||
}
|
||||
} else {
|
||||
if status != libcontainerd.StatusRunning && status != libcontainerd.StatusUnknown {
|
||||
if status != libcontainerdtypes.StatusRunning && status != libcontainerdtypes.StatusUnknown {
|
||||
if err2 := e.client.Delete(ctx, id); err2 != nil && !errdefs.IsNotFound(err2) {
|
||||
logrus.WithError(err2).WithField("plugin", id).Error("Error cleaning up containerd container")
|
||||
}
|
||||
|
@ -122,19 +123,19 @@ func (e *Executor) Restore(id string, stdout, stderr io.WriteCloser) (bool, erro
|
|||
// IsRunning returns if the container with the given id is running
|
||||
func (e *Executor) IsRunning(id string) (bool, error) {
|
||||
status, err := e.client.Status(context.Background(), id)
|
||||
return status == libcontainerd.StatusRunning, err
|
||||
return status == libcontainerdtypes.StatusRunning, err
|
||||
}
|
||||
|
||||
// Signal sends the specified signal to the container
|
||||
func (e *Executor) Signal(id string, signal int) error {
|
||||
return e.client.SignalProcess(context.Background(), id, libcontainerd.InitProcessName, signal)
|
||||
return e.client.SignalProcess(context.Background(), id, libcontainerdtypes.InitProcessName, signal)
|
||||
}
|
||||
|
||||
// ProcessEvent handles events from containerd
|
||||
// All events are ignored except the exit event, which is sent of to the stored handler
|
||||
func (e *Executor) ProcessEvent(id string, et libcontainerd.EventType, ei libcontainerd.EventInfo) error {
|
||||
func (e *Executor) ProcessEvent(id string, et libcontainerdtypes.EventType, ei libcontainerdtypes.EventInfo) error {
|
||||
switch et {
|
||||
case libcontainerd.EventExit:
|
||||
case libcontainerdtypes.EventExit:
|
||||
deleteTaskAndContainer(context.Background(), e.client, id)
|
||||
return e.exitHandler.HandleExitEvent(ei.ContainerID)
|
||||
}
|
||||
|
@ -152,7 +153,7 @@ func (c *rio) Wait() {
|
|||
c.IO.Wait()
|
||||
}
|
||||
|
||||
func attachStreamsFunc(stdout, stderr io.WriteCloser) libcontainerd.StdioCallback {
|
||||
func attachStreamsFunc(stdout, stderr io.WriteCloser) libcontainerdtypes.StdioCallback {
|
||||
return func(iop *cio.DirectIO) (cio.IO, error) {
|
||||
if iop.Stdin != nil {
|
||||
iop.Stdin.Close()
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/libcontainerd"
|
||||
libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
"gotest.tools/assert"
|
||||
|
@ -82,22 +82,22 @@ func (c *mockClient) Create(ctx context.Context, id string, _ *specs.Spec, _ int
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *mockClient) Restore(ctx context.Context, id string, attachStdio libcontainerd.StdioCallback) (alive bool, pid int, err error) {
|
||||
func (c *mockClient) Restore(ctx context.Context, id string, attachStdio libcontainerdtypes.StdioCallback) (alive bool, pid int, err error) {
|
||||
return false, 0, nil
|
||||
}
|
||||
|
||||
func (c *mockClient) Status(ctx context.Context, id string) (libcontainerd.Status, error) {
|
||||
func (c *mockClient) Status(ctx context.Context, id string) (libcontainerdtypes.Status, error) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
running, ok := c.containers[id]
|
||||
if !ok {
|
||||
return libcontainerd.StatusUnknown, errors.New("not found")
|
||||
return libcontainerdtypes.StatusUnknown, errors.New("not found")
|
||||
}
|
||||
if running {
|
||||
return libcontainerd.StatusRunning, nil
|
||||
return libcontainerdtypes.StatusRunning, nil
|
||||
}
|
||||
return libcontainerd.StatusStopped, nil
|
||||
return libcontainerdtypes.StatusStopped, nil
|
||||
}
|
||||
|
||||
func (c *mockClient) Delete(ctx context.Context, id string) error {
|
||||
|
@ -111,7 +111,7 @@ func (c *mockClient) DeleteTask(ctx context.Context, id string) (uint32, time.Ti
|
|||
return 0, time.Time{}, nil
|
||||
}
|
||||
|
||||
func (c *mockClient) Start(ctx context.Context, id, checkpointDir string, withStdin bool, attachStdio libcontainerd.StdioCallback) (pid int, err error) {
|
||||
func (c *mockClient) Start(ctx context.Context, id, checkpointDir string, withStdin bool, attachStdio libcontainerdtypes.StdioCallback) (pid int, err error) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
# the following lines are in sorted order, FYI
|
||||
github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109
|
||||
github.com/Microsoft/hcsshim v0.8.6
|
||||
github.com/Microsoft/go-winio v0.4.11
|
||||
github.com/Microsoft/hcsshim ada9cb39f715fb568e1030e7613732bb4f1e4aeb
|
||||
github.com/Microsoft/go-winio 4de24ed3e8c509e6d1f609a8cb6b1c9fd9816e6d
|
||||
github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
|
||||
github.com/go-check/check 4ed411733c5785b40214c70bce814c3a3a689609 https://github.com/cpuguy83/check.git
|
||||
github.com/golang/gddo 9b12a26f3fbd7397dee4e20939ddca719d840d2a
|
||||
github.com/google/uuid v1.1.1
|
||||
github.com/gorilla/mux v1.7.0
|
||||
github.com/Microsoft/opengcs v0.3.9
|
||||
github.com/Microsoft/opengcs a10967154e143a36014584a6f664344e3bb0aa64
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1
|
||||
github.com/kr/pty 5cf931ef8f
|
||||
github.com/mattn/go-shellwords v1.0.3
|
||||
github.com/sirupsen/logrus v1.0.6
|
||||
github.com/sirupsen/logrus v1.3.0
|
||||
github.com/tchap/go-patricia v2.2.6
|
||||
github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3
|
||||
golang.org/x/net a680a1efc54dd51c040b3b5ce4939ea3cf2ea0d1
|
||||
|
|
15
vendor/github.com/Microsoft/go-winio/internal/etw/etw.go
generated
vendored
Normal file
15
vendor/github.com/Microsoft/go-winio/internal/etw/etw.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
// Package etw provides support for TraceLogging-based ETW (Event Tracing
|
||||
// for Windows). TraceLogging is a format of ETW events that are self-describing
|
||||
// (the event contains information on its own schema). This allows them to be
|
||||
// decoded without needing a separate manifest with event information. The
|
||||
// implementation here is based on the information found in
|
||||
// TraceLoggingProvider.h in the Windows SDK, which implements TraceLogging as a
|
||||
// set of C macros.
|
||||
package etw
|
||||
|
||||
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go etw.go
|
||||
|
||||
//sys eventRegister(providerId *windows.GUID, callback uintptr, callbackContext uintptr, providerHandle *providerHandle) (win32err error) = advapi32.EventRegister
|
||||
//sys eventUnregister(providerHandle providerHandle) (win32err error) = advapi32.EventUnregister
|
||||
//sys eventWriteTransfer(providerHandle providerHandle, descriptor *EventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) = advapi32.EventWriteTransfer
|
||||
//sys eventSetInformation(providerHandle providerHandle, class eventInfoClass, information uintptr, length uint32) (win32err error) = advapi32.EventSetInformation
|
65
vendor/github.com/Microsoft/go-winio/internal/etw/eventdata.go
generated
vendored
Normal file
65
vendor/github.com/Microsoft/go-winio/internal/etw/eventdata.go
generated
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
package etw
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// EventData maintains a buffer which builds up the data for an ETW event. It
|
||||
// needs to be paired with EventMetadata which describes the event.
|
||||
type EventData struct {
|
||||
buffer bytes.Buffer
|
||||
}
|
||||
|
||||
// Bytes returns the raw binary data containing the event data. The returned
|
||||
// value is not copied from the internal buffer, so it can be mutated by the
|
||||
// EventData object after it is returned.
|
||||
func (ed *EventData) Bytes() []byte {
|
||||
return ed.buffer.Bytes()
|
||||
}
|
||||
|
||||
// WriteString appends a string, including the null terminator, to the buffer.
|
||||
func (ed *EventData) WriteString(data string) {
|
||||
ed.buffer.WriteString(data)
|
||||
ed.buffer.WriteByte(0)
|
||||
}
|
||||
|
||||
// WriteInt8 appends a int8 to the buffer.
|
||||
func (ed *EventData) WriteInt8(value int8) {
|
||||
ed.buffer.WriteByte(uint8(value))
|
||||
}
|
||||
|
||||
// WriteInt16 appends a int16 to the buffer.
|
||||
func (ed *EventData) WriteInt16(value int16) {
|
||||
binary.Write(&ed.buffer, binary.LittleEndian, value)
|
||||
}
|
||||
|
||||
// WriteInt32 appends a int32 to the buffer.
|
||||
func (ed *EventData) WriteInt32(value int32) {
|
||||
binary.Write(&ed.buffer, binary.LittleEndian, value)
|
||||
}
|
||||
|
||||
// WriteInt64 appends a int64 to the buffer.
|
||||
func (ed *EventData) WriteInt64(value int64) {
|
||||
binary.Write(&ed.buffer, binary.LittleEndian, value)
|
||||
}
|
||||
|
||||
// WriteUint8 appends a uint8 to the buffer.
|
||||
func (ed *EventData) WriteUint8(value uint8) {
|
||||
ed.buffer.WriteByte(value)
|
||||
}
|
||||
|
||||
// WriteUint16 appends a uint16 to the buffer.
|
||||
func (ed *EventData) WriteUint16(value uint16) {
|
||||
binary.Write(&ed.buffer, binary.LittleEndian, value)
|
||||
}
|
||||
|
||||
// WriteUint32 appends a uint32 to the buffer.
|
||||
func (ed *EventData) WriteUint32(value uint32) {
|
||||
binary.Write(&ed.buffer, binary.LittleEndian, value)
|
||||
}
|
||||
|
||||
// WriteUint64 appends a uint64 to the buffer.
|
||||
func (ed *EventData) WriteUint64(value uint64) {
|
||||
binary.Write(&ed.buffer, binary.LittleEndian, value)
|
||||
}
|
29
vendor/github.com/Microsoft/go-winio/internal/etw/eventdatadescriptor.go
generated
vendored
Normal file
29
vendor/github.com/Microsoft/go-winio/internal/etw/eventdatadescriptor.go
generated
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
package etw
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type eventDataDescriptorType uint8
|
||||
|
||||
const (
|
||||
eventDataDescriptorTypeUserData eventDataDescriptorType = iota
|
||||
eventDataDescriptorTypeEventMetadata
|
||||
eventDataDescriptorTypeProviderMetadata
|
||||
)
|
||||
|
||||
type eventDataDescriptor struct {
|
||||
ptr ptr64
|
||||
size uint32
|
||||
dataType eventDataDescriptorType
|
||||
reserved1 uint8
|
||||
reserved2 uint16
|
||||
}
|
||||
|
||||
func newEventDataDescriptor(dataType eventDataDescriptorType, buffer []byte) eventDataDescriptor {
|
||||
return eventDataDescriptor{
|
||||
ptr: ptr64{ptr: unsafe.Pointer(&buffer[0])},
|
||||
size: uint32(len(buffer)),
|
||||
dataType: dataType,
|
||||
}
|
||||
}
|
67
vendor/github.com/Microsoft/go-winio/internal/etw/eventdescriptor.go
generated
vendored
Normal file
67
vendor/github.com/Microsoft/go-winio/internal/etw/eventdescriptor.go
generated
vendored
Normal file
|
@ -0,0 +1,67 @@
|
|||
package etw
|
||||
|
||||
// Channel represents the ETW logging channel that is used. It can be used by
|
||||
// event consumers to give an event special treatment.
|
||||
type Channel uint8
|
||||
|
||||
const (
|
||||
// ChannelTraceLogging is the default channel for TraceLogging events. It is
|
||||
// not required to be used for TraceLogging, but will prevent decoding
|
||||
// issues for these events on older operating systems.
|
||||
ChannelTraceLogging Channel = 11
|
||||
)
|
||||
|
||||
// Level represents the ETW logging level. There are several predefined levels
|
||||
// that are commonly used, but technically anything from 0-255 is allowed.
|
||||
// Lower levels indicate more important events, and 0 indicates an event that
|
||||
// will always be collected.
|
||||
type Level uint8
|
||||
|
||||
// Predefined ETW log levels.
|
||||
const (
|
||||
LevelAlways Level = iota
|
||||
LevelCritical
|
||||
LevelError
|
||||
LevelWarning
|
||||
LevelInfo
|
||||
LevelVerbose
|
||||
)
|
||||
|
||||
// EventDescriptor represents various metadata for an ETW event.
|
||||
type EventDescriptor struct {
|
||||
id uint16
|
||||
version uint8
|
||||
Channel Channel
|
||||
Level Level
|
||||
Opcode uint8
|
||||
Task uint16
|
||||
Keyword uint64
|
||||
}
|
||||
|
||||
// NewEventDescriptor returns an EventDescriptor initialized for use with
|
||||
// TraceLogging.
|
||||
func NewEventDescriptor() *EventDescriptor {
|
||||
// Standard TraceLogging events default to the TraceLogging channel, and
|
||||
// verbose level.
|
||||
return &EventDescriptor{
|
||||
Channel: ChannelTraceLogging,
|
||||
Level: LevelVerbose,
|
||||
}
|
||||
}
|
||||
|
||||
// Identity returns the identity of the event. If the identity is not 0, it
|
||||
// should uniquely identify the other event metadata (contained in
|
||||
// EventDescriptor, and field metadata). Only the lower 24 bits of this value
|
||||
// are relevant.
|
||||
func (ed *EventDescriptor) Identity() uint32 {
|
||||
return (uint32(ed.version) << 16) | uint32(ed.id)
|
||||
}
|
||||
|
||||
// SetIdentity sets the identity of the event. If the identity is not 0, it
|
||||
// should uniquely identify the other event metadata (contained in
|
||||
// EventDescriptor, and field metadata). Only the lower 24 bits of this value
|
||||
// are relevant.
|
||||
func (ed *EventDescriptor) SetIdentity(identity uint32) {
|
||||
ed.id = uint16(identity)
|
||||
ed.version = uint8(identity >> 16)
|
||||
}
|
177
vendor/github.com/Microsoft/go-winio/internal/etw/eventmetadata.go
generated
vendored
Normal file
177
vendor/github.com/Microsoft/go-winio/internal/etw/eventmetadata.go
generated
vendored
Normal file
|
@ -0,0 +1,177 @@
|
|||
package etw
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// InType indicates the type of data contained in the ETW event.
|
||||
type InType byte
|
||||
|
||||
// Various InType definitions for TraceLogging. These must match the definitions
|
||||
// found in TraceLoggingProvider.h in the Windows SDK.
|
||||
const (
|
||||
InTypeNull InType = iota
|
||||
InTypeUnicodeString
|
||||
InTypeANSIString
|
||||
InTypeInt8
|
||||
InTypeUint8
|
||||
InTypeInt16
|
||||
InTypeUint16
|
||||
InTypeInt32
|
||||
InTypeUint32
|
||||
InTypeInt64
|
||||
InTypeUint64
|
||||
InTypeFloat
|
||||
InTypeDouble
|
||||
InTypeBool32
|
||||
InTypeBinary
|
||||
InTypeGUID
|
||||
InTypePointerUnsupported
|
||||
InTypeFileTime
|
||||
InTypeSystemTime
|
||||
InTypeSID
|
||||
InTypeHexInt32
|
||||
InTypeHexInt64
|
||||
InTypeCountedString
|
||||
InTypeCountedANSIString
|
||||
InTypeStruct
|
||||
InTypeCountedBinary
|
||||
InTypeCountedArray InType = 32
|
||||
InTypeArray InType = 64
|
||||
)
|
||||
|
||||
// OutType specifies a hint to the event decoder for how the value should be
|
||||
// formatted.
|
||||
type OutType byte
|
||||
|
||||
// Various OutType definitions for TraceLogging. These must match the
|
||||
// definitions found in TraceLoggingProvider.h in the Windows SDK.
|
||||
const (
|
||||
// OutTypeDefault indicates that the default formatting for the InType will
|
||||
// be used by the event decoder.
|
||||
OutTypeDefault OutType = iota
|
||||
OutTypeNoPrint
|
||||
OutTypeString
|
||||
OutTypeBoolean
|
||||
OutTypeHex
|
||||
OutTypePID
|
||||
OutTypeTID
|
||||
OutTypePort
|
||||
OutTypeIPv4
|
||||
OutTypeIPv6
|
||||
OutTypeSocketAddress
|
||||
OutTypeXML
|
||||
OutTypeJSON
|
||||
OutTypeWin32Error
|
||||
OutTypeNTStatus
|
||||
OutTypeHResult
|
||||
OutTypeFileTime
|
||||
OutTypeSigned
|
||||
OutTypeUnsigned
|
||||
OutTypeUTF8 OutType = 35
|
||||
OutTypePKCS7WithTypeInfo OutType = 36
|
||||
OutTypeCodePointer OutType = 37
|
||||
OutTypeDateTimeUTC OutType = 38
|
||||
)
|
||||
|
||||
// EventMetadata maintains a buffer which builds up the metadata for an ETW
|
||||
// event. It needs to be paired with EventData which describes the event.
|
||||
type EventMetadata struct {
|
||||
buffer bytes.Buffer
|
||||
}
|
||||
|
||||
// Bytes returns the raw binary data containing the event metadata. Before being
|
||||
// returned, the current size of the buffer is written to the start of the
|
||||
// buffer. The returned value is not copied from the internal buffer, so it can
|
||||
// be mutated by the EventMetadata object after it is returned.
|
||||
func (em *EventMetadata) Bytes() []byte {
|
||||
// Finalize the event metadata buffer by filling in the buffer length at the
|
||||
// beginning.
|
||||
binary.LittleEndian.PutUint16(em.buffer.Bytes(), uint16(em.buffer.Len()))
|
||||
return em.buffer.Bytes()
|
||||
}
|
||||
|
||||
// WriteEventHeader writes the metadata for the start of an event to the buffer.
|
||||
// This specifies the event name and tags.
|
||||
func (em *EventMetadata) WriteEventHeader(name string, tags uint32) {
|
||||
binary.Write(&em.buffer, binary.LittleEndian, uint16(0)) // Length placeholder
|
||||
em.writeTags(tags)
|
||||
em.buffer.WriteString(name)
|
||||
em.buffer.WriteByte(0) // Null terminator for name
|
||||
}
|
||||
|
||||
func (em *EventMetadata) writeField(name string, inType InType, outType OutType, tags uint32, arrSize uint16) {
|
||||
em.buffer.WriteString(name)
|
||||
em.buffer.WriteByte(0) // Null terminator for name
|
||||
|
||||
if outType == OutTypeDefault && tags == 0 {
|
||||
em.buffer.WriteByte(byte(inType))
|
||||
} else {
|
||||
em.buffer.WriteByte(byte(inType | 128))
|
||||
if tags == 0 {
|
||||
em.buffer.WriteByte(byte(outType))
|
||||
} else {
|
||||
em.buffer.WriteByte(byte(outType | 128))
|
||||
em.writeTags(tags)
|
||||
}
|
||||
}
|
||||
|
||||
if arrSize != 0 {
|
||||
binary.Write(&em.buffer, binary.LittleEndian, arrSize)
|
||||
}
|
||||
}
|
||||
|
||||
// writeTags writes out the tags value to the event metadata. Tags is a 28-bit
|
||||
// value, interpreted as bit flags, which are only relevant to the event
|
||||
// consumer. The event consumer may choose to attribute special meaning to tags
|
||||
// (e.g. 0x4 could mean the field contains PII). Tags are written as a series of
|
||||
// bytes, each containing 7 bits of tag value, with the high bit set if there is
|
||||
// more tag data in the following byte. This allows for a more compact
|
||||
// representation when not all of the tag bits are needed.
|
||||
func (em *EventMetadata) writeTags(tags uint32) {
|
||||
// Only use the top 28 bits of the tags value.
|
||||
tags &= 0xfffffff
|
||||
|
||||
for {
|
||||
// Tags are written with the most significant bits (e.g. 21-27) first.
|
||||
val := tags >> 21
|
||||
|
||||
if tags&0x1fffff == 0 {
|
||||
// If there is no more data to write after this, write this value
|
||||
// without the high bit set, and return.
|
||||
em.buffer.WriteByte(byte(val & 0x7f))
|
||||
return
|
||||
}
|
||||
|
||||
em.buffer.WriteByte(byte(val | 0x80))
|
||||
|
||||
tags <<= 7
|
||||
}
|
||||
}
|
||||
|
||||
// WriteField writes the metadata for a simple field to the buffer.
|
||||
func (em *EventMetadata) WriteField(name string, inType InType, outType OutType, tags uint32) {
|
||||
em.writeField(name, inType, outType, tags, 0)
|
||||
}
|
||||
|
||||
// WriteArray writes the metadata for an array field to the buffer. The number
|
||||
// of elements in the array must be written as a uint16 in the event data,
|
||||
// immediately preceeding the event data.
|
||||
func (em *EventMetadata) WriteArray(name string, inType InType, outType OutType, tags uint32) {
|
||||
em.writeField(name, inType|InTypeArray, outType, tags, 0)
|
||||
}
|
||||
|
||||
// WriteCountedArray writes the metadata for an array field to the buffer. The
|
||||
// size of a counted array is fixed, and the size is written into the metadata
|
||||
// directly.
|
||||
func (em *EventMetadata) WriteCountedArray(name string, count uint16, inType InType, outType OutType, tags uint32) {
|
||||
em.writeField(name, inType|InTypeCountedArray, outType, tags, count)
|
||||
}
|
||||
|
||||
// WriteStruct writes the metadata for a nested struct to the buffer. The struct
|
||||
// contains the next N fields in the metadata, where N is specified by the
|
||||
// fieldCount argument.
|
||||
func (em *EventMetadata) WriteStruct(name string, fieldCount uint8, tags uint32) {
|
||||
em.writeField(name, InTypeStruct, OutType(fieldCount), tags, 0)
|
||||
}
|
63
vendor/github.com/Microsoft/go-winio/internal/etw/eventopt.go
generated
vendored
Normal file
63
vendor/github.com/Microsoft/go-winio/internal/etw/eventopt.go
generated
vendored
Normal file
|
@ -0,0 +1,63 @@
|
|||
package etw
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
type eventOptions struct {
|
||||
descriptor *EventDescriptor
|
||||
activityID *windows.GUID
|
||||
relatedActivityID *windows.GUID
|
||||
tags uint32
|
||||
}
|
||||
|
||||
// EventOpt defines the option function type that can be passed to
|
||||
// Provider.WriteEvent to specify general event options, such as level and
|
||||
// keyword.
|
||||
type EventOpt func(options *eventOptions)
|
||||
|
||||
// WithEventOpts returns the variadic arguments as a single slice.
|
||||
func WithEventOpts(opts ...EventOpt) []EventOpt {
|
||||
return opts
|
||||
}
|
||||
|
||||
// WithLevel specifies the level of the event to be written.
|
||||
func WithLevel(level Level) EventOpt {
|
||||
return func(options *eventOptions) {
|
||||
options.descriptor.Level = level
|
||||
}
|
||||
}
|
||||
|
||||
// WithKeyword specifies the keywords of the event to be written. Multiple uses
|
||||
// of this option are OR'd together.
|
||||
func WithKeyword(keyword uint64) EventOpt {
|
||||
return func(options *eventOptions) {
|
||||
options.descriptor.Keyword |= keyword
|
||||
}
|
||||
}
|
||||
|
||||
func WithChannel(channel Channel) EventOpt {
|
||||
return func(options *eventOptions) {
|
||||
options.descriptor.Channel = channel
|
||||
}
|
||||
}
|
||||
|
||||
// WithTags specifies the tags of the event to be written. Tags is a 28-bit
|
||||
// value (top 4 bits are ignored) which are interpreted by the event consumer.
|
||||
func WithTags(newTags uint32) EventOpt {
|
||||
return func(options *eventOptions) {
|
||||
options.tags |= newTags
|
||||
}
|
||||
}
|
||||
|
||||
func WithActivityID(activityID *windows.GUID) EventOpt {
|
||||
return func(options *eventOptions) {
|
||||
options.activityID = activityID
|
||||
}
|
||||
}
|
||||
|
||||
func WithRelatedActivityID(activityID *windows.GUID) EventOpt {
|
||||
return func(options *eventOptions) {
|
||||
options.relatedActivityID = activityID
|
||||
}
|
||||
}
|
379
vendor/github.com/Microsoft/go-winio/internal/etw/fieldopt.go
generated
vendored
Normal file
379
vendor/github.com/Microsoft/go-winio/internal/etw/fieldopt.go
generated
vendored
Normal file
|
@ -0,0 +1,379 @@
|
|||
package etw
|
||||
|
||||
import (
|
||||
"math"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// FieldOpt defines the option function type that can be passed to
|
||||
// Provider.WriteEvent to add fields to the event.
|
||||
type FieldOpt func(em *EventMetadata, ed *EventData)
|
||||
|
||||
// WithFields returns the variadic arguments as a single slice.
|
||||
func WithFields(opts ...FieldOpt) []FieldOpt {
|
||||
return opts
|
||||
}
|
||||
|
||||
// BoolField adds a single bool field to the event.
|
||||
func BoolField(name string, value bool) FieldOpt {
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteField(name, InTypeUint8, OutTypeBoolean, 0)
|
||||
bool8 := uint8(0)
|
||||
if value {
|
||||
bool8 = uint8(1)
|
||||
}
|
||||
ed.WriteUint8(bool8)
|
||||
}
|
||||
}
|
||||
|
||||
// BoolArray adds an array of bool to the event.
|
||||
func BoolArray(name string, values []bool) FieldOpt {
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteArray(name, InTypeUint8, OutTypeBoolean, 0)
|
||||
ed.WriteUint16(uint16(len(values)))
|
||||
for _, v := range values {
|
||||
bool8 := uint8(0)
|
||||
if v {
|
||||
bool8 = uint8(1)
|
||||
}
|
||||
ed.WriteUint8(bool8)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// StringField adds a single string field to the event.
|
||||
func StringField(name string, value string) FieldOpt {
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteField(name, InTypeANSIString, OutTypeUTF8, 0)
|
||||
ed.WriteString(value)
|
||||
}
|
||||
}
|
||||
|
||||
// StringArray adds an array of string to the event.
|
||||
func StringArray(name string, values []string) FieldOpt {
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteArray(name, InTypeANSIString, OutTypeUTF8, 0)
|
||||
ed.WriteUint16(uint16(len(values)))
|
||||
for _, v := range values {
|
||||
ed.WriteString(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IntField adds a single int field to the event.
|
||||
func IntField(name string, value int) FieldOpt {
|
||||
switch unsafe.Sizeof(value) {
|
||||
case 4:
|
||||
return Int32Field(name, int32(value))
|
||||
case 8:
|
||||
return Int64Field(name, int64(value))
|
||||
default:
|
||||
panic("Unsupported int size")
|
||||
}
|
||||
}
|
||||
|
||||
// IntArray adds an array of int to the event.
|
||||
func IntArray(name string, values []int) FieldOpt {
|
||||
inType := InTypeNull
|
||||
var writeItem func(*EventData, int)
|
||||
switch unsafe.Sizeof(values[0]) {
|
||||
case 4:
|
||||
inType = InTypeInt32
|
||||
writeItem = func(ed *EventData, item int) { ed.WriteInt32(int32(item)) }
|
||||
case 8:
|
||||
inType = InTypeInt64
|
||||
writeItem = func(ed *EventData, item int) { ed.WriteInt64(int64(item)) }
|
||||
default:
|
||||
panic("Unsupported int size")
|
||||
}
|
||||
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteArray(name, inType, OutTypeDefault, 0)
|
||||
ed.WriteUint16(uint16(len(values)))
|
||||
for _, v := range values {
|
||||
writeItem(ed, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Int8Field adds a single int8 field to the event.
|
||||
func Int8Field(name string, value int8) FieldOpt {
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteField(name, InTypeInt8, OutTypeDefault, 0)
|
||||
ed.WriteInt8(value)
|
||||
}
|
||||
}
|
||||
|
||||
// Int8Array adds an array of int8 to the event.
|
||||
func Int8Array(name string, values []int8) FieldOpt {
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteArray(name, InTypeInt8, OutTypeDefault, 0)
|
||||
ed.WriteUint16(uint16(len(values)))
|
||||
for _, v := range values {
|
||||
ed.WriteInt8(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Int16Field adds a single int16 field to the event.
|
||||
func Int16Field(name string, value int16) FieldOpt {
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteField(name, InTypeInt16, OutTypeDefault, 0)
|
||||
ed.WriteInt16(value)
|
||||
}
|
||||
}
|
||||
|
||||
// Int16Array adds an array of int16 to the event.
|
||||
func Int16Array(name string, values []int16) FieldOpt {
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteArray(name, InTypeInt16, OutTypeDefault, 0)
|
||||
ed.WriteUint16(uint16(len(values)))
|
||||
for _, v := range values {
|
||||
ed.WriteInt16(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Int32Field adds a single int32 field to the event.
|
||||
func Int32Field(name string, value int32) FieldOpt {
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteField(name, InTypeInt32, OutTypeDefault, 0)
|
||||
ed.WriteInt32(value)
|
||||
}
|
||||
}
|
||||
|
||||
// Int32Array adds an array of int32 to the event.
|
||||
func Int32Array(name string, values []int32) FieldOpt {
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteArray(name, InTypeInt32, OutTypeDefault, 0)
|
||||
ed.WriteUint16(uint16(len(values)))
|
||||
for _, v := range values {
|
||||
ed.WriteInt32(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Int64Field adds a single int64 field to the event.
|
||||
func Int64Field(name string, value int64) FieldOpt {
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteField(name, InTypeInt64, OutTypeDefault, 0)
|
||||
ed.WriteInt64(value)
|
||||
}
|
||||
}
|
||||
|
||||
// Int64Array adds an array of int64 to the event.
|
||||
func Int64Array(name string, values []int64) FieldOpt {
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteArray(name, InTypeInt64, OutTypeDefault, 0)
|
||||
ed.WriteUint16(uint16(len(values)))
|
||||
for _, v := range values {
|
||||
ed.WriteInt64(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// UintField adds a single uint field to the event.
|
||||
func UintField(name string, value uint) FieldOpt {
|
||||
switch unsafe.Sizeof(value) {
|
||||
case 4:
|
||||
return Uint32Field(name, uint32(value))
|
||||
case 8:
|
||||
return Uint64Field(name, uint64(value))
|
||||
default:
|
||||
panic("Unsupported uint size")
|
||||
}
|
||||
}
|
||||
|
||||
// UintArray adds an array of uint to the event.
|
||||
func UintArray(name string, values []uint) FieldOpt {
|
||||
inType := InTypeNull
|
||||
var writeItem func(*EventData, uint)
|
||||
switch unsafe.Sizeof(values[0]) {
|
||||
case 4:
|
||||
inType = InTypeUint32
|
||||
writeItem = func(ed *EventData, item uint) { ed.WriteUint32(uint32(item)) }
|
||||
case 8:
|
||||
inType = InTypeUint64
|
||||
writeItem = func(ed *EventData, item uint) { ed.WriteUint64(uint64(item)) }
|
||||
default:
|
||||
panic("Unsupported uint size")
|
||||
}
|
||||
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteArray(name, inType, OutTypeDefault, 0)
|
||||
ed.WriteUint16(uint16(len(values)))
|
||||
for _, v := range values {
|
||||
writeItem(ed, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Uint8Field adds a single uint8 field to the event.
|
||||
func Uint8Field(name string, value uint8) FieldOpt {
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteField(name, InTypeUint8, OutTypeDefault, 0)
|
||||
ed.WriteUint8(value)
|
||||
}
|
||||
}
|
||||
|
||||
// Uint8Array adds an array of uint8 to the event.
|
||||
func Uint8Array(name string, values []uint8) FieldOpt {
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteArray(name, InTypeUint8, OutTypeDefault, 0)
|
||||
ed.WriteUint16(uint16(len(values)))
|
||||
for _, v := range values {
|
||||
ed.WriteUint8(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Uint16Field adds a single uint16 field to the event.
|
||||
func Uint16Field(name string, value uint16) FieldOpt {
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteField(name, InTypeUint16, OutTypeDefault, 0)
|
||||
ed.WriteUint16(value)
|
||||
}
|
||||
}
|
||||
|
||||
// Uint16Array adds an array of uint16 to the event.
|
||||
func Uint16Array(name string, values []uint16) FieldOpt {
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteArray(name, InTypeUint16, OutTypeDefault, 0)
|
||||
ed.WriteUint16(uint16(len(values)))
|
||||
for _, v := range values {
|
||||
ed.WriteUint16(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Uint32Field adds a single uint32 field to the event.
|
||||
func Uint32Field(name string, value uint32) FieldOpt {
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteField(name, InTypeUint32, OutTypeDefault, 0)
|
||||
ed.WriteUint32(value)
|
||||
}
|
||||
}
|
||||
|
||||
// Uint32Array adds an array of uint32 to the event.
|
||||
func Uint32Array(name string, values []uint32) FieldOpt {
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteArray(name, InTypeUint32, OutTypeDefault, 0)
|
||||
ed.WriteUint16(uint16(len(values)))
|
||||
for _, v := range values {
|
||||
ed.WriteUint32(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Uint64Field adds a single uint64 field to the event.
|
||||
func Uint64Field(name string, value uint64) FieldOpt {
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteField(name, InTypeUint64, OutTypeDefault, 0)
|
||||
ed.WriteUint64(value)
|
||||
}
|
||||
}
|
||||
|
||||
// Uint64Array adds an array of uint64 to the event.
|
||||
func Uint64Array(name string, values []uint64) FieldOpt {
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteArray(name, InTypeUint64, OutTypeDefault, 0)
|
||||
ed.WriteUint16(uint16(len(values)))
|
||||
for _, v := range values {
|
||||
ed.WriteUint64(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// UintptrField adds a single uintptr field to the event.
|
||||
func UintptrField(name string, value uintptr) FieldOpt {
|
||||
inType := InTypeNull
|
||||
var writeItem func(*EventData, uintptr)
|
||||
switch unsafe.Sizeof(value) {
|
||||
case 4:
|
||||
inType = InTypeHexInt32
|
||||
writeItem = func(ed *EventData, item uintptr) { ed.WriteUint32(uint32(item)) }
|
||||
case 8:
|
||||
inType = InTypeHexInt64
|
||||
writeItem = func(ed *EventData, item uintptr) { ed.WriteUint64(uint64(item)) }
|
||||
default:
|
||||
panic("Unsupported uintptr size")
|
||||
}
|
||||
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteField(name, inType, OutTypeDefault, 0)
|
||||
writeItem(ed, value)
|
||||
}
|
||||
}
|
||||
|
||||
// UintptrArray adds an array of uintptr to the event.
|
||||
func UintptrArray(name string, values []uintptr) FieldOpt {
|
||||
inType := InTypeNull
|
||||
var writeItem func(*EventData, uintptr)
|
||||
switch unsafe.Sizeof(values[0]) {
|
||||
case 4:
|
||||
inType = InTypeHexInt32
|
||||
writeItem = func(ed *EventData, item uintptr) { ed.WriteUint32(uint32(item)) }
|
||||
case 8:
|
||||
inType = InTypeHexInt64
|
||||
writeItem = func(ed *EventData, item uintptr) { ed.WriteUint64(uint64(item)) }
|
||||
default:
|
||||
panic("Unsupported uintptr size")
|
||||
}
|
||||
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteArray(name, inType, OutTypeDefault, 0)
|
||||
ed.WriteUint16(uint16(len(values)))
|
||||
for _, v := range values {
|
||||
writeItem(ed, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Float32Field adds a single float32 field to the event.
|
||||
func Float32Field(name string, value float32) FieldOpt {
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteField(name, InTypeFloat, OutTypeDefault, 0)
|
||||
ed.WriteUint32(math.Float32bits(value))
|
||||
}
|
||||
}
|
||||
|
||||
// Float32Array adds an array of float32 to the event.
|
||||
func Float32Array(name string, values []float32) FieldOpt {
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteArray(name, InTypeFloat, OutTypeDefault, 0)
|
||||
ed.WriteUint16(uint16(len(values)))
|
||||
for _, v := range values {
|
||||
ed.WriteUint32(math.Float32bits(v))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Float64Field adds a single float64 field to the event.
|
||||
func Float64Field(name string, value float64) FieldOpt {
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteField(name, InTypeDouble, OutTypeDefault, 0)
|
||||
ed.WriteUint64(math.Float64bits(value))
|
||||
}
|
||||
}
|
||||
|
||||
// Float64Array adds an array of float64 to the event.
|
||||
func Float64Array(name string, values []float64) FieldOpt {
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteArray(name, InTypeDouble, OutTypeDefault, 0)
|
||||
ed.WriteUint16(uint16(len(values)))
|
||||
for _, v := range values {
|
||||
ed.WriteUint64(math.Float64bits(v))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Struct adds a nested struct to the event, the FieldOpts in the opts argument
|
||||
// are used to specify the fields of the struct.
|
||||
func Struct(name string, opts ...FieldOpt) FieldOpt {
|
||||
return func(em *EventMetadata, ed *EventData) {
|
||||
em.WriteStruct(name, uint8(len(opts)), 0)
|
||||
for _, opt := range opts {
|
||||
opt(em, ed)
|
||||
}
|
||||
}
|
||||
}
|
279
vendor/github.com/Microsoft/go-winio/internal/etw/provider.go
generated
vendored
Normal file
279
vendor/github.com/Microsoft/go-winio/internal/etw/provider.go
generated
vendored
Normal file
|
@ -0,0 +1,279 @@
|
|||
package etw
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode/utf16"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// Provider represents an ETW event provider. It is identified by a provider
|
||||
// name and ID (GUID), which should always have a 1:1 mapping to each other
|
||||
// (e.g. don't use multiple provider names with the same ID, or vice versa).
|
||||
type Provider struct {
|
||||
ID *windows.GUID
|
||||
handle providerHandle
|
||||
metadata []byte
|
||||
callback EnableCallback
|
||||
index uint
|
||||
enabled bool
|
||||
level Level
|
||||
keywordAny uint64
|
||||
keywordAll uint64
|
||||
}
|
||||
|
||||
// String returns the `provider`.ID as a string
|
||||
func (provider *Provider) String() string {
|
||||
data1 := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(data1, provider.ID.Data1)
|
||||
data2 := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(data2, provider.ID.Data2)
|
||||
data3 := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(data3, provider.ID.Data3)
|
||||
return fmt.Sprintf(
|
||||
"%s-%s-%s-%s-%s",
|
||||
hex.EncodeToString(data1),
|
||||
hex.EncodeToString(data2),
|
||||
hex.EncodeToString(data3),
|
||||
hex.EncodeToString(provider.ID.Data4[:2]),
|
||||
hex.EncodeToString(provider.ID.Data4[2:]))
|
||||
}
|
||||
|
||||
type providerHandle windows.Handle
|
||||
|
||||
// ProviderState informs the provider EnableCallback what action is being
|
||||
// performed.
|
||||
type ProviderState uint32
|
||||
|
||||
const (
|
||||
// ProviderStateDisable indicates the provider is being disabled.
|
||||
ProviderStateDisable ProviderState = iota
|
||||
// ProviderStateEnable indicates the provider is being enabled.
|
||||
ProviderStateEnable
|
||||
// ProviderStateCaptureState indicates the provider is having its current
|
||||
// state snap-shotted.
|
||||
ProviderStateCaptureState
|
||||
)
|
||||
|
||||
type eventInfoClass uint32
|
||||
|
||||
const (
|
||||
eventInfoClassProviderBinaryTrackInfo eventInfoClass = iota
|
||||
eventInfoClassProviderSetReserved1
|
||||
eventInfoClassProviderSetTraits
|
||||
eventInfoClassProviderUseDescriptorType
|
||||
)
|
||||
|
||||
// EnableCallback is the form of the callback function that receives provider
|
||||
// enable/disable notifications from ETW.
|
||||
type EnableCallback func(*windows.GUID, ProviderState, Level, uint64, uint64, uintptr)
|
||||
|
||||
func providerCallback(sourceID *windows.GUID, state ProviderState, level Level, matchAnyKeyword uint64, matchAllKeyword uint64, filterData uintptr, i uintptr) {
|
||||
provider := providers.getProvider(uint(i))
|
||||
|
||||
switch state {
|
||||
case ProviderStateDisable:
|
||||
provider.enabled = false
|
||||
case ProviderStateEnable:
|
||||
provider.enabled = true
|
||||
provider.level = level
|
||||
provider.keywordAny = matchAnyKeyword
|
||||
provider.keywordAll = matchAllKeyword
|
||||
}
|
||||
|
||||
if provider.callback != nil {
|
||||
provider.callback(sourceID, state, level, matchAnyKeyword, matchAllKeyword, filterData)
|
||||
}
|
||||
}
|
||||
|
||||
// providerCallbackAdapter acts as the first-level callback from the C/ETW side
|
||||
// for provider notifications. Because Go has trouble with callback arguments of
|
||||
// different size, it has only pointer-sized arguments, which are then cast to
|
||||
// the appropriate types when calling providerCallback.
|
||||
func providerCallbackAdapter(sourceID *windows.GUID, state uintptr, level uintptr, matchAnyKeyword uintptr, matchAllKeyword uintptr, filterData uintptr, i uintptr) uintptr {
|
||||
providerCallback(sourceID, ProviderState(state), Level(level), uint64(matchAnyKeyword), uint64(matchAllKeyword), filterData, i)
|
||||
return 0
|
||||
}
|
||||
|
||||
// providerIDFromName generates a provider ID based on the provider name. It
|
||||
// uses the same algorithm as used by .NET's EventSource class, which is based
|
||||
// on RFC 4122. More information on the algorithm can be found here:
|
||||
// https://blogs.msdn.microsoft.com/dcook/2015/09/08/etw-provider-names-and-guids/
|
||||
// The algorithm is roughly:
|
||||
// Hash = Sha1(namespace + arg.ToUpper().ToUtf16be())
|
||||
// Guid = Hash[0..15], with Hash[7] tweaked according to RFC 4122
|
||||
func providerIDFromName(name string) *windows.GUID {
|
||||
buffer := sha1.New()
|
||||
|
||||
namespace := []byte{0x48, 0x2C, 0x2D, 0xB2, 0xC3, 0x90, 0x47, 0xC8, 0x87, 0xF8, 0x1A, 0x15, 0xBF, 0xC1, 0x30, 0xFB}
|
||||
buffer.Write(namespace)
|
||||
|
||||
binary.Write(buffer, binary.BigEndian, utf16.Encode([]rune(strings.ToUpper(name))))
|
||||
|
||||
sum := buffer.Sum(nil)
|
||||
sum[7] = (sum[7] & 0xf) | 0x50
|
||||
|
||||
return &windows.GUID{
|
||||
Data1: binary.LittleEndian.Uint32(sum[0:4]),
|
||||
Data2: binary.LittleEndian.Uint16(sum[4:6]),
|
||||
Data3: binary.LittleEndian.Uint16(sum[6:8]),
|
||||
Data4: [8]byte{sum[8], sum[9], sum[10], sum[11], sum[12], sum[13], sum[14], sum[15]},
|
||||
}
|
||||
}
|
||||
|
||||
// NewProvider creates and registers a new ETW provider. The provider ID is
|
||||
// generated based on the provider name.
|
||||
func NewProvider(name string, callback EnableCallback) (provider *Provider, err error) {
|
||||
return NewProviderWithID(name, providerIDFromName(name), callback)
|
||||
}
|
||||
|
||||
// NewProviderWithID creates and registers a new ETW provider, allowing the
|
||||
// provider ID to be manually specified. This is most useful when there is an
|
||||
// existing provider ID that must be used to conform to existing diagnostic
|
||||
// infrastructure.
|
||||
func NewProviderWithID(name string, id *windows.GUID, callback EnableCallback) (provider *Provider, err error) {
|
||||
providerCallbackOnce.Do(func() {
|
||||
globalProviderCallback = windows.NewCallback(providerCallbackAdapter)
|
||||
})
|
||||
|
||||
provider = providers.newProvider()
|
||||
defer func() {
|
||||
if err != nil {
|
||||
providers.removeProvider(provider)
|
||||
}
|
||||
}()
|
||||
provider.ID = id
|
||||
provider.callback = callback
|
||||
|
||||
if err := eventRegister(provider.ID, globalProviderCallback, uintptr(provider.index), &provider.handle); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
metadata := &bytes.Buffer{}
|
||||
binary.Write(metadata, binary.LittleEndian, uint16(0)) // Write empty size for buffer (to update later)
|
||||
metadata.WriteString(name)
|
||||
metadata.WriteByte(0) // Null terminator for name
|
||||
binary.LittleEndian.PutUint16(metadata.Bytes(), uint16(metadata.Len())) // Update the size at the beginning of the buffer
|
||||
provider.metadata = metadata.Bytes()
|
||||
|
||||
if err := eventSetInformation(
|
||||
provider.handle,
|
||||
eventInfoClassProviderSetTraits,
|
||||
uintptr(unsafe.Pointer(&provider.metadata[0])),
|
||||
uint32(len(provider.metadata))); err != nil {
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return provider, nil
|
||||
}
|
||||
|
||||
// Close unregisters the provider.
|
||||
func (provider *Provider) Close() error {
|
||||
providers.removeProvider(provider)
|
||||
return eventUnregister(provider.handle)
|
||||
}
|
||||
|
||||
// IsEnabled calls IsEnabledForLevelAndKeywords with LevelAlways and all
|
||||
// keywords set.
|
||||
func (provider *Provider) IsEnabled() bool {
|
||||
return provider.IsEnabledForLevelAndKeywords(LevelAlways, ^uint64(0))
|
||||
}
|
||||
|
||||
// IsEnabledForLevel calls IsEnabledForLevelAndKeywords with the specified level
|
||||
// and all keywords set.
|
||||
func (provider *Provider) IsEnabledForLevel(level Level) bool {
|
||||
return provider.IsEnabledForLevelAndKeywords(level, ^uint64(0))
|
||||
}
|
||||
|
||||
// IsEnabledForLevelAndKeywords allows event producer code to check if there are
|
||||
// any event sessions that are interested in an event, based on the event level
|
||||
// and keywords. Although this check happens automatically in the ETW
|
||||
// infrastructure, it can be useful to check if an event will actually be
|
||||
// consumed before doing expensive work to build the event data.
|
||||
func (provider *Provider) IsEnabledForLevelAndKeywords(level Level, keywords uint64) bool {
|
||||
if !provider.enabled {
|
||||
return false
|
||||
}
|
||||
|
||||
// ETW automatically sets the level to 255 if it is specified as 0, so we
|
||||
// don't need to worry about the level=0 (all events) case.
|
||||
if level > provider.level {
|
||||
return false
|
||||
}
|
||||
|
||||
if keywords != 0 && (keywords&provider.keywordAny == 0 || keywords&provider.keywordAll != provider.keywordAll) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// WriteEvent writes a single ETW event from the provider. The event is
|
||||
// constructed based on the EventOpt and FieldOpt values that are passed as
|
||||
// opts.
|
||||
func (provider *Provider) WriteEvent(name string, eventOpts []EventOpt, fieldOpts []FieldOpt) error {
|
||||
options := eventOptions{descriptor: NewEventDescriptor()}
|
||||
em := &EventMetadata{}
|
||||
ed := &EventData{}
|
||||
|
||||
// We need to evaluate the EventOpts first since they might change tags, and
|
||||
// we write out the tags before evaluating FieldOpts.
|
||||
for _, opt := range eventOpts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
if !provider.IsEnabledForLevelAndKeywords(options.descriptor.Level, options.descriptor.Keyword) {
|
||||
return nil
|
||||
}
|
||||
|
||||
em.WriteEventHeader(name, options.tags)
|
||||
|
||||
for _, opt := range fieldOpts {
|
||||
opt(em, ed)
|
||||
}
|
||||
|
||||
// Don't pass a data blob if there is no event data. There will always be
|
||||
// event metadata (e.g. for the name) so we don't need to do this check for
|
||||
// the metadata.
|
||||
dataBlobs := [][]byte{}
|
||||
if len(ed.Bytes()) > 0 {
|
||||
dataBlobs = [][]byte{ed.Bytes()}
|
||||
}
|
||||
|
||||
return provider.WriteEventRaw(options.descriptor, nil, nil, [][]byte{em.Bytes()}, dataBlobs)
|
||||
}
|
||||
|
||||
// WriteEventRaw writes a single ETW event from the provider. This function is
|
||||
// less abstracted than WriteEvent, and presents a fairly direct interface to
|
||||
// the event writing functionality. It expects a series of event metadata and
|
||||
// event data blobs to be passed in, which must conform to the TraceLogging
|
||||
// schema. The functions on EventMetadata and EventData can help with creating
|
||||
// these blobs. The blobs of each type are effectively concatenated together by
|
||||
// the ETW infrastructure.
|
||||
func (provider *Provider) WriteEventRaw(
|
||||
descriptor *EventDescriptor,
|
||||
activityID *windows.GUID,
|
||||
relatedActivityID *windows.GUID,
|
||||
metadataBlobs [][]byte,
|
||||
dataBlobs [][]byte) error {
|
||||
|
||||
dataDescriptorCount := uint32(1 + len(metadataBlobs) + len(dataBlobs))
|
||||
dataDescriptors := make([]eventDataDescriptor, 0, dataDescriptorCount)
|
||||
|
||||
dataDescriptors = append(dataDescriptors, newEventDataDescriptor(eventDataDescriptorTypeProviderMetadata, provider.metadata))
|
||||
for _, blob := range metadataBlobs {
|
||||
dataDescriptors = append(dataDescriptors, newEventDataDescriptor(eventDataDescriptorTypeEventMetadata, blob))
|
||||
}
|
||||
for _, blob := range dataBlobs {
|
||||
dataDescriptors = append(dataDescriptors, newEventDataDescriptor(eventDataDescriptorTypeUserData, blob))
|
||||
}
|
||||
|
||||
return eventWriteTransfer(provider.handle, descriptor, activityID, relatedActivityID, dataDescriptorCount, &dataDescriptors[0])
|
||||
}
|
52
vendor/github.com/Microsoft/go-winio/internal/etw/providerglobal.go
generated
vendored
Normal file
52
vendor/github.com/Microsoft/go-winio/internal/etw/providerglobal.go
generated
vendored
Normal file
|
@ -0,0 +1,52 @@
|
|||
package etw
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Because the provider callback function needs to be able to access the
|
||||
// provider data when it is invoked by ETW, we need to keep provider data stored
|
||||
// in a global map based on an index. The index is passed as the callback
|
||||
// context to ETW.
|
||||
type providerMap struct {
|
||||
m map[uint]*Provider
|
||||
i uint
|
||||
lock sync.Mutex
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
var providers = providerMap{
|
||||
m: make(map[uint]*Provider),
|
||||
}
|
||||
|
||||
func (p *providerMap) newProvider() *Provider {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
i := p.i
|
||||
p.i++
|
||||
|
||||
provider := &Provider{
|
||||
index: i,
|
||||
}
|
||||
|
||||
p.m[i] = provider
|
||||
return provider
|
||||
}
|
||||
|
||||
func (p *providerMap) removeProvider(provider *Provider) {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
delete(p.m, provider.index)
|
||||
}
|
||||
|
||||
func (p *providerMap) getProvider(index uint) *Provider {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
return p.m[index]
|
||||
}
|
||||
|
||||
var providerCallbackOnce sync.Once
|
||||
var globalProviderCallback uintptr
|
16
vendor/github.com/Microsoft/go-winio/internal/etw/ptr64_32.go
generated
vendored
Normal file
16
vendor/github.com/Microsoft/go-winio/internal/etw/ptr64_32.go
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
// +build 386 arm
|
||||
|
||||
package etw
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// byteptr64 defines a struct containing a pointer. The struct is guaranteed to
|
||||
// be 64 bits, regardless of the actual size of a pointer on the platform. This
|
||||
// is intended for use with certain Windows APIs that expect a pointer as a
|
||||
// ULONGLONG.
|
||||
type ptr64 struct {
|
||||
ptr unsafe.Pointer
|
||||
_ uint32
|
||||
}
|
15
vendor/github.com/Microsoft/go-winio/internal/etw/ptr64_64.go
generated
vendored
Normal file
15
vendor/github.com/Microsoft/go-winio/internal/etw/ptr64_64.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
// +build amd64 arm64
|
||||
|
||||
package etw
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// byteptr64 defines a struct containing a pointer. The struct is guaranteed to
|
||||
// be 64 bits, regardless of the actual size of a pointer on the platform. This
|
||||
// is intended for use with certain Windows APIs that expect a pointer as a
|
||||
// ULONGLONG.
|
||||
type ptr64 struct {
|
||||
ptr unsafe.Pointer
|
||||
}
|
78
vendor/github.com/Microsoft/go-winio/internal/etw/zsyscall_windows.go
generated
vendored
Normal file
78
vendor/github.com/Microsoft/go-winio/internal/etw/zsyscall_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,78 @@
|
|||
// Code generated by 'go generate'; DO NOT EDIT.
|
||||
|
||||
package etw
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var _ unsafe.Pointer
|
||||
|
||||
// Do the interface allocations only once for common
|
||||
// Errno values.
|
||||
const (
|
||||
errnoERROR_IO_PENDING = 997
|
||||
)
|
||||
|
||||
var (
|
||||
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||
)
|
||||
|
||||
// errnoErr returns common boxed Errno values, to prevent
|
||||
// allocations at runtime.
|
||||
func errnoErr(e syscall.Errno) error {
|
||||
switch e {
|
||||
case 0:
|
||||
return nil
|
||||
case errnoERROR_IO_PENDING:
|
||||
return errERROR_IO_PENDING
|
||||
}
|
||||
// TODO: add more here, after collecting data on the common
|
||||
// error values see on Windows. (perhaps when running
|
||||
// all.bat?)
|
||||
return e
|
||||
}
|
||||
|
||||
var (
|
||||
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
|
||||
|
||||
procEventRegister = modadvapi32.NewProc("EventRegister")
|
||||
procEventUnregister = modadvapi32.NewProc("EventUnregister")
|
||||
procEventWriteTransfer = modadvapi32.NewProc("EventWriteTransfer")
|
||||
procEventSetInformation = modadvapi32.NewProc("EventSetInformation")
|
||||
)
|
||||
|
||||
func eventRegister(providerId *windows.GUID, callback uintptr, callbackContext uintptr, providerHandle *providerHandle) (win32err error) {
|
||||
r0, _, _ := syscall.Syscall6(procEventRegister.Addr(), 4, uintptr(unsafe.Pointer(providerId)), uintptr(callback), uintptr(callbackContext), uintptr(unsafe.Pointer(providerHandle)), 0, 0)
|
||||
if r0 != 0 {
|
||||
win32err = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func eventUnregister(providerHandle providerHandle) (win32err error) {
|
||||
r0, _, _ := syscall.Syscall(procEventUnregister.Addr(), 1, uintptr(providerHandle), 0, 0)
|
||||
if r0 != 0 {
|
||||
win32err = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func eventWriteTransfer(providerHandle providerHandle, descriptor *EventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) {
|
||||
r0, _, _ := syscall.Syscall6(procEventWriteTransfer.Addr(), 6, uintptr(providerHandle), uintptr(unsafe.Pointer(descriptor)), uintptr(unsafe.Pointer(activityID)), uintptr(unsafe.Pointer(relatedActivityID)), uintptr(dataDescriptorCount), uintptr(unsafe.Pointer(dataDescriptors)))
|
||||
if r0 != 0 {
|
||||
win32err = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func eventSetInformation(providerHandle providerHandle, class eventInfoClass, information uintptr, length uint32) (win32err error) {
|
||||
r0, _, _ := syscall.Syscall6(procEventSetInformation.Addr(), 4, uintptr(providerHandle), uintptr(class), uintptr(information), uintptr(length), 0, 0)
|
||||
if r0 != 0 {
|
||||
win32err = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
192
vendor/github.com/Microsoft/go-winio/pkg/etwlogrus/hook.go
generated
vendored
Normal file
192
vendor/github.com/Microsoft/go-winio/pkg/etwlogrus/hook.go
generated
vendored
Normal file
|
@ -0,0 +1,192 @@
|
|||
package etwlogrus
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/Microsoft/go-winio/internal/etw"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Hook is a Logrus hook which logs received events to ETW.
|
||||
type Hook struct {
|
||||
provider *etw.Provider
|
||||
}
|
||||
|
||||
// NewHook registers a new ETW provider and returns a hook to log from it.
|
||||
func NewHook(providerName string) (*Hook, error) {
|
||||
hook := Hook{}
|
||||
|
||||
provider, err := etw.NewProvider(providerName, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hook.provider = provider
|
||||
|
||||
return &hook, nil
|
||||
}
|
||||
|
||||
// Levels returns the set of levels that this hook wants to receive log entries
|
||||
// for.
|
||||
func (h *Hook) Levels() []logrus.Level {
|
||||
return []logrus.Level{
|
||||
logrus.TraceLevel,
|
||||
logrus.DebugLevel,
|
||||
logrus.InfoLevel,
|
||||
logrus.WarnLevel,
|
||||
logrus.ErrorLevel,
|
||||
logrus.FatalLevel,
|
||||
logrus.PanicLevel,
|
||||
}
|
||||
}
|
||||
|
||||
// Fire receives each Logrus entry as it is logged, and logs it to ETW.
|
||||
func (h *Hook) Fire(e *logrus.Entry) error {
|
||||
level := etw.Level(e.Level)
|
||||
if !h.provider.IsEnabledForLevel(level) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reserve extra space for the message field.
|
||||
fields := make([]etw.FieldOpt, 0, len(e.Data)+1)
|
||||
|
||||
fields = append(fields, etw.StringField("Message", e.Message))
|
||||
|
||||
for k, v := range e.Data {
|
||||
fields = append(fields, getFieldOpt(k, v))
|
||||
}
|
||||
|
||||
// We could try to map Logrus levels to ETW levels, but we would lose some
|
||||
// fidelity as there are fewer ETW levels. So instead we use the level
|
||||
// directly.
|
||||
return h.provider.WriteEvent(
|
||||
"LogrusEntry",
|
||||
etw.WithEventOpts(etw.WithLevel(level)),
|
||||
fields)
|
||||
}
|
||||
|
||||
// Currently, we support logging basic builtin types (int, string, etc), slices
|
||||
// of basic builtin types, error, types derived from the basic types (e.g. "type
|
||||
// foo int"), and structs (recursively logging their fields). We do not support
|
||||
// slices of derived types (e.g. "[]foo").
|
||||
//
|
||||
// For types that we don't support, the value is formatted via fmt.Sprint, and
|
||||
// we also log a message that the type is unsupported along with the formatted
|
||||
// type. The intent of this is to make it easier to see which types are not
|
||||
// supported in traces, so we can evaluate adding support for more types in the
|
||||
// future.
|
||||
func getFieldOpt(k string, v interface{}) etw.FieldOpt {
|
||||
switch v := v.(type) {
|
||||
case bool:
|
||||
return etw.BoolField(k, v)
|
||||
case []bool:
|
||||
return etw.BoolArray(k, v)
|
||||
case string:
|
||||
return etw.StringField(k, v)
|
||||
case []string:
|
||||
return etw.StringArray(k, v)
|
||||
case int:
|
||||
return etw.IntField(k, v)
|
||||
case []int:
|
||||
return etw.IntArray(k, v)
|
||||
case int8:
|
||||
return etw.Int8Field(k, v)
|
||||
case []int8:
|
||||
return etw.Int8Array(k, v)
|
||||
case int16:
|
||||
return etw.Int16Field(k, v)
|
||||
case []int16:
|
||||
return etw.Int16Array(k, v)
|
||||
case int32:
|
||||
return etw.Int32Field(k, v)
|
||||
case []int32:
|
||||
return etw.Int32Array(k, v)
|
||||
case int64:
|
||||
return etw.Int64Field(k, v)
|
||||
case []int64:
|
||||
return etw.Int64Array(k, v)
|
||||
case uint:
|
||||
return etw.UintField(k, v)
|
||||
case []uint:
|
||||
return etw.UintArray(k, v)
|
||||
case uint8:
|
||||
return etw.Uint8Field(k, v)
|
||||
case []uint8:
|
||||
return etw.Uint8Array(k, v)
|
||||
case uint16:
|
||||
return etw.Uint16Field(k, v)
|
||||
case []uint16:
|
||||
return etw.Uint16Array(k, v)
|
||||
case uint32:
|
||||
return etw.Uint32Field(k, v)
|
||||
case []uint32:
|
||||
return etw.Uint32Array(k, v)
|
||||
case uint64:
|
||||
return etw.Uint64Field(k, v)
|
||||
case []uint64:
|
||||
return etw.Uint64Array(k, v)
|
||||
case uintptr:
|
||||
return etw.UintptrField(k, v)
|
||||
case []uintptr:
|
||||
return etw.UintptrArray(k, v)
|
||||
case float32:
|
||||
return etw.Float32Field(k, v)
|
||||
case []float32:
|
||||
return etw.Float32Array(k, v)
|
||||
case float64:
|
||||
return etw.Float64Field(k, v)
|
||||
case []float64:
|
||||
return etw.Float64Array(k, v)
|
||||
case error:
|
||||
return etw.StringField(k, v.Error())
|
||||
default:
|
||||
switch rv := reflect.ValueOf(v); rv.Kind() {
|
||||
case reflect.Bool:
|
||||
return getFieldOpt(k, rv.Bool())
|
||||
case reflect.Int:
|
||||
return getFieldOpt(k, int(rv.Int()))
|
||||
case reflect.Int8:
|
||||
return getFieldOpt(k, int8(rv.Int()))
|
||||
case reflect.Int16:
|
||||
return getFieldOpt(k, int16(rv.Int()))
|
||||
case reflect.Int32:
|
||||
return getFieldOpt(k, int32(rv.Int()))
|
||||
case reflect.Int64:
|
||||
return getFieldOpt(k, int64(rv.Int()))
|
||||
case reflect.Uint:
|
||||
return getFieldOpt(k, uint(rv.Uint()))
|
||||
case reflect.Uint8:
|
||||
return getFieldOpt(k, uint8(rv.Uint()))
|
||||
case reflect.Uint16:
|
||||
return getFieldOpt(k, uint16(rv.Uint()))
|
||||
case reflect.Uint32:
|
||||
return getFieldOpt(k, uint32(rv.Uint()))
|
||||
case reflect.Uint64:
|
||||
return getFieldOpt(k, uint64(rv.Uint()))
|
||||
case reflect.Uintptr:
|
||||
return getFieldOpt(k, uintptr(rv.Uint()))
|
||||
case reflect.Float32:
|
||||
return getFieldOpt(k, float32(rv.Float()))
|
||||
case reflect.Float64:
|
||||
return getFieldOpt(k, float64(rv.Float()))
|
||||
case reflect.String:
|
||||
return getFieldOpt(k, rv.String())
|
||||
case reflect.Struct:
|
||||
fields := make([]etw.FieldOpt, 0, rv.NumField())
|
||||
for i := 0; i < rv.NumField(); i++ {
|
||||
field := rv.Field(i)
|
||||
if field.CanInterface() {
|
||||
fields = append(fields, getFieldOpt(k, field.Interface()))
|
||||
}
|
||||
}
|
||||
return etw.Struct(k, fields...)
|
||||
}
|
||||
}
|
||||
|
||||
return etw.StringField(k, fmt.Sprintf("(Unsupported: %T) %v", v, v))
|
||||
}
|
||||
|
||||
// Close cleans up the hook and closes the ETW provider.
|
||||
func (h *Hook) Close() error {
|
||||
return h.provider.Close()
|
||||
}
|
107
vendor/github.com/Microsoft/go-winio/vhd/vhd.go
generated
vendored
107
vendor/github.com/Microsoft/go-winio/vhd/vhd.go
generated
vendored
|
@ -7,7 +7,7 @@ import "syscall"
|
|||
//go:generate go run mksyscall_windows.go -output zvhd.go vhd.go
|
||||
|
||||
//sys createVirtualDisk(virtualStorageType *virtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, flags uint32, providerSpecificFlags uint32, parameters *createVirtualDiskParameters, o *syscall.Overlapped, handle *syscall.Handle) (err error) [failretval != 0] = VirtDisk.CreateVirtualDisk
|
||||
//sys openVirtualDisk(virtualStorageType *virtualStorageType, path string, virtualDiskAccessMask uint32, flags uint32, parameters *uintptr, handle *syscall.Handle) (err error) [failretval != 0] = VirtDisk.OpenVirtualDisk
|
||||
//sys openVirtualDisk(virtualStorageType *virtualStorageType, path string, virtualDiskAccessMask uint32, flags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (err error) [failretval != 0] = VirtDisk.OpenVirtualDisk
|
||||
//sys detachVirtualDisk(handle syscall.Handle, flags uint32, providerSpecificFlags uint32) (err error) [failretval != 0] = VirtDisk.DetachVirtualDisk
|
||||
|
||||
type virtualStorageType struct {
|
||||
|
@ -15,23 +15,45 @@ type virtualStorageType struct {
|
|||
VendorID [16]byte
|
||||
}
|
||||
|
||||
const virtualDiskAccessNONE uint32 = 0
|
||||
const virtualDiskAccessATTACHRO uint32 = 65536
|
||||
const virtualDiskAccessATTACHRW uint32 = 131072
|
||||
const virtualDiskAccessDETACH uint32 = 262144
|
||||
const virtualDiskAccessGETINFO uint32 = 524288
|
||||
const virtualDiskAccessCREATE uint32 = 1048576
|
||||
const virtualDiskAccessMETAOPS uint32 = 2097152
|
||||
const virtualDiskAccessREAD uint32 = 851968
|
||||
const virtualDiskAccessALL uint32 = 4128768
|
||||
const virtualDiskAccessWRITABLE uint32 = 3276800
|
||||
type (
|
||||
createVirtualDiskFlag uint32
|
||||
VirtualDiskAccessMask uint32
|
||||
VirtualDiskFlag uint32
|
||||
)
|
||||
|
||||
const createVirtualDiskFlagNone uint32 = 0
|
||||
const createVirtualDiskFlagFullPhysicalAllocation uint32 = 1
|
||||
const createVirtualDiskFlagPreventWritesToSourceDisk uint32 = 2
|
||||
const createVirtualDiskFlagDoNotCopyMetadataFromParent uint32 = 4
|
||||
const (
|
||||
// Flags for creating a VHD (not exported)
|
||||
createVirtualDiskFlagNone createVirtualDiskFlag = 0
|
||||
createVirtualDiskFlagFullPhysicalAllocation createVirtualDiskFlag = 1
|
||||
createVirtualDiskFlagPreventWritesToSourceDisk createVirtualDiskFlag = 2
|
||||
createVirtualDiskFlagDoNotCopyMetadataFromParent createVirtualDiskFlag = 4
|
||||
|
||||
type version2 struct {
|
||||
// Access Mask for opening a VHD
|
||||
VirtualDiskAccessNone VirtualDiskAccessMask = 0
|
||||
VirtualDiskAccessAttachRO VirtualDiskAccessMask = 65536
|
||||
VirtualDiskAccessAttachRW VirtualDiskAccessMask = 131072
|
||||
VirtualDiskAccessDetach VirtualDiskAccessMask = 262144
|
||||
VirtualDiskAccessGetInfo VirtualDiskAccessMask = 524288
|
||||
VirtualDiskAccessCreate VirtualDiskAccessMask = 1048576
|
||||
VirtualDiskAccessMetaOps VirtualDiskAccessMask = 2097152
|
||||
VirtualDiskAccessRead VirtualDiskAccessMask = 851968
|
||||
VirtualDiskAccessAll VirtualDiskAccessMask = 4128768
|
||||
VirtualDiskAccessWritable VirtualDiskAccessMask = 3276800
|
||||
|
||||
// Flags for opening a VHD
|
||||
OpenVirtualDiskFlagNone VirtualDiskFlag = 0
|
||||
OpenVirtualDiskFlagNoParents VirtualDiskFlag = 0x1
|
||||
OpenVirtualDiskFlagBlankFile VirtualDiskFlag = 0x2
|
||||
OpenVirtualDiskFlagBootDrive VirtualDiskFlag = 0x4
|
||||
OpenVirtualDiskFlagCachedIO VirtualDiskFlag = 0x8
|
||||
OpenVirtualDiskFlagCustomDiffChain VirtualDiskFlag = 0x10
|
||||
OpenVirtualDiskFlagParentCachedIO VirtualDiskFlag = 0x20
|
||||
OpenVirtualDiskFlagVhdSetFileOnly VirtualDiskFlag = 0x40
|
||||
OpenVirtualDiskFlagIgnoreRelativeParentLocator VirtualDiskFlag = 0x80
|
||||
OpenVirtualDiskFlagNoWriteHardening VirtualDiskFlag = 0x100
|
||||
)
|
||||
|
||||
type createVersion2 struct {
|
||||
UniqueID [16]byte // GUID
|
||||
MaximumSize uint64
|
||||
BlockSizeInBytes uint32
|
||||
|
@ -46,29 +68,41 @@ type version2 struct {
|
|||
|
||||
type createVirtualDiskParameters struct {
|
||||
Version uint32 // Must always be set to 2
|
||||
Version2 version2
|
||||
Version2 createVersion2
|
||||
}
|
||||
|
||||
type openVersion2 struct {
|
||||
GetInfoOnly int32 // bool but 4-byte aligned
|
||||
ReadOnly int32 // bool but 4-byte aligned
|
||||
ResiliencyGUID [16]byte // GUID
|
||||
}
|
||||
|
||||
type openVirtualDiskParameters struct {
|
||||
Version uint32 // Must always be set to 2
|
||||
Version2 openVersion2
|
||||
}
|
||||
|
||||
// CreateVhdx will create a simple vhdx file at the given path using default values.
|
||||
func CreateVhdx(path string, maxSizeInGb, blockSizeInMb uint32) error {
|
||||
var defaultType virtualStorageType
|
||||
var (
|
||||
defaultType virtualStorageType
|
||||
handle syscall.Handle
|
||||
)
|
||||
|
||||
parameters := createVirtualDiskParameters{
|
||||
Version: 2,
|
||||
Version2: version2{
|
||||
Version2: createVersion2{
|
||||
MaximumSize: uint64(maxSizeInGb) * 1024 * 1024 * 1024,
|
||||
BlockSizeInBytes: blockSizeInMb * 1024 * 1024,
|
||||
},
|
||||
}
|
||||
|
||||
var handle syscall.Handle
|
||||
|
||||
if err := createVirtualDisk(
|
||||
&defaultType,
|
||||
path,
|
||||
virtualDiskAccessNONE,
|
||||
uint32(VirtualDiskAccessNone),
|
||||
nil,
|
||||
createVirtualDiskFlagNone,
|
||||
uint32(createVirtualDiskFlagNone),
|
||||
0,
|
||||
¶meters,
|
||||
nil,
|
||||
|
@ -85,24 +119,29 @@ func CreateVhdx(path string, maxSizeInGb, blockSizeInMb uint32) error {
|
|||
|
||||
// DetachVhd detaches a VHD attached at the given path.
|
||||
func DetachVhd(path string) error {
|
||||
handle, err := OpenVirtualDisk(path, VirtualDiskAccessDetach, OpenVirtualDiskFlagNone)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer syscall.CloseHandle(handle)
|
||||
return detachVirtualDisk(handle, 0, 0)
|
||||
}
|
||||
|
||||
// OpenVirtuaDisk obtains a handle to a VHD opened with supplied access mask and flags.
|
||||
func OpenVirtualDisk(path string, accessMask VirtualDiskAccessMask, flag VirtualDiskFlag) (syscall.Handle, error) {
|
||||
var (
|
||||
defaultType virtualStorageType
|
||||
handle syscall.Handle
|
||||
)
|
||||
|
||||
parameters := openVirtualDiskParameters{Version: 2}
|
||||
if err := openVirtualDisk(
|
||||
&defaultType,
|
||||
path,
|
||||
virtualDiskAccessDETACH,
|
||||
0,
|
||||
nil,
|
||||
uint32(accessMask),
|
||||
uint32(flag),
|
||||
¶meters,
|
||||
&handle); err != nil {
|
||||
return err
|
||||
return 0, err
|
||||
}
|
||||
defer syscall.CloseHandle(handle)
|
||||
|
||||
if err := detachVirtualDisk(handle, 0, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return handle, nil
|
||||
}
|
||||
|
|
4
vendor/github.com/Microsoft/go-winio/vhd/zvhd.go
generated
vendored
4
vendor/github.com/Microsoft/go-winio/vhd/zvhd.go
generated
vendored
|
@ -65,7 +65,7 @@ func _createVirtualDisk(virtualStorageType *virtualStorageType, path *uint16, vi
|
|||
return
|
||||
}
|
||||
|
||||
func openVirtualDisk(virtualStorageType *virtualStorageType, path string, virtualDiskAccessMask uint32, flags uint32, parameters *uintptr, handle *syscall.Handle) (err error) {
|
||||
func openVirtualDisk(virtualStorageType *virtualStorageType, path string, virtualDiskAccessMask uint32, flags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (err error) {
|
||||
var _p0 *uint16
|
||||
_p0, err = syscall.UTF16PtrFromString(path)
|
||||
if err != nil {
|
||||
|
@ -74,7 +74,7 @@ func openVirtualDisk(virtualStorageType *virtualStorageType, path string, virtua
|
|||
return _openVirtualDisk(virtualStorageType, _p0, virtualDiskAccessMask, flags, parameters, handle)
|
||||
}
|
||||
|
||||
func _openVirtualDisk(virtualStorageType *virtualStorageType, path *uint16, virtualDiskAccessMask uint32, flags uint32, parameters *uintptr, handle *syscall.Handle) (err error) {
|
||||
func _openVirtualDisk(virtualStorageType *virtualStorageType, path *uint16, virtualDiskAccessMask uint32, flags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procOpenVirtualDisk.Addr(), 6, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(flags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(handle)))
|
||||
if r1 != 0 {
|
||||
if e1 != 0 {
|
||||
|
|
1
vendor/github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options/doc.go
generated
vendored
Normal file
1
vendor/github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options/doc.go
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
package options
|
1033
vendor/github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options/runhcs.pb.go
generated
vendored
Normal file
1033
vendor/github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options/runhcs.pb.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
63
vendor/github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options/runhcs.proto
generated
vendored
Normal file
63
vendor/github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options/runhcs.proto
generated
vendored
Normal file
|
@ -0,0 +1,63 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package containerd.runhcs.v1;
|
||||
|
||||
import weak "gogoproto/gogo.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
option go_package = "github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options;options";
|
||||
|
||||
// Options are the set of customizations that can be passed at Create time.
|
||||
message Options {
|
||||
// enable debug tracing
|
||||
bool debug = 1;
|
||||
|
||||
enum DebugType {
|
||||
NPIPE = 0;
|
||||
FILE = 1;
|
||||
ETW = 2;
|
||||
}
|
||||
|
||||
// debug tracing output type
|
||||
DebugType debug_type = 2;
|
||||
|
||||
// registry key root for storage of the runhcs container state
|
||||
string registry_root = 3;
|
||||
|
||||
// sandbox_image is the image to use for the sandbox that matches the
|
||||
// sandbox_platform.
|
||||
string sandbox_image = 4;
|
||||
|
||||
// sandbox_platform is a CRI setting that specifies the platform
|
||||
// architecture for all sandbox's in this runtime. Values are
|
||||
// 'windows/amd64' and 'linux/amd64'.
|
||||
string sandbox_platform = 5;
|
||||
|
||||
enum SandboxIsolation {
|
||||
PROCESS = 0;
|
||||
HYPERVISOR = 1;
|
||||
}
|
||||
|
||||
// sandbox_isolation is a CRI setting that specifies the isolation level of
|
||||
// the sandbox. For Windows runtime PROCESS and HYPERVISOR are valid. For
|
||||
// LCOW only HYPERVISOR is valid and default if omitted.
|
||||
SandboxIsolation sandbox_isolation = 6;
|
||||
|
||||
// boot_files_root_path is the path to the directory containing the LCOW
|
||||
// kernel and root FS files.
|
||||
string boot_files_root_path = 7;
|
||||
}
|
||||
|
||||
// ProcessDetails contains additional information about a process. This is the additional
|
||||
// info returned in the Pids query.
|
||||
message ProcessDetails {
|
||||
string image_name = 1;
|
||||
google.protobuf.Timestamp created_at = 2 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
||||
uint64 kernel_time_100_ns = 3;
|
||||
uint64 memory_commit_bytes = 4;
|
||||
uint64 memory_working_set_private_bytes = 5;
|
||||
uint64 memory_working_set_shared_bytes = 6;
|
||||
uint32 process_id = 7;
|
||||
uint64 user_time_100_ns = 8;
|
||||
string exec_id = 9;
|
||||
}
|
13
vendor/github.com/Microsoft/hcsshim/internal/hcs/process.go
generated
vendored
13
vendor/github.com/Microsoft/hcsshim/internal/hcs/process.go
generated
vendored
|
@ -276,15 +276,20 @@ func (process *Process) ExitCode() (_ int, err error) {
|
|||
|
||||
properties, err := process.Properties()
|
||||
if err != nil {
|
||||
return 0, makeProcessError(process, operation, err, nil)
|
||||
return -1, makeProcessError(process, operation, err, nil)
|
||||
}
|
||||
|
||||
if properties.Exited == false {
|
||||
return 0, makeProcessError(process, operation, ErrInvalidProcessState, nil)
|
||||
return -1, makeProcessError(process, operation, ErrInvalidProcessState, nil)
|
||||
}
|
||||
|
||||
if properties.LastWaitResult != 0 {
|
||||
return 0, makeProcessError(process, operation, syscall.Errno(properties.LastWaitResult), nil)
|
||||
logrus.WithFields(logrus.Fields{
|
||||
logfields.ContainerID: process.SystemID(),
|
||||
logfields.ProcessID: process.processID,
|
||||
"wait-result": properties.LastWaitResult,
|
||||
}).Warn("hcsshim::Process::ExitCode - Non-zero last wait result")
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
return int(properties.ExitCode), nil
|
||||
|
@ -450,7 +455,7 @@ func (process *Process) unregisterCallback() error {
|
|||
closeChannels(context.channels)
|
||||
|
||||
callbackMapLock.Lock()
|
||||
callbackMap[callbackNumber] = nil
|
||||
delete(callbackMap, callbackNumber)
|
||||
callbackMapLock.Unlock()
|
||||
|
||||
handle = 0
|
||||
|
|
4
vendor/github.com/Microsoft/hcsshim/internal/hcs/system.go
generated
vendored
4
vendor/github.com/Microsoft/hcsshim/internal/hcs/system.go
generated
vendored
|
@ -280,7 +280,7 @@ func (computeSystem *System) Shutdown() (err error) {
|
|||
operation := "hcsshim::ComputeSystem::Shutdown"
|
||||
computeSystem.logOperationBegin(operation)
|
||||
defer func() {
|
||||
if IsAlreadyStopped(err) {
|
||||
if IsAlreadyStopped(err) || IsPending(err) {
|
||||
computeSystem.logOperationEnd(operation, nil)
|
||||
} else {
|
||||
computeSystem.logOperationEnd(operation, err)
|
||||
|
@ -640,7 +640,7 @@ func (computeSystem *System) unregisterCallback() error {
|
|||
closeChannels(context.channels)
|
||||
|
||||
callbackMapLock.Lock()
|
||||
callbackMap[callbackNumber] = nil
|
||||
delete(callbackMap, callbackNumber)
|
||||
callbackMapLock.Unlock()
|
||||
|
||||
handle = 0
|
||||
|
|
5
vendor/github.com/Microsoft/hcsshim/internal/hcs/waithelper.go
generated
vendored
5
vendor/github.com/Microsoft/hcsshim/internal/hcs/waithelper.go
generated
vendored
|
@ -17,6 +17,11 @@ func processAsyncHcsResult(err error, resultp *uint16, callbackNumber uintptr, e
|
|||
|
||||
func waitForNotification(callbackNumber uintptr, expectedNotification hcsNotification, timeout *time.Duration) error {
|
||||
callbackMapLock.RLock()
|
||||
if _, ok := callbackMap[callbackNumber]; !ok {
|
||||
callbackMapLock.RUnlock()
|
||||
logrus.Errorf("failed to waitForNotification: callbackNumber %d does not exist in callbackMap", callbackNumber)
|
||||
return ErrHandleClose
|
||||
}
|
||||
channels := callbackMap[callbackNumber].channels
|
||||
callbackMapLock.RUnlock()
|
||||
|
||||
|
|
10
vendor/github.com/Microsoft/hcsshim/internal/hns/hnsnetwork.go
generated
vendored
10
vendor/github.com/Microsoft/hcsshim/internal/hns/hnsnetwork.go
generated
vendored
|
@ -2,9 +2,9 @@ package hns
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net"
|
||||
|
||||
"errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"net"
|
||||
)
|
||||
|
||||
// Subnet is assoicated with a network and represents a list
|
||||
|
@ -98,6 +98,12 @@ func (network *HNSNetwork) Create() (*HNSNetwork, error) {
|
|||
title := "hcsshim::HNSNetwork::" + operation
|
||||
logrus.Debugf(title+" id=%s", network.Id)
|
||||
|
||||
for _, subnet := range network.Subnets {
|
||||
if (subnet.AddressPrefix != "") && (subnet.GatewayAddress == "") {
|
||||
return nil, errors.New("network create error, subnet has address prefix but no gateway specified")
|
||||
}
|
||||
}
|
||||
|
||||
jsonString, err := json.Marshal(network)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
3
vendor/github.com/Microsoft/hcsshim/internal/schema2/plan9_share.go
generated
vendored
3
vendor/github.com/Microsoft/hcsshim/internal/schema2/plan9_share.go
generated
vendored
|
@ -10,7 +10,6 @@
|
|||
package hcsschema
|
||||
|
||||
type Plan9Share struct {
|
||||
|
||||
Name string `json:"Name,omitempty"`
|
||||
|
||||
// The name by which the guest operation system can access this share, via the aname parameter in the Plan9 protocol.
|
||||
|
@ -30,4 +29,6 @@ type Plan9Share struct {
|
|||
ReadOnly bool `json:"ReadOnly,omitempty"`
|
||||
|
||||
UseShareRootIdentity bool `json:"UseShareRootIdentity,omitempty"`
|
||||
|
||||
AllowedFiles []string `json:"AllowedFiles,omitempty"`
|
||||
}
|
||||
|
|
16
vendor/github.com/Microsoft/hcsshim/vendor.conf
generated
vendored
16
vendor/github.com/Microsoft/hcsshim/vendor.conf
generated
vendored
|
@ -1,13 +1,20 @@
|
|||
github.com/blang/semver v3.1.0
|
||||
github.com/containerd/console c12b1e7919c14469339a5d38f2f8ed9b64a9de23
|
||||
github.com/containerd/containerd faec567304bbdf6864b1663d4f813641b5880a4a
|
||||
github.com/containerd/go-runc 5a6d9f37cfa36b15efba46dc7ea349fa9b7143c3
|
||||
github.com/containerd/ttrpc 2a805f71863501300ae1976d29f0454ae003e85a
|
||||
github.com/containerd/typeurl a93fcdb778cd272c6e9b3028b2f42d813e785d40
|
||||
github.com/gogo/protobuf v1.0.0
|
||||
github.com/golang/protobuf v1.1.0
|
||||
github.com/hashicorp/errwrap 7554cd9344cec97297fa6649b055a8c98c2a1e55
|
||||
github.com/hashicorp/go-multierror ed905158d87462226a13fe39ddf685ea65f1c11f
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1
|
||||
github.com/linuxkit/virtsock 8e79449dea0735c1c056d814934dd035734cc97c
|
||||
github.com/Microsoft/go-winio 16cfc975803886a5e47c4257a24c8d8c52e178b2
|
||||
github.com/Microsoft/opengcs v0.3.9
|
||||
github.com/opencontainers/runtime-spec eba862dc2470385a233c7507392675cbeadf7353
|
||||
github.com/opencontainers/go-digest c9281466c8b2f606084ac71339773efd177436e7
|
||||
github.com/opencontainers/runc 12f6a991201fdb8f82579582d5e00e28fba06d0a
|
||||
github.com/opencontainers/runtime-spec 29686dbc5559d93fb1ef402eeda3e35c38d75af4
|
||||
github.com/opencontainers/runtime-tools 1d69bd0f9c39677d0630e50664fbc3154ae61b88
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/sirupsen/logrus v1.3.0
|
||||
|
@ -17,5 +24,10 @@ github.com/xeipuuv/gojsonpointer 4e3ac2762d5f479393488629ee9370b50873b3a6
|
|||
github.com/xeipuuv/gojsonreference bd5ef7bd5415a7ac448318e64f11a24cd21e594b
|
||||
github.com/xeipuuv/gojsonschema 1d523034197ff1f222f6429836dd36a2457a1874
|
||||
golang.org/x/crypto ff983b9c42bc9fbf91556e191cc8efb585c16908
|
||||
golang.org/x/net ed066c81e75eba56dd9bd2139ade88125b855585
|
||||
golang.org/x/sync 37e7f081c4d4c64e13b10787722085407fe5d15f
|
||||
golang.org/x/sys e5ecc2a6747ce8d4af18ed98b3de5ae30eb3a5bb
|
||||
golang.org/x/sys e5ecc2a6747ce8d4af18ed98b3de5ae30eb3a5bb
|
||||
golang.org/x/text d14c52b222ee852cdba8b07206ca0c614b389876
|
||||
google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
|
||||
google.golang.org/grpc v1.12.0
|
||||
k8s.io/kubernetes v1.13.0
|
||||
|
|
79
vendor/github.com/Microsoft/opengcs/client/config.go
generated
vendored
79
vendor/github.com/Microsoft/opengcs/client/config.go
generated
vendored
|
@ -18,24 +18,6 @@ import (
|
|||
type Mode uint
|
||||
|
||||
const (
|
||||
// Constants for the actual mode after validation
|
||||
|
||||
// ModeActualError means an error has occurred during validation
|
||||
ModeActualError = iota
|
||||
// ModeActualVhdx means that we are going to use VHDX boot after validation
|
||||
ModeActualVhdx
|
||||
// ModeActualKernelInitrd means that we are going to use kernel+initrd for boot after validation
|
||||
ModeActualKernelInitrd
|
||||
|
||||
// Constants for the requested mode
|
||||
|
||||
// ModeRequestAuto means auto-select the boot mode for a utility VM
|
||||
ModeRequestAuto = iota // VHDX will be priority over kernel+initrd
|
||||
// ModeRequestVhdx means request VHDX boot if possible
|
||||
ModeRequestVhdx
|
||||
// ModeRequestKernelInitrd means request Kernel+initrd boot if possible
|
||||
ModeRequestKernelInitrd
|
||||
|
||||
// defaultUvmTimeoutSeconds is the default time to wait for utility VM operations
|
||||
defaultUvmTimeoutSeconds = 5 * 60
|
||||
|
||||
|
@ -54,8 +36,6 @@ const (
|
|||
type Config struct {
|
||||
Options // Configuration options
|
||||
Name string // Name of the utility VM
|
||||
RequestedMode Mode // What mode is preferred when validating
|
||||
ActualMode Mode // What mode was obtained during validation
|
||||
UvmTimeoutSeconds int // How long to wait for the utility VM to respond in seconds
|
||||
Uvm hcsshim.Container // The actual container
|
||||
MappedVirtualDisks []hcsshim.MappedVirtualDisk // Data-disks to be attached
|
||||
|
@ -66,9 +46,8 @@ type Options struct {
|
|||
KirdPath string // Path to where kernel/initrd are found (defaults to %PROGRAMFILES%\Linux Containers)
|
||||
KernelFile string // Kernel for Utility VM (embedded in a UEFI bootloader) - does NOT include full path, just filename
|
||||
InitrdFile string // Initrd image for Utility VM - does NOT include full path, just filename
|
||||
Vhdx string // VHD for booting the utility VM - is a full path
|
||||
TimeoutSeconds int // Requested time for the utility VM to respond in seconds (may be over-ridden by environment)
|
||||
BootParameters string // Additional boot parameters for initrd booting (not VHDx)
|
||||
BootParameters string // Additional boot parameters for initrd booting
|
||||
}
|
||||
|
||||
// ParseOptions parses a set of K-V pairs into options used by opengcs. Note
|
||||
|
@ -86,8 +65,6 @@ func ParseOptions(options []string) (Options, error) {
|
|||
rOpts.KernelFile = opt[1]
|
||||
case "lcow.initrd":
|
||||
rOpts.InitrdFile = opt[1]
|
||||
case "lcow.vhdx":
|
||||
rOpts.Vhdx = opt[1]
|
||||
case "lcow.bootparameters":
|
||||
rOpts.BootParameters = opt[1]
|
||||
case "lcow.timeout":
|
||||
|
@ -106,9 +83,6 @@ func ParseOptions(options []string) (Options, error) {
|
|||
if rOpts.KirdPath == "" {
|
||||
rOpts.KirdPath = filepath.Join(os.Getenv("ProgramFiles"), "Linux Containers")
|
||||
}
|
||||
if rOpts.Vhdx == "" {
|
||||
rOpts.Vhdx = filepath.Join(rOpts.KirdPath, `uvm.vhdx`)
|
||||
}
|
||||
if rOpts.KernelFile == "" {
|
||||
rOpts.KernelFile = `kernel`
|
||||
}
|
||||
|
@ -157,47 +131,11 @@ func (config *Config) GenerateDefault(options []string) error {
|
|||
// Last priority is the default timeout
|
||||
config.UvmTimeoutSeconds = defaultUvmTimeoutSeconds
|
||||
|
||||
// Set the default requested mode
|
||||
config.RequestedMode = ModeRequestAuto
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate validates a Config structure for starting a utility VM.
|
||||
func (config *Config) Validate() error {
|
||||
config.ActualMode = ModeActualError
|
||||
|
||||
if config.RequestedMode == ModeRequestVhdx && config.Vhdx == "" {
|
||||
return fmt.Errorf("VHDx mode must supply a VHDx")
|
||||
}
|
||||
if config.RequestedMode == ModeRequestKernelInitrd && (config.KernelFile == "" || config.InitrdFile == "") {
|
||||
return fmt.Errorf("kernel+initrd mode must supply both kernel and initrd")
|
||||
}
|
||||
|
||||
// Validate that if VHDX requested or auto, it exists.
|
||||
if config.RequestedMode == ModeRequestAuto || config.RequestedMode == ModeRequestVhdx {
|
||||
if _, err := os.Stat(config.Vhdx); os.IsNotExist(err) {
|
||||
if config.RequestedMode == ModeRequestVhdx {
|
||||
return fmt.Errorf("VHDx '%s' not found", config.Vhdx)
|
||||
}
|
||||
} else {
|
||||
config.ActualMode = ModeActualVhdx
|
||||
|
||||
// Can't specify boot parameters with VHDx
|
||||
if config.BootParameters != "" {
|
||||
return fmt.Errorf("Boot parameters cannot be specified in VHDx mode")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// So must be kernel+initrd, or auto where we fallback as the VHDX doesn't exist
|
||||
if config.InitrdFile == "" || config.KernelFile == "" {
|
||||
if config.RequestedMode == ModeRequestKernelInitrd {
|
||||
return fmt.Errorf("initrd and kernel options must be supplied")
|
||||
}
|
||||
return fmt.Errorf("opengcs: configuration is invalid")
|
||||
}
|
||||
|
||||
if _, err := os.Stat(filepath.Join(config.KirdPath, config.KernelFile)); os.IsNotExist(err) {
|
||||
return fmt.Errorf("kernel '%s' not found", filepath.Join(config.KirdPath, config.KernelFile))
|
||||
|
@ -206,8 +144,6 @@ func (config *Config) Validate() error {
|
|||
return fmt.Errorf("initrd '%s' not found", filepath.Join(config.KirdPath, config.InitrdFile))
|
||||
}
|
||||
|
||||
config.ActualMode = ModeActualKernelInitrd
|
||||
|
||||
// Ensure all the MappedVirtualDisks exist on the host
|
||||
for _, mvd := range config.MappedVirtualDisks {
|
||||
if _, err := os.Stat(mvd.HostPath); err != nil {
|
||||
|
@ -236,21 +172,12 @@ func (config *Config) StartUtilityVM() error {
|
|||
ContainerType: "linux",
|
||||
TerminateOnLastHandleClosed: true,
|
||||
MappedVirtualDisks: config.MappedVirtualDisks,
|
||||
}
|
||||
|
||||
if config.ActualMode == ModeActualVhdx {
|
||||
configuration.HvRuntime = &hcsshim.HvRuntime{
|
||||
ImagePath: config.Vhdx,
|
||||
BootSource: "Vhd",
|
||||
WritableBootSource: false,
|
||||
}
|
||||
} else {
|
||||
configuration.HvRuntime = &hcsshim.HvRuntime{
|
||||
HvRuntime: &hcsshim.HvRuntime{
|
||||
ImagePath: config.KirdPath,
|
||||
LinuxInitrdFile: config.InitrdFile,
|
||||
LinuxKernelFile: config.KernelFile,
|
||||
LinuxBootParameters: config.BootParameters,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
configurationS, _ := json.Marshal(configuration)
|
||||
|
|
46
vendor/github.com/Microsoft/opengcs/client/tartovhd.go
generated
vendored
46
vendor/github.com/Microsoft/opengcs/client/tartovhd.go
generated
vendored
|
@ -1,46 +0,0 @@
|
|||
// +build windows
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// TarToVhd streams a tarstream contained in an io.Reader to a fixed vhd file
|
||||
func (config *Config) TarToVhd(targetVHDFile string, reader io.Reader) (int64, error) {
|
||||
logrus.Debugf("opengcs: TarToVhd: %s", targetVHDFile)
|
||||
|
||||
if config.Uvm == nil {
|
||||
return 0, fmt.Errorf("cannot Tar2Vhd as no utility VM is in configuration")
|
||||
}
|
||||
|
||||
defer config.DebugGCS()
|
||||
|
||||
process, err := config.createUtilsProcess("tar2vhd")
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to start tar2vhd for %s: %s", targetVHDFile, err)
|
||||
}
|
||||
defer process.Process.Close()
|
||||
|
||||
// Send the tarstream into the `tar2vhd`s stdin
|
||||
if _, err = copyWithTimeout(process.Stdin, reader, 0, config.UvmTimeoutSeconds, fmt.Sprintf("stdin of tar2vhd for generating %s", targetVHDFile)); err != nil {
|
||||
return 0, fmt.Errorf("failed sending to tar2vhd for %s: %s", targetVHDFile, err)
|
||||
}
|
||||
|
||||
// Don't need stdin now we've sent everything. This signals GCS that we are finished sending data.
|
||||
if err := process.Process.CloseStdin(); err != nil {
|
||||
return 0, fmt.Errorf("failed closing stdin handle for %s: %s", targetVHDFile, err)
|
||||
}
|
||||
|
||||
// Write stdout contents of `tar2vhd` to the VHD file
|
||||
payloadSize, err := writeFileFromReader(targetVHDFile, process.Stdout, config.UvmTimeoutSeconds, fmt.Sprintf("stdout of tar2vhd to %s", targetVHDFile))
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to write %s during tar2vhd: %s", targetVHDFile, err)
|
||||
}
|
||||
|
||||
logrus.Debugf("opengcs: TarToVhd: %s created, %d bytes", targetVHDFile, payloadSize)
|
||||
return payloadSize, err
|
||||
}
|
333
vendor/github.com/Microsoft/opengcs/init/init.c
generated
vendored
Normal file
333
vendor/github.com/Microsoft/opengcs/init/init.c
generated
vendored
Normal file
|
@ -0,0 +1,333 @@
|
|||
#define _GNU_SOURCE
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define DEFAULT_PATH_ENV "PATH=/sbin:/usr/sbin:/bin:/usr/bin"
|
||||
|
||||
const char *const default_envp[] = {
|
||||
DEFAULT_PATH_ENV,
|
||||
NULL,
|
||||
};
|
||||
|
||||
// When nothing is passed, default to the LCOWv1 behavior.
|
||||
const char *const default_argv[] = { "/bin/gcs", "-loglevel", "debug", "-logfile=/tmp/gcs.log" };
|
||||
const char *const default_shell = "/bin/sh";
|
||||
|
||||
struct Mount {
|
||||
const char *source, *target, *type;
|
||||
unsigned long flags;
|
||||
const void *data;
|
||||
};
|
||||
|
||||
struct Mkdir {
|
||||
const char *path;
|
||||
mode_t mode;
|
||||
};
|
||||
|
||||
struct Mknod {
|
||||
const char *path;
|
||||
mode_t mode;
|
||||
int major, minor;
|
||||
};
|
||||
|
||||
struct Symlink {
|
||||
const char *linkpath, *target;
|
||||
};
|
||||
|
||||
enum OpType {
|
||||
OpMount,
|
||||
OpMkdir,
|
||||
OpMknod,
|
||||
OpSymlink,
|
||||
};
|
||||
|
||||
struct InitOp {
|
||||
enum OpType op;
|
||||
union {
|
||||
struct Mount mount;
|
||||
struct Mkdir mkdir;
|
||||
struct Mknod mknod;
|
||||
struct Symlink symlink;
|
||||
};
|
||||
};
|
||||
|
||||
const struct InitOp ops[] = {
|
||||
// mount /proc (which should already exist)
|
||||
{ OpMount, .mount = { "proc", "/proc", "proc", MS_NODEV | MS_NOSUID | MS_NOEXEC } },
|
||||
|
||||
// add symlinks in /dev (which is already mounted)
|
||||
{ OpSymlink, .symlink = { "/dev/fd", "/proc/self/fd" } },
|
||||
{ OpSymlink, .symlink = { "/dev/stdin", "/proc/self/fd/0" } },
|
||||
{ OpSymlink, .symlink = { "/dev/stdout", "/proc/self/fd/1" } },
|
||||
{ OpSymlink, .symlink = { "/dev/stderr", "/proc/self/fd/2" } },
|
||||
|
||||
// mount tmpfs on /run and /tmp (which should already exist)
|
||||
{ OpMount, .mount = { "tmpfs", "/run", "tmpfs", MS_NODEV | MS_NOSUID | MS_NOEXEC, "mode=0755" } },
|
||||
{ OpMount, .mount = { "tmpfs", "/tmp", "tmpfs", MS_NODEV | MS_NOSUID | MS_NOEXEC } },
|
||||
|
||||
// mount shm and devpts
|
||||
{ OpMkdir, .mkdir = { "/dev/shm", 0755 } },
|
||||
{ OpMount, .mount = { "shm", "/dev/shm", "tmpfs", MS_NODEV | MS_NOSUID | MS_NOEXEC } },
|
||||
{ OpMkdir, .mkdir = { "/dev/pts", 0755 } },
|
||||
{ OpMount, .mount = { "devpts", "/dev/pts", "devpts", MS_NOSUID | MS_NOEXEC } },
|
||||
|
||||
// mount /sys (which should already exist)
|
||||
{ OpMount, .mount = { "sysfs", "/sys", "sysfs", MS_NODEV | MS_NOSUID | MS_NOEXEC } },
|
||||
{ OpMount, .mount = { "cgroup_root", "/sys/fs/cgroup", "tmpfs", MS_NODEV | MS_NOSUID | MS_NOEXEC, "mode=0755" } },
|
||||
};
|
||||
|
||||
void warn(const char *msg) {
|
||||
int error = errno;
|
||||
perror(msg);
|
||||
errno = error;
|
||||
}
|
||||
|
||||
void warn2(const char *msg1, const char *msg2) {
|
||||
int error = errno;
|
||||
fputs(msg1, stderr);
|
||||
fputs(": ", stderr);
|
||||
errno = error;
|
||||
warn(msg2);
|
||||
}
|
||||
|
||||
_Noreturn void dien() {
|
||||
exit(errno);
|
||||
}
|
||||
|
||||
_Noreturn void die(const char *msg) {
|
||||
warn(msg);
|
||||
dien();
|
||||
}
|
||||
|
||||
_Noreturn void die2(const char *msg1, const char *msg2) {
|
||||
warn2(msg1, msg2);
|
||||
dien();
|
||||
}
|
||||
|
||||
void init_dev() {
|
||||
if (mount("dev", "/dev", "devtmpfs", MS_NOSUID | MS_NOEXEC, NULL) < 0) {
|
||||
warn2("mount", "/dev");
|
||||
// /dev will be already mounted if devtmpfs.mount = 1 on the kernel
|
||||
// command line or CONFIG_DEVTMPFS_MOUNT is set. Do not consider this
|
||||
// an error.
|
||||
if (errno != EBUSY) {
|
||||
dien();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void init_fs(const struct InitOp *ops, size_t count) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
switch (ops[i].op) {
|
||||
case OpMount: {
|
||||
const struct Mount *m = &ops[i].mount;
|
||||
if (mount(m->source, m->target, m->type, m->flags, m->data) < 0) {
|
||||
die2("mount", m->target);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpMkdir: {
|
||||
const struct Mkdir *m = &ops[i].mkdir;
|
||||
if (mkdir(m->path, m->mode) < 0) {
|
||||
warn2("mkdir", m->path);
|
||||
if (errno != EEXIST) {
|
||||
dien();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpMknod: {
|
||||
const struct Mknod *n = &ops[i].mknod;
|
||||
if (mknod(n->path, n->mode, makedev(n->major, n->minor)) < 0) {
|
||||
warn2("mknod", n->path);
|
||||
if (errno != EEXIST) {
|
||||
dien();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpSymlink: {
|
||||
const struct Symlink *sl = &ops[i].symlink;
|
||||
if (symlink(sl->target, sl->linkpath) < 0) {
|
||||
warn2("symlink", sl->linkpath);
|
||||
if (errno != EEXIST) {
|
||||
dien();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void init_cgroups() {
|
||||
const char *fpath = "/proc/cgroups";
|
||||
FILE *f = fopen(fpath, "r");
|
||||
if (f == NULL) {
|
||||
die2("fopen", fpath);
|
||||
}
|
||||
// Skip the first line.
|
||||
for (;;) {
|
||||
char c = fgetc(f);
|
||||
if (c == EOF || c == '\n') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (;;) {
|
||||
static const char base_path[] = "/sys/fs/cgroup/";
|
||||
char path[sizeof(base_path) - 1 + 64];
|
||||
char* name = path + sizeof(base_path) - 1;
|
||||
int hier, groups, enabled;
|
||||
int r = fscanf(f, "%64s %d %d %d\n", name, &hier, &groups, &enabled);
|
||||
if (r == EOF) {
|
||||
break;
|
||||
}
|
||||
if (r != 4) {
|
||||
errno = errno ? : EINVAL;
|
||||
die2("fscanf", fpath);
|
||||
}
|
||||
if (enabled) {
|
||||
memcpy(path, base_path, sizeof(base_path) - 1);
|
||||
if (mkdir(path, 0755) < 0) {
|
||||
die2("mkdir", path);
|
||||
}
|
||||
if (mount(name, path, "cgroup", MS_NODEV | MS_NOSUID | MS_NOEXEC, name) < 0) {
|
||||
die2("mount", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void init_network(const char *iface, int domain) {
|
||||
int s = socket(domain, SOCK_DGRAM, IPPROTO_IP);
|
||||
if (s < 0) {
|
||||
if (errno == EAFNOSUPPORT) {
|
||||
return;
|
||||
}
|
||||
die("socket");
|
||||
}
|
||||
|
||||
struct ifreq request = {0};
|
||||
strncpy(request.ifr_name, iface, sizeof(request.ifr_name));
|
||||
if (ioctl(s, SIOCGIFFLAGS, &request) < 0) {
|
||||
die2("ioctl(SIOCGIFFLAGS)", iface);
|
||||
}
|
||||
|
||||
request.ifr_flags |= IFF_UP | IFF_RUNNING;
|
||||
if (ioctl(s, SIOCSIFFLAGS, &request) < 0) {
|
||||
die2("ioctl(SIOCSIFFLAGS)", iface);
|
||||
}
|
||||
|
||||
close(s);
|
||||
}
|
||||
|
||||
pid_t launch(int argc, char **argv) {
|
||||
int pid = fork();
|
||||
if (pid != 0) {
|
||||
if (pid < 0) {
|
||||
die("fork");
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
// Unblock signals before execing.
|
||||
sigset_t set;
|
||||
sigfillset(&set);
|
||||
sigprocmask(SIG_UNBLOCK, &set, 0);
|
||||
|
||||
// Create a session and process group.
|
||||
setsid();
|
||||
setpgid(0, 0);
|
||||
|
||||
// Terminate the arguments and exec.
|
||||
char **argvn = alloca(sizeof(argv[0]) * (argc + 1));
|
||||
memcpy(argvn, argv, sizeof(argv[0]) * argc);
|
||||
argvn[argc] = NULL;
|
||||
if (putenv(DEFAULT_PATH_ENV)) { // Specify the PATH used for execvpe
|
||||
die("putenv");
|
||||
}
|
||||
execvpe(argvn[0], argvn, (char**)default_envp);
|
||||
die2("execvpe", argvn[0]);
|
||||
}
|
||||
|
||||
int reap_until(pid_t until_pid) {
|
||||
for (;;) {
|
||||
int status;
|
||||
pid_t pid = wait(&status);
|
||||
if (pid < 0) {
|
||||
die("wait");
|
||||
}
|
||||
|
||||
if (pid == until_pid) {
|
||||
// The initial child process died. Pass through the exit status.
|
||||
if (WIFEXITED(status)) {
|
||||
if (WEXITSTATUS(status) != 0) {
|
||||
fputs("child exited with error\n", stderr);
|
||||
}
|
||||
return WEXITSTATUS(status);
|
||||
}
|
||||
fputs("child exited by signal\n", stderr);
|
||||
return 128 + WTERMSIG(status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char *debug_shell = NULL;
|
||||
if (argc <= 1) {
|
||||
argv = (char **)default_argv;
|
||||
argc = sizeof(default_argv) / sizeof(default_argv[0]);
|
||||
optind = 0;
|
||||
debug_shell = (char*)default_shell;
|
||||
} else {
|
||||
for (int opt; (opt = getopt(argc, argv, "+d:")) >= 0; ) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
debug_shell = optarg;
|
||||
break;
|
||||
|
||||
default:
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char **child_argv = argv + optind;
|
||||
int child_argc = argc - optind;
|
||||
|
||||
// Block all signals in init. SIGCHLD will still cause wait() to return.
|
||||
sigset_t set;
|
||||
sigfillset(&set);
|
||||
sigprocmask(SIG_BLOCK, &set, 0);
|
||||
|
||||
init_dev();
|
||||
init_fs(ops, sizeof(ops) / sizeof(ops[0]));
|
||||
init_cgroups();
|
||||
init_network("lo", AF_INET);
|
||||
init_network("lo", AF_INET6);
|
||||
|
||||
pid_t pid = launch(child_argc, child_argv);
|
||||
if (debug_shell != NULL) {
|
||||
// The debug shell takes over as the primary child.
|
||||
pid = launch(1, &debug_shell);
|
||||
}
|
||||
|
||||
// Reap until the initial child process dies.
|
||||
return reap_until(pid);
|
||||
}
|
18
vendor/github.com/containerd/containerd/windows/hcsshimtypes/doc.go
generated
vendored
18
vendor/github.com/containerd/containerd/windows/hcsshimtypes/doc.go
generated
vendored
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package hcsshimtypes holds the windows runtime specific types
|
||||
package hcsshimtypes
|
744
vendor/github.com/containerd/containerd/windows/hcsshimtypes/hcsshim.pb.go
generated
vendored
744
vendor/github.com/containerd/containerd/windows/hcsshimtypes/hcsshim.pb.go
generated
vendored
|
@ -1,744 +0,0 @@
|
|||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
||||
// source: github.com/containerd/containerd/windows/hcsshimtypes/hcsshim.proto
|
||||
|
||||
/*
|
||||
Package hcsshimtypes is a generated protocol buffer package.
|
||||
|
||||
It is generated from these files:
|
||||
github.com/containerd/containerd/windows/hcsshimtypes/hcsshim.proto
|
||||
|
||||
It has these top-level messages:
|
||||
CreateOptions
|
||||
ProcessDetails
|
||||
*/
|
||||
package hcsshimtypes
|
||||
|
||||
import proto "github.com/gogo/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
|
||||
// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto"
|
||||
import _ "github.com/gogo/protobuf/types"
|
||||
import _ "github.com/gogo/protobuf/types"
|
||||
|
||||
import time "time"
|
||||
|
||||
import types "github.com/gogo/protobuf/types"
|
||||
|
||||
import strings "strings"
|
||||
import reflect "reflect"
|
||||
|
||||
import io "io"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
var _ = time.Kitchen
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
type CreateOptions struct {
|
||||
TerminateDuration time.Duration `protobuf:"bytes,1,opt,name=terminate_duration,json=terminateDuration,stdduration" json:"terminate_duration"`
|
||||
}
|
||||
|
||||
func (m *CreateOptions) Reset() { *m = CreateOptions{} }
|
||||
func (*CreateOptions) ProtoMessage() {}
|
||||
func (*CreateOptions) Descriptor() ([]byte, []int) { return fileDescriptorHcsshim, []int{0} }
|
||||
|
||||
// ProcessDetails contains additional information about a process
|
||||
// ProcessDetails is made of the same fields as found in hcsshim.ProcessListItem
|
||||
type ProcessDetails struct {
|
||||
ImageName string `protobuf:"bytes,1,opt,name=image_name,json=imageName,proto3" json:"image_name,omitempty"`
|
||||
CreatedAt time.Time `protobuf:"bytes,2,opt,name=created_at,json=createdAt,stdtime" json:"created_at"`
|
||||
KernelTime_100Ns uint64 `protobuf:"varint,3,opt,name=kernel_time_100_ns,json=kernelTime100Ns,proto3" json:"kernel_time_100_ns,omitempty"`
|
||||
MemoryCommitBytes uint64 `protobuf:"varint,4,opt,name=memory_commit_bytes,json=memoryCommitBytes,proto3" json:"memory_commit_bytes,omitempty"`
|
||||
MemoryWorkingSetPrivateBytes uint64 `protobuf:"varint,5,opt,name=memory_working_set_private_bytes,json=memoryWorkingSetPrivateBytes,proto3" json:"memory_working_set_private_bytes,omitempty"`
|
||||
MemoryWorkingSetSharedBytes uint64 `protobuf:"varint,6,opt,name=memory_working_set_shared_bytes,json=memoryWorkingSetSharedBytes,proto3" json:"memory_working_set_shared_bytes,omitempty"`
|
||||
ProcessID uint32 `protobuf:"varint,7,opt,name=process_id,json=processId,proto3" json:"process_id,omitempty"`
|
||||
UserTime_100Ns uint64 `protobuf:"varint,8,opt,name=user_time_100_ns,json=userTime100Ns,proto3" json:"user_time_100_ns,omitempty"`
|
||||
ExecID string `protobuf:"bytes,9,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"`
|
||||
}
|
||||
|
||||
func (m *ProcessDetails) Reset() { *m = ProcessDetails{} }
|
||||
func (*ProcessDetails) ProtoMessage() {}
|
||||
func (*ProcessDetails) Descriptor() ([]byte, []int) { return fileDescriptorHcsshim, []int{1} }
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*CreateOptions)(nil), "containerd.windows.hcsshim.CreateOptions")
|
||||
proto.RegisterType((*ProcessDetails)(nil), "containerd.windows.hcsshim.ProcessDetails")
|
||||
}
|
||||
func (m *CreateOptions) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalTo(dAtA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *CreateOptions) MarshalTo(dAtA []byte) (int, error) {
|
||||
var i int
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
dAtA[i] = 0xa
|
||||
i++
|
||||
i = encodeVarintHcsshim(dAtA, i, uint64(types.SizeOfStdDuration(m.TerminateDuration)))
|
||||
n1, err := types.StdDurationMarshalTo(m.TerminateDuration, dAtA[i:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i += n1
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (m *ProcessDetails) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalTo(dAtA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *ProcessDetails) MarshalTo(dAtA []byte) (int, error) {
|
||||
var i int
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.ImageName) > 0 {
|
||||
dAtA[i] = 0xa
|
||||
i++
|
||||
i = encodeVarintHcsshim(dAtA, i, uint64(len(m.ImageName)))
|
||||
i += copy(dAtA[i:], m.ImageName)
|
||||
}
|
||||
dAtA[i] = 0x12
|
||||
i++
|
||||
i = encodeVarintHcsshim(dAtA, i, uint64(types.SizeOfStdTime(m.CreatedAt)))
|
||||
n2, err := types.StdTimeMarshalTo(m.CreatedAt, dAtA[i:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i += n2
|
||||
if m.KernelTime_100Ns != 0 {
|
||||
dAtA[i] = 0x18
|
||||
i++
|
||||
i = encodeVarintHcsshim(dAtA, i, uint64(m.KernelTime_100Ns))
|
||||
}
|
||||
if m.MemoryCommitBytes != 0 {
|
||||
dAtA[i] = 0x20
|
||||
i++
|
||||
i = encodeVarintHcsshim(dAtA, i, uint64(m.MemoryCommitBytes))
|
||||
}
|
||||
if m.MemoryWorkingSetPrivateBytes != 0 {
|
||||
dAtA[i] = 0x28
|
||||
i++
|
||||
i = encodeVarintHcsshim(dAtA, i, uint64(m.MemoryWorkingSetPrivateBytes))
|
||||
}
|
||||
if m.MemoryWorkingSetSharedBytes != 0 {
|
||||
dAtA[i] = 0x30
|
||||
i++
|
||||
i = encodeVarintHcsshim(dAtA, i, uint64(m.MemoryWorkingSetSharedBytes))
|
||||
}
|
||||
if m.ProcessID != 0 {
|
||||
dAtA[i] = 0x38
|
||||
i++
|
||||
i = encodeVarintHcsshim(dAtA, i, uint64(m.ProcessID))
|
||||
}
|
||||
if m.UserTime_100Ns != 0 {
|
||||
dAtA[i] = 0x40
|
||||
i++
|
||||
i = encodeVarintHcsshim(dAtA, i, uint64(m.UserTime_100Ns))
|
||||
}
|
||||
if len(m.ExecID) > 0 {
|
||||
dAtA[i] = 0x4a
|
||||
i++
|
||||
i = encodeVarintHcsshim(dAtA, i, uint64(len(m.ExecID)))
|
||||
i += copy(dAtA[i:], m.ExecID)
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func encodeVarintHcsshim(dAtA []byte, offset int, v uint64) int {
|
||||
for v >= 1<<7 {
|
||||
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||
v >>= 7
|
||||
offset++
|
||||
}
|
||||
dAtA[offset] = uint8(v)
|
||||
return offset + 1
|
||||
}
|
||||
func (m *CreateOptions) Size() (n int) {
|
||||
var l int
|
||||
_ = l
|
||||
l = types.SizeOfStdDuration(m.TerminateDuration)
|
||||
n += 1 + l + sovHcsshim(uint64(l))
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *ProcessDetails) Size() (n int) {
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.ImageName)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovHcsshim(uint64(l))
|
||||
}
|
||||
l = types.SizeOfStdTime(m.CreatedAt)
|
||||
n += 1 + l + sovHcsshim(uint64(l))
|
||||
if m.KernelTime_100Ns != 0 {
|
||||
n += 1 + sovHcsshim(uint64(m.KernelTime_100Ns))
|
||||
}
|
||||
if m.MemoryCommitBytes != 0 {
|
||||
n += 1 + sovHcsshim(uint64(m.MemoryCommitBytes))
|
||||
}
|
||||
if m.MemoryWorkingSetPrivateBytes != 0 {
|
||||
n += 1 + sovHcsshim(uint64(m.MemoryWorkingSetPrivateBytes))
|
||||
}
|
||||
if m.MemoryWorkingSetSharedBytes != 0 {
|
||||
n += 1 + sovHcsshim(uint64(m.MemoryWorkingSetSharedBytes))
|
||||
}
|
||||
if m.ProcessID != 0 {
|
||||
n += 1 + sovHcsshim(uint64(m.ProcessID))
|
||||
}
|
||||
if m.UserTime_100Ns != 0 {
|
||||
n += 1 + sovHcsshim(uint64(m.UserTime_100Ns))
|
||||
}
|
||||
l = len(m.ExecID)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovHcsshim(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func sovHcsshim(x uint64) (n int) {
|
||||
for {
|
||||
n++
|
||||
x >>= 7
|
||||
if x == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
func sozHcsshim(x uint64) (n int) {
|
||||
return sovHcsshim(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
}
|
||||
func (this *CreateOptions) String() string {
|
||||
if this == nil {
|
||||
return "nil"
|
||||
}
|
||||
s := strings.Join([]string{`&CreateOptions{`,
|
||||
`TerminateDuration:` + strings.Replace(strings.Replace(this.TerminateDuration.String(), "Duration", "google_protobuf1.Duration", 1), `&`, ``, 1) + `,`,
|
||||
`}`,
|
||||
}, "")
|
||||
return s
|
||||
}
|
||||
func (this *ProcessDetails) String() string {
|
||||
if this == nil {
|
||||
return "nil"
|
||||
}
|
||||
s := strings.Join([]string{`&ProcessDetails{`,
|
||||
`ImageName:` + fmt.Sprintf("%v", this.ImageName) + `,`,
|
||||
`CreatedAt:` + strings.Replace(strings.Replace(this.CreatedAt.String(), "Timestamp", "google_protobuf2.Timestamp", 1), `&`, ``, 1) + `,`,
|
||||
`KernelTime_100Ns:` + fmt.Sprintf("%v", this.KernelTime_100Ns) + `,`,
|
||||
`MemoryCommitBytes:` + fmt.Sprintf("%v", this.MemoryCommitBytes) + `,`,
|
||||
`MemoryWorkingSetPrivateBytes:` + fmt.Sprintf("%v", this.MemoryWorkingSetPrivateBytes) + `,`,
|
||||
`MemoryWorkingSetSharedBytes:` + fmt.Sprintf("%v", this.MemoryWorkingSetSharedBytes) + `,`,
|
||||
`ProcessID:` + fmt.Sprintf("%v", this.ProcessID) + `,`,
|
||||
`UserTime_100Ns:` + fmt.Sprintf("%v", this.UserTime_100Ns) + `,`,
|
||||
`ExecID:` + fmt.Sprintf("%v", this.ExecID) + `,`,
|
||||
`}`,
|
||||
}, "")
|
||||
return s
|
||||
}
|
||||
func valueToStringHcsshim(v interface{}) string {
|
||||
rv := reflect.ValueOf(v)
|
||||
if rv.IsNil() {
|
||||
return "nil"
|
||||
}
|
||||
pv := reflect.Indirect(rv).Interface()
|
||||
return fmt.Sprintf("*%v", pv)
|
||||
}
|
||||
func (m *CreateOptions) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowHcsshim
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: CreateOptions: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: CreateOptions: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field TerminateDuration", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowHcsshim
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthHcsshim
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if err := types.StdDurationUnmarshal(&m.TerminateDuration, dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipHcsshim(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthHcsshim
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *ProcessDetails) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowHcsshim
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: ProcessDetails: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: ProcessDetails: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field ImageName", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowHcsshim
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthHcsshim
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.ImageName = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field CreatedAt", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowHcsshim
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthHcsshim
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if err := types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 3:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field KernelTime_100Ns", wireType)
|
||||
}
|
||||
m.KernelTime_100Ns = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowHcsshim
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.KernelTime_100Ns |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 4:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field MemoryCommitBytes", wireType)
|
||||
}
|
||||
m.MemoryCommitBytes = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowHcsshim
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.MemoryCommitBytes |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 5:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field MemoryWorkingSetPrivateBytes", wireType)
|
||||
}
|
||||
m.MemoryWorkingSetPrivateBytes = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowHcsshim
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.MemoryWorkingSetPrivateBytes |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 6:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field MemoryWorkingSetSharedBytes", wireType)
|
||||
}
|
||||
m.MemoryWorkingSetSharedBytes = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowHcsshim
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.MemoryWorkingSetSharedBytes |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 7:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field ProcessID", wireType)
|
||||
}
|
||||
m.ProcessID = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowHcsshim
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.ProcessID |= (uint32(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 8:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field UserTime_100Ns", wireType)
|
||||
}
|
||||
m.UserTime_100Ns = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowHcsshim
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.UserTime_100Ns |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 9:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field ExecID", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowHcsshim
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthHcsshim
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.ExecID = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipHcsshim(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthHcsshim
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func skipHcsshim(dAtA []byte) (n int, err error) {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowHcsshim
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
wireType := int(wire & 0x7)
|
||||
switch wireType {
|
||||
case 0:
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowHcsshim
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx++
|
||||
if dAtA[iNdEx-1] < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return iNdEx, nil
|
||||
case 1:
|
||||
iNdEx += 8
|
||||
return iNdEx, nil
|
||||
case 2:
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowHcsshim
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
length |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
iNdEx += length
|
||||
if length < 0 {
|
||||
return 0, ErrInvalidLengthHcsshim
|
||||
}
|
||||
return iNdEx, nil
|
||||
case 3:
|
||||
for {
|
||||
var innerWire uint64
|
||||
var start int = iNdEx
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowHcsshim
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
innerWire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
innerWireType := int(innerWire & 0x7)
|
||||
if innerWireType == 4 {
|
||||
break
|
||||
}
|
||||
next, err := skipHcsshim(dAtA[start:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
iNdEx = start + next
|
||||
}
|
||||
return iNdEx, nil
|
||||
case 4:
|
||||
return iNdEx, nil
|
||||
case 5:
|
||||
iNdEx += 4
|
||||
return iNdEx, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLengthHcsshim = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflowHcsshim = fmt.Errorf("proto: integer overflow")
|
||||
)
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("github.com/containerd/containerd/windows/hcsshimtypes/hcsshim.proto", fileDescriptorHcsshim)
|
||||
}
|
||||
|
||||
var fileDescriptorHcsshim = []byte{
|
||||
// 507 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x93, 0x41, 0x6f, 0xd3, 0x3c,
|
||||
0x18, 0xc7, 0x9b, 0x77, 0x7b, 0xbb, 0xc5, 0xa8, 0xc0, 0x0c, 0x87, 0x52, 0x20, 0xa9, 0xc6, 0x81,
|
||||
0x4a, 0xa0, 0xb4, 0x83, 0x23, 0x27, 0xd2, 0x82, 0xd4, 0xcb, 0x98, 0x32, 0x24, 0x10, 0x42, 0xb2,
|
||||
0xdc, 0xe4, 0x21, 0xb5, 0x56, 0xc7, 0x91, 0xed, 0xd2, 0xf5, 0xc6, 0x47, 0xe0, 0xc8, 0x47, 0xea,
|
||||
0x91, 0x23, 0x12, 0x52, 0x61, 0xf9, 0x24, 0xc8, 0x76, 0xba, 0x8d, 0xc1, 0x89, 0x9b, 0xed, 0xff,
|
||||
0xef, 0xf9, 0x3d, 0xf1, 0x63, 0x05, 0x0d, 0x73, 0xa6, 0xa7, 0xf3, 0x49, 0x94, 0x0a, 0xde, 0x4f,
|
||||
0x45, 0xa1, 0x29, 0x2b, 0x40, 0x66, 0x97, 0x97, 0x0b, 0x56, 0x64, 0x62, 0xa1, 0xfa, 0xd3, 0x54,
|
||||
0xa9, 0x29, 0xe3, 0x7a, 0x59, 0xc2, 0xf9, 0x26, 0x2a, 0xa5, 0xd0, 0x02, 0x77, 0x2e, 0xf0, 0xa8,
|
||||
0xc6, 0xa3, 0x9a, 0xe8, 0xdc, 0xce, 0x45, 0x2e, 0x2c, 0xd6, 0x37, 0x2b, 0x57, 0xd1, 0x09, 0x72,
|
||||
0x21, 0xf2, 0x19, 0xf4, 0xed, 0x6e, 0x32, 0xff, 0xd0, 0xcf, 0xe6, 0x92, 0x6a, 0x26, 0x8a, 0x3a,
|
||||
0x0f, 0xaf, 0xe6, 0x9a, 0x71, 0x50, 0x9a, 0xf2, 0xd2, 0x01, 0xfb, 0x29, 0x6a, 0x0d, 0x25, 0x50,
|
||||
0x0d, 0xaf, 0x4a, 0x53, 0xa6, 0x70, 0x82, 0xb0, 0x06, 0xc9, 0x59, 0x41, 0x35, 0x90, 0x8d, 0xad,
|
||||
0xed, 0x75, 0xbd, 0xde, 0xb5, 0x27, 0x77, 0x22, 0xa7, 0x8b, 0x36, 0xba, 0x68, 0x54, 0x03, 0xf1,
|
||||
0xee, 0x6a, 0x1d, 0x36, 0xbe, 0xfc, 0x08, 0xbd, 0x64, 0xef, 0xbc, 0x7c, 0x13, 0xee, 0x7f, 0xdf,
|
||||
0x42, 0xd7, 0x8f, 0xa4, 0x48, 0x41, 0xa9, 0x11, 0x68, 0xca, 0x66, 0x0a, 0xdf, 0x47, 0x88, 0x71,
|
||||
0x9a, 0x03, 0x29, 0x28, 0x07, 0xab, 0xf7, 0x13, 0xdf, 0x9e, 0x1c, 0x52, 0x0e, 0x78, 0x88, 0x50,
|
||||
0x6a, 0x3f, 0x2b, 0x23, 0x54, 0xb7, 0xff, 0xb3, 0xdd, 0x3b, 0x7f, 0x74, 0x7f, 0xbd, 0xb9, 0x8c,
|
||||
0x6b, 0xff, 0xd9, 0xb4, 0xf7, 0xeb, 0xba, 0xe7, 0x1a, 0x3f, 0x42, 0xf8, 0x04, 0x64, 0x01, 0x33,
|
||||
0x62, 0x6e, 0x4d, 0x0e, 0x06, 0x03, 0x52, 0xa8, 0xf6, 0x56, 0xd7, 0xeb, 0x6d, 0x27, 0x37, 0x5c,
|
||||
0x62, 0x0c, 0x07, 0x83, 0xc1, 0xa1, 0xc2, 0x11, 0xba, 0xc5, 0x81, 0x0b, 0xb9, 0x24, 0xa9, 0xe0,
|
||||
0x9c, 0x69, 0x32, 0x59, 0x6a, 0x50, 0xed, 0x6d, 0x4b, 0xef, 0xb9, 0x68, 0x68, 0x93, 0xd8, 0x04,
|
||||
0xf8, 0x25, 0xea, 0xd6, 0xfc, 0x42, 0xc8, 0x13, 0x56, 0xe4, 0x44, 0x81, 0x26, 0xa5, 0x64, 0x1f,
|
||||
0xcd, 0xe0, 0x5c, 0xf1, 0xff, 0xb6, 0xf8, 0x9e, 0xe3, 0xde, 0x38, 0xec, 0x18, 0xf4, 0x91, 0x83,
|
||||
0x9c, 0x67, 0x84, 0xc2, 0xbf, 0x78, 0xd4, 0x94, 0x4a, 0xc8, 0x6a, 0x4d, 0xd3, 0x6a, 0xee, 0x5e,
|
||||
0xd5, 0x1c, 0x5b, 0xc6, 0x59, 0x1e, 0x23, 0x54, 0xba, 0x01, 0x13, 0x96, 0xb5, 0x77, 0xba, 0x5e,
|
||||
0xaf, 0x15, 0xb7, 0xaa, 0x75, 0xe8, 0xd7, 0x63, 0x1f, 0x8f, 0x12, 0xbf, 0x06, 0xc6, 0x19, 0x7e,
|
||||
0x88, 0x6e, 0xce, 0x15, 0xc8, 0xdf, 0xc6, 0xb2, 0x6b, 0x9b, 0xb4, 0xcc, 0xf9, 0xc5, 0x50, 0x1e,
|
||||
0xa0, 0x1d, 0x38, 0x85, 0xd4, 0x38, 0x7d, 0xf3, 0x44, 0x31, 0xaa, 0xd6, 0x61, 0xf3, 0xc5, 0x29,
|
||||
0xa4, 0xe3, 0x51, 0xd2, 0x34, 0xd1, 0x38, 0x8b, 0xdf, 0xaf, 0xce, 0x82, 0xc6, 0xb7, 0xb3, 0xa0,
|
||||
0xf1, 0xa9, 0x0a, 0xbc, 0x55, 0x15, 0x78, 0x5f, 0xab, 0xc0, 0xfb, 0x59, 0x05, 0xde, 0xbb, 0xf8,
|
||||
0x9f, 0x7e, 0x8a, 0x67, 0x97, 0x37, 0x6f, 0x1b, 0x93, 0xa6, 0x7d, 0xef, 0xa7, 0xbf, 0x02, 0x00,
|
||||
0x00, 0xff, 0xff, 0x1e, 0xd7, 0x2f, 0xa8, 0x63, 0x03, 0x00, 0x00,
|
||||
}
|
27
vendor/github.com/containerd/containerd/windows/hcsshimtypes/hcsshim.proto
generated
vendored
27
vendor/github.com/containerd/containerd/windows/hcsshimtypes/hcsshim.proto
generated
vendored
|
@ -1,27 +0,0 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package containerd.windows.hcsshim;
|
||||
|
||||
import weak "gogoproto/gogo.proto";
|
||||
import "google/protobuf/duration.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
option go_package = "github.com/containerd/containerd/windows/hcsshimtypes;hcsshimtypes";
|
||||
|
||||
message CreateOptions {
|
||||
google.protobuf.Duration terminate_duration = 1 [(gogoproto.stdduration) = true, (gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// ProcessDetails contains additional information about a process
|
||||
// ProcessDetails is made of the same fields as found in hcsshim.ProcessListItem
|
||||
message ProcessDetails {
|
||||
string image_name = 1;
|
||||
google.protobuf.Timestamp created_at = 2 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
||||
uint64 kernel_time_100_ns = 3;
|
||||
uint64 memory_commit_bytes = 4;
|
||||
uint64 memory_working_set_private_bytes = 5;
|
||||
uint64 memory_working_set_shared_bytes = 6;
|
||||
uint32 process_id = 7;
|
||||
uint64 user_time_100_ns = 8;
|
||||
string exec_id = 9;
|
||||
}
|
9
vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE
generated
vendored
Normal file
9
vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
(The MIT License)
|
||||
|
||||
Copyright (c) 2017 marvin + konsorten GmbH (open-source@konsorten.de)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
40
vendor/github.com/konsorten/go-windows-terminal-sequences/README.md
generated
vendored
Normal file
40
vendor/github.com/konsorten/go-windows-terminal-sequences/README.md
generated
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
# Windows Terminal Sequences
|
||||
|
||||
This library allow for enabling Windows terminal color support for Go.
|
||||
|
||||
See [Console Virtual Terminal Sequences](https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences) for details.
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
sequences "github.com/konsorten/go-windows-terminal-sequences"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sequences.EnableVirtualTerminalProcessing(syscall.Stdout, true)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Authors
|
||||
|
||||
The tool is sponsored by the [marvin + konsorten GmbH](http://www.konsorten.de).
|
||||
|
||||
We thank all the authors who provided code to this library:
|
||||
|
||||
* Felix Kollmann
|
||||
|
||||
## License
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2018 marvin + konsorten GmbH (open-source@konsorten.de)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
36
vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go
generated
vendored
Normal file
36
vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
// +build windows
|
||||
|
||||
package sequences
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
kernel32Dll *syscall.LazyDLL = syscall.NewLazyDLL("Kernel32.dll")
|
||||
setConsoleMode *syscall.LazyProc = kernel32Dll.NewProc("SetConsoleMode")
|
||||
)
|
||||
|
||||
func EnableVirtualTerminalProcessing(stream syscall.Handle, enable bool) error {
|
||||
const ENABLE_VIRTUAL_TERMINAL_PROCESSING uint32 = 0x4
|
||||
|
||||
var mode uint32
|
||||
err := syscall.GetConsoleMode(syscall.Stdout, &mode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if enable {
|
||||
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
} else {
|
||||
mode &^= ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
}
|
||||
|
||||
ret, _, err := setConsoleMode.Call(uintptr(unsafe.Pointer(stream)), uintptr(mode))
|
||||
if ret == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
37
vendor/github.com/sirupsen/logrus/README.md
generated
vendored
37
vendor/github.com/sirupsen/logrus/README.md
generated
vendored
|
@ -56,8 +56,39 @@ time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased
|
|||
time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
|
||||
time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
|
||||
time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true
|
||||
exit status 1
|
||||
```
|
||||
To ensure this behaviour even if a TTY is attached, set your formatter as follows:
|
||||
|
||||
```go
|
||||
log.SetFormatter(&log.TextFormatter{
|
||||
DisableColors: true,
|
||||
FullTimestamp: true,
|
||||
})
|
||||
```
|
||||
|
||||
#### Logging Method Name
|
||||
|
||||
If you wish to add the calling method as a field, instruct the logger via:
|
||||
```go
|
||||
log.SetReportCaller(true)
|
||||
```
|
||||
This adds the caller as 'method' like so:
|
||||
|
||||
```json
|
||||
{"animal":"penguin","level":"fatal","method":"github.com/sirupsen/arcticcreatures.migrate","msg":"a penguin swims by",
|
||||
"time":"2014-03-10 19:57:38.562543129 -0400 EDT"}
|
||||
```
|
||||
|
||||
```text
|
||||
time="2015-03-26T01:27:38-04:00" level=fatal method=github.com/sirupsen/arcticcreatures.migrate msg="a penguin swims by" animal=penguin
|
||||
```
|
||||
Note that this does add measurable overhead - the cost will depend on the version of Go, but is
|
||||
between 20 and 40% in recent tests with 1.6 and 1.7. You can validate this in your
|
||||
environment via benchmarks:
|
||||
```
|
||||
go test -bench=.*CallerTracing
|
||||
```
|
||||
|
||||
|
||||
#### Case-sensitivity
|
||||
|
||||
|
@ -246,9 +277,10 @@ A list of currently known of service hook can be found in this wiki [page](https
|
|||
|
||||
#### Level logging
|
||||
|
||||
Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic.
|
||||
Logrus has seven logging levels: Trace, Debug, Info, Warning, Error, Fatal and Panic.
|
||||
|
||||
```go
|
||||
log.Trace("Something very low level.")
|
||||
log.Debug("Useful debugging information.")
|
||||
log.Info("Something noteworthy happened!")
|
||||
log.Warn("You should probably take a look at this.")
|
||||
|
@ -329,6 +361,7 @@ The built-in logging formatters are:
|
|||
Third party logging formatters:
|
||||
|
||||
* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can be parsed by Kubernetes and Google Container Engine.
|
||||
* [`GELF`](https://github.com/fabienm/go-logrus-formatters). Formats entries so they comply to Graylog's [GELF 1.1 specification](http://docs.graylog.org/en/2.4/pages/gelf.html).
|
||||
* [`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̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
|
||||
|
|
233
vendor/github.com/sirupsen/logrus/entry.go
generated
vendored
233
vendor/github.com/sirupsen/logrus/entry.go
generated
vendored
|
@ -4,11 +4,30 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var bufferPool *sync.Pool
|
||||
var (
|
||||
bufferPool *sync.Pool
|
||||
|
||||
// qualified package name, cached at first use
|
||||
logrusPackage string
|
||||
|
||||
// Positions in the call stack when tracing to report the calling method
|
||||
minimumCallerDepth int
|
||||
|
||||
// Used for caller information initialisation
|
||||
callerInitOnce sync.Once
|
||||
)
|
||||
|
||||
const (
|
||||
maximumCallerDepth int = 25
|
||||
knownLogrusFrames int = 4
|
||||
)
|
||||
|
||||
func init() {
|
||||
bufferPool = &sync.Pool{
|
||||
|
@ -16,15 +35,18 @@ func init() {
|
|||
return new(bytes.Buffer)
|
||||
},
|
||||
}
|
||||
|
||||
// start at the bottom of the stack before the package-name cache is primed
|
||||
minimumCallerDepth = 1
|
||||
}
|
||||
|
||||
// Defines the key when adding errors using WithError.
|
||||
var ErrorKey = "error"
|
||||
|
||||
// An entry is the final or intermediate Logrus logging entry. It contains all
|
||||
// the fields passed with WithField{,s}. It's finally logged when Debug, Info,
|
||||
// Warn, Error, Fatal or Panic is called on it. These objects can be reused and
|
||||
// passed around as much as you wish to avoid field duplication.
|
||||
// the fields passed with WithField{,s}. It's finally logged when Trace, Debug,
|
||||
// Info, Warn, Error, Fatal or Panic is called on it. These objects can be
|
||||
// reused and passed around as much as you wish to avoid field duplication.
|
||||
type Entry struct {
|
||||
Logger *Logger
|
||||
|
||||
|
@ -34,22 +56,28 @@ type Entry struct {
|
|||
// Time at which the log entry was created
|
||||
Time time.Time
|
||||
|
||||
// Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
|
||||
// Level the log entry was logged at: Trace, Debug, Info, Warn, Error, Fatal or Panic
|
||||
// This field will be set on entry firing and the value will be equal to the one in Logger struct field.
|
||||
Level Level
|
||||
|
||||
// Message passed to Debug, Info, Warn, Error, Fatal or Panic
|
||||
// Calling method, with package name
|
||||
Caller *runtime.Frame
|
||||
|
||||
// Message passed to Trace, Debug, Info, Warn, Error, Fatal or Panic
|
||||
Message string
|
||||
|
||||
// When formatter is called in entry.log(), an Buffer may be set to entry
|
||||
// When formatter is called in entry.log(), a Buffer may be set to entry
|
||||
Buffer *bytes.Buffer
|
||||
|
||||
// err may contain a field formatting error
|
||||
err string
|
||||
}
|
||||
|
||||
func NewEntry(logger *Logger) *Entry {
|
||||
return &Entry{
|
||||
Logger: logger,
|
||||
// Default is five fields, give a little extra room
|
||||
Data: make(Fields, 5),
|
||||
// Default is three fields, plus one optional. Give a little extra room.
|
||||
Data: make(Fields, 6),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,15 +108,85 @@ func (entry *Entry) WithFields(fields Fields) *Entry {
|
|||
for k, v := range entry.Data {
|
||||
data[k] = v
|
||||
}
|
||||
fieldErr := entry.err
|
||||
for k, v := range fields {
|
||||
data[k] = v
|
||||
isErrField := false
|
||||
if t := reflect.TypeOf(v); t != nil {
|
||||
switch t.Kind() {
|
||||
case reflect.Func:
|
||||
isErrField = true
|
||||
case reflect.Ptr:
|
||||
isErrField = t.Elem().Kind() == reflect.Func
|
||||
}
|
||||
}
|
||||
if isErrField {
|
||||
tmp := fmt.Sprintf("can not add field %q", k)
|
||||
if fieldErr != "" {
|
||||
fieldErr = entry.err + ", " + tmp
|
||||
} else {
|
||||
fieldErr = tmp
|
||||
}
|
||||
} else {
|
||||
data[k] = v
|
||||
}
|
||||
}
|
||||
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time}
|
||||
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: fieldErr}
|
||||
}
|
||||
|
||||
// Overrides the time of the Entry.
|
||||
func (entry *Entry) WithTime(t time.Time) *Entry {
|
||||
return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t}
|
||||
return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t, err: entry.err}
|
||||
}
|
||||
|
||||
// getPackageName reduces a fully qualified function name to the package name
|
||||
// There really ought to be to be a better way...
|
||||
func getPackageName(f string) string {
|
||||
for {
|
||||
lastPeriod := strings.LastIndex(f, ".")
|
||||
lastSlash := strings.LastIndex(f, "/")
|
||||
if lastPeriod > lastSlash {
|
||||
f = f[:lastPeriod]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
// getCaller retrieves the name of the first non-logrus calling function
|
||||
func getCaller() *runtime.Frame {
|
||||
// Restrict the lookback frames to avoid runaway lookups
|
||||
pcs := make([]uintptr, maximumCallerDepth)
|
||||
depth := runtime.Callers(minimumCallerDepth, pcs)
|
||||
frames := runtime.CallersFrames(pcs[:depth])
|
||||
|
||||
// cache this package's fully-qualified name
|
||||
callerInitOnce.Do(func() {
|
||||
logrusPackage = getPackageName(runtime.FuncForPC(pcs[0]).Name())
|
||||
|
||||
// now that we have the cache, we can skip a minimum count of known-logrus functions
|
||||
// XXX this is dubious, the number of frames may vary store an entry in a logger interface
|
||||
minimumCallerDepth = knownLogrusFrames
|
||||
})
|
||||
|
||||
for f, again := frames.Next(); again; f, again = frames.Next() {
|
||||
pkg := getPackageName(f.Function)
|
||||
|
||||
// If the caller isn't part of this package, we're done
|
||||
if pkg != logrusPackage {
|
||||
return &f
|
||||
}
|
||||
}
|
||||
|
||||
// if we got here, we failed to find the caller's context
|
||||
return nil
|
||||
}
|
||||
|
||||
func (entry Entry) HasCaller() (has bool) {
|
||||
return entry.Logger != nil &&
|
||||
entry.Logger.ReportCaller &&
|
||||
entry.Caller != nil
|
||||
}
|
||||
|
||||
// This function is not declared with a pointer value because otherwise
|
||||
|
@ -107,6 +205,9 @@ func (entry Entry) log(level Level, msg string) {
|
|||
|
||||
entry.Level = level
|
||||
entry.Message = msg
|
||||
if entry.Logger.ReportCaller {
|
||||
entry.Caller = getCaller()
|
||||
}
|
||||
|
||||
entry.fireHooks()
|
||||
|
||||
|
@ -137,9 +238,9 @@ func (entry *Entry) fireHooks() {
|
|||
}
|
||||
|
||||
func (entry *Entry) write() {
|
||||
serialized, err := entry.Logger.Formatter.Format(entry)
|
||||
entry.Logger.mu.Lock()
|
||||
defer entry.Logger.mu.Unlock()
|
||||
serialized, err := entry.Logger.Formatter.Format(entry)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
|
||||
} else {
|
||||
|
@ -150,26 +251,30 @@ func (entry *Entry) write() {
|
|||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Debug(args ...interface{}) {
|
||||
if entry.Logger.level() >= DebugLevel {
|
||||
entry.log(DebugLevel, fmt.Sprint(args...))
|
||||
func (entry *Entry) Log(level Level, args ...interface{}) {
|
||||
if entry.Logger.IsLevelEnabled(level) {
|
||||
entry.log(level, fmt.Sprint(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Trace(args ...interface{}) {
|
||||
entry.Log(TraceLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Debug(args ...interface{}) {
|
||||
entry.Log(DebugLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Print(args ...interface{}) {
|
||||
entry.Info(args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Info(args ...interface{}) {
|
||||
if entry.Logger.level() >= InfoLevel {
|
||||
entry.log(InfoLevel, fmt.Sprint(args...))
|
||||
}
|
||||
entry.Log(InfoLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Warn(args ...interface{}) {
|
||||
if entry.Logger.level() >= WarnLevel {
|
||||
entry.log(WarnLevel, fmt.Sprint(args...))
|
||||
}
|
||||
entry.Log(WarnLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Warning(args ...interface{}) {
|
||||
|
@ -177,37 +282,35 @@ func (entry *Entry) Warning(args ...interface{}) {
|
|||
}
|
||||
|
||||
func (entry *Entry) Error(args ...interface{}) {
|
||||
if entry.Logger.level() >= ErrorLevel {
|
||||
entry.log(ErrorLevel, fmt.Sprint(args...))
|
||||
}
|
||||
entry.Log(ErrorLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Fatal(args ...interface{}) {
|
||||
if entry.Logger.level() >= FatalLevel {
|
||||
entry.log(FatalLevel, fmt.Sprint(args...))
|
||||
}
|
||||
Exit(1)
|
||||
entry.Log(FatalLevel, args...)
|
||||
entry.Logger.Exit(1)
|
||||
}
|
||||
|
||||
func (entry *Entry) Panic(args ...interface{}) {
|
||||
if entry.Logger.level() >= PanicLevel {
|
||||
entry.log(PanicLevel, fmt.Sprint(args...))
|
||||
}
|
||||
entry.Log(PanicLevel, args...)
|
||||
panic(fmt.Sprint(args...))
|
||||
}
|
||||
|
||||
// Entry Printf family functions
|
||||
|
||||
func (entry *Entry) Logf(level Level, format string, args ...interface{}) {
|
||||
entry.Log(level, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
func (entry *Entry) Tracef(format string, args ...interface{}) {
|
||||
entry.Logf(TraceLevel, format, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Debugf(format string, args ...interface{}) {
|
||||
if entry.Logger.level() >= DebugLevel {
|
||||
entry.Debug(fmt.Sprintf(format, args...))
|
||||
}
|
||||
entry.Logf(DebugLevel, format, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Infof(format string, args ...interface{}) {
|
||||
if entry.Logger.level() >= InfoLevel {
|
||||
entry.Info(fmt.Sprintf(format, args...))
|
||||
}
|
||||
entry.Logf(InfoLevel, format, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Printf(format string, args ...interface{}) {
|
||||
|
@ -215,9 +318,7 @@ func (entry *Entry) Printf(format string, args ...interface{}) {
|
|||
}
|
||||
|
||||
func (entry *Entry) Warnf(format string, args ...interface{}) {
|
||||
if entry.Logger.level() >= WarnLevel {
|
||||
entry.Warn(fmt.Sprintf(format, args...))
|
||||
}
|
||||
entry.Logf(WarnLevel, format, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Warningf(format string, args ...interface{}) {
|
||||
|
@ -225,36 +326,36 @@ func (entry *Entry) Warningf(format string, args ...interface{}) {
|
|||
}
|
||||
|
||||
func (entry *Entry) Errorf(format string, args ...interface{}) {
|
||||
if entry.Logger.level() >= ErrorLevel {
|
||||
entry.Error(fmt.Sprintf(format, args...))
|
||||
}
|
||||
entry.Logf(ErrorLevel, format, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Fatalf(format string, args ...interface{}) {
|
||||
if entry.Logger.level() >= FatalLevel {
|
||||
entry.Fatal(fmt.Sprintf(format, args...))
|
||||
}
|
||||
Exit(1)
|
||||
entry.Logf(FatalLevel, format, args...)
|
||||
entry.Logger.Exit(1)
|
||||
}
|
||||
|
||||
func (entry *Entry) Panicf(format string, args ...interface{}) {
|
||||
if entry.Logger.level() >= PanicLevel {
|
||||
entry.Panic(fmt.Sprintf(format, args...))
|
||||
}
|
||||
entry.Logf(PanicLevel, format, args...)
|
||||
}
|
||||
|
||||
// Entry Println family functions
|
||||
|
||||
func (entry *Entry) Debugln(args ...interface{}) {
|
||||
if entry.Logger.level() >= DebugLevel {
|
||||
entry.Debug(entry.sprintlnn(args...))
|
||||
func (entry *Entry) Logln(level Level, args ...interface{}) {
|
||||
if entry.Logger.IsLevelEnabled(level) {
|
||||
entry.Log(level, entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Traceln(args ...interface{}) {
|
||||
entry.Logln(TraceLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Debugln(args ...interface{}) {
|
||||
entry.Logln(DebugLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Infoln(args ...interface{}) {
|
||||
if entry.Logger.level() >= InfoLevel {
|
||||
entry.Info(entry.sprintlnn(args...))
|
||||
}
|
||||
entry.Logln(InfoLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Println(args ...interface{}) {
|
||||
|
@ -262,9 +363,7 @@ func (entry *Entry) Println(args ...interface{}) {
|
|||
}
|
||||
|
||||
func (entry *Entry) Warnln(args ...interface{}) {
|
||||
if entry.Logger.level() >= WarnLevel {
|
||||
entry.Warn(entry.sprintlnn(args...))
|
||||
}
|
||||
entry.Logln(WarnLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Warningln(args ...interface{}) {
|
||||
|
@ -272,22 +371,16 @@ func (entry *Entry) Warningln(args ...interface{}) {
|
|||
}
|
||||
|
||||
func (entry *Entry) Errorln(args ...interface{}) {
|
||||
if entry.Logger.level() >= ErrorLevel {
|
||||
entry.Error(entry.sprintlnn(args...))
|
||||
}
|
||||
entry.Logln(ErrorLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Fatalln(args ...interface{}) {
|
||||
if entry.Logger.level() >= FatalLevel {
|
||||
entry.Fatal(entry.sprintlnn(args...))
|
||||
}
|
||||
Exit(1)
|
||||
entry.Logln(FatalLevel, args...)
|
||||
entry.Logger.Exit(1)
|
||||
}
|
||||
|
||||
func (entry *Entry) Panicln(args ...interface{}) {
|
||||
if entry.Logger.level() >= PanicLevel {
|
||||
entry.Panic(entry.sprintlnn(args...))
|
||||
}
|
||||
entry.Logln(PanicLevel, args...)
|
||||
}
|
||||
|
||||
// Sprintlnn => Sprint no newline. This is to get the behavior of how
|
||||
|
|
40
vendor/github.com/sirupsen/logrus/exported.go
generated
vendored
40
vendor/github.com/sirupsen/logrus/exported.go
generated
vendored
|
@ -21,30 +21,33 @@ func SetOutput(out io.Writer) {
|
|||
|
||||
// SetFormatter sets the standard logger formatter.
|
||||
func SetFormatter(formatter Formatter) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.Formatter = formatter
|
||||
std.SetFormatter(formatter)
|
||||
}
|
||||
|
||||
// SetReportCaller sets whether the standard logger will include the calling
|
||||
// method as a field.
|
||||
func SetReportCaller(include bool) {
|
||||
std.SetReportCaller(include)
|
||||
}
|
||||
|
||||
// SetLevel sets the standard logger level.
|
||||
func SetLevel(level Level) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.SetLevel(level)
|
||||
}
|
||||
|
||||
// GetLevel returns the standard logger level.
|
||||
func GetLevel() Level {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
return std.level()
|
||||
return std.GetLevel()
|
||||
}
|
||||
|
||||
// IsLevelEnabled checks if the log level of the standard logger is greater than the level param
|
||||
func IsLevelEnabled(level Level) bool {
|
||||
return std.IsLevelEnabled(level)
|
||||
}
|
||||
|
||||
// AddHook adds a hook to the standard logger hooks.
|
||||
func AddHook(hook Hook) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.Hooks.Add(hook)
|
||||
std.AddHook(hook)
|
||||
}
|
||||
|
||||
// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
|
||||
|
@ -80,6 +83,11 @@ func WithTime(t time.Time) *Entry {
|
|||
return std.WithTime(t)
|
||||
}
|
||||
|
||||
// Trace logs a message at level Trace on the standard logger.
|
||||
func Trace(args ...interface{}) {
|
||||
std.Trace(args...)
|
||||
}
|
||||
|
||||
// Debug logs a message at level Debug on the standard logger.
|
||||
func Debug(args ...interface{}) {
|
||||
std.Debug(args...)
|
||||
|
@ -120,6 +128,11 @@ func Fatal(args ...interface{}) {
|
|||
std.Fatal(args...)
|
||||
}
|
||||
|
||||
// Tracef logs a message at level Trace on the standard logger.
|
||||
func Tracef(format string, args ...interface{}) {
|
||||
std.Tracef(format, args...)
|
||||
}
|
||||
|
||||
// Debugf logs a message at level Debug on the standard logger.
|
||||
func Debugf(format string, args ...interface{}) {
|
||||
std.Debugf(format, args...)
|
||||
|
@ -160,6 +173,11 @@ func Fatalf(format string, args ...interface{}) {
|
|||
std.Fatalf(format, args...)
|
||||
}
|
||||
|
||||
// Traceln logs a message at level Trace on the standard logger.
|
||||
func Traceln(args ...interface{}) {
|
||||
std.Traceln(args...)
|
||||
}
|
||||
|
||||
// Debugln logs a message at level Debug on the standard logger.
|
||||
func Debugln(args ...interface{}) {
|
||||
std.Debugln(args...)
|
||||
|
|
33
vendor/github.com/sirupsen/logrus/formatter.go
generated
vendored
33
vendor/github.com/sirupsen/logrus/formatter.go
generated
vendored
|
@ -2,7 +2,16 @@ package logrus
|
|||
|
||||
import "time"
|
||||
|
||||
const defaultTimestampFormat = time.RFC3339
|
||||
// Default key names for the default fields
|
||||
const (
|
||||
defaultTimestampFormat = time.RFC3339
|
||||
FieldKeyMsg = "msg"
|
||||
FieldKeyLevel = "level"
|
||||
FieldKeyTime = "time"
|
||||
FieldKeyLogrusError = "logrus_error"
|
||||
FieldKeyFunc = "func"
|
||||
FieldKeyFile = "file"
|
||||
)
|
||||
|
||||
// The Formatter interface is used to implement a custom Formatter. It takes an
|
||||
// `Entry`. It exposes all the fields, including the default ones:
|
||||
|
@ -18,7 +27,7 @@ type Formatter interface {
|
|||
Format(*Entry) ([]byte, error)
|
||||
}
|
||||
|
||||
// This is to not silently overwrite `time`, `msg` and `level` fields when
|
||||
// This is to not silently overwrite `time`, `msg`, `func` and `level` fields when
|
||||
// dumping it. If this code wasn't there doing:
|
||||
//
|
||||
// logrus.WithField("level", 1).Info("hello")
|
||||
|
@ -30,7 +39,7 @@ 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, fieldMap FieldMap) {
|
||||
func prefixFieldClashes(data Fields, fieldMap FieldMap, reportCaller bool) {
|
||||
timeKey := fieldMap.resolve(FieldKeyTime)
|
||||
if t, ok := data[timeKey]; ok {
|
||||
data["fields."+timeKey] = t
|
||||
|
@ -48,4 +57,22 @@ func prefixFieldClashes(data Fields, fieldMap FieldMap) {
|
|||
data["fields."+levelKey] = l
|
||||
delete(data, levelKey)
|
||||
}
|
||||
|
||||
logrusErrKey := fieldMap.resolve(FieldKeyLogrusError)
|
||||
if l, ok := data[logrusErrKey]; ok {
|
||||
data["fields."+logrusErrKey] = l
|
||||
delete(data, logrusErrKey)
|
||||
}
|
||||
|
||||
// If reportCaller is not set, 'func' will not conflict.
|
||||
if reportCaller {
|
||||
funcKey := fieldMap.resolve(FieldKeyFunc)
|
||||
if l, ok := data[funcKey]; ok {
|
||||
data["fields."+funcKey] = l
|
||||
}
|
||||
fileKey := fieldMap.resolve(FieldKeyFile)
|
||||
if l, ok := data[fileKey]; ok {
|
||||
data["fields."+fileKey] = l
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
44
vendor/github.com/sirupsen/logrus/json_formatter.go
generated
vendored
44
vendor/github.com/sirupsen/logrus/json_formatter.go
generated
vendored
|
@ -1,6 +1,7 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
@ -10,13 +11,6 @@ type fieldKey string
|
|||
// FieldMap allows customization of the key names for default fields.
|
||||
type FieldMap map[fieldKey]string
|
||||
|
||||
// Default key names for the default fields
|
||||
const (
|
||||
FieldKeyMsg = "msg"
|
||||
FieldKeyLevel = "level"
|
||||
FieldKeyTime = "time"
|
||||
)
|
||||
|
||||
func (f FieldMap) resolve(key fieldKey) string {
|
||||
if k, ok := f[key]; ok {
|
||||
return k
|
||||
|
@ -40,17 +34,21 @@ type JSONFormatter struct {
|
|||
// As an example:
|
||||
// formatter := &JSONFormatter{
|
||||
// FieldMap: FieldMap{
|
||||
// FieldKeyTime: "@timestamp",
|
||||
// FieldKeyTime: "@timestamp",
|
||||
// FieldKeyLevel: "@level",
|
||||
// FieldKeyMsg: "@message",
|
||||
// FieldKeyMsg: "@message",
|
||||
// FieldKeyFunc: "@caller",
|
||||
// },
|
||||
// }
|
||||
FieldMap FieldMap
|
||||
|
||||
// PrettyPrint will indent all json logs
|
||||
PrettyPrint bool
|
||||
}
|
||||
|
||||
// Format renders a single log entry
|
||||
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||
data := make(Fields, len(entry.Data)+3)
|
||||
data := make(Fields, len(entry.Data)+4)
|
||||
for k, v := range entry.Data {
|
||||
switch v := v.(type) {
|
||||
case error:
|
||||
|
@ -68,22 +66,40 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
|||
data = newData
|
||||
}
|
||||
|
||||
prefixFieldClashes(data, f.FieldMap)
|
||||
prefixFieldClashes(data, f.FieldMap, entry.HasCaller())
|
||||
|
||||
timestampFormat := f.TimestampFormat
|
||||
if timestampFormat == "" {
|
||||
timestampFormat = defaultTimestampFormat
|
||||
}
|
||||
|
||||
if entry.err != "" {
|
||||
data[f.FieldMap.resolve(FieldKeyLogrusError)] = entry.err
|
||||
}
|
||||
if !f.DisableTimestamp {
|
||||
data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat)
|
||||
}
|
||||
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
|
||||
data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
|
||||
if entry.HasCaller() {
|
||||
data[f.FieldMap.resolve(FieldKeyFunc)] = entry.Caller.Function
|
||||
data[f.FieldMap.resolve(FieldKeyFile)] = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
||||
}
|
||||
|
||||
serialized, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
var b *bytes.Buffer
|
||||
if entry.Buffer != nil {
|
||||
b = entry.Buffer
|
||||
} else {
|
||||
b = &bytes.Buffer{}
|
||||
}
|
||||
|
||||
encoder := json.NewEncoder(b)
|
||||
if f.PrettyPrint {
|
||||
encoder.SetIndent("", " ")
|
||||
}
|
||||
if err := encoder.Encode(data); err != nil {
|
||||
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
||||
}
|
||||
return append(serialized, '\n'), nil
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
|
222
vendor/github.com/sirupsen/logrus/logger.go
generated
vendored
222
vendor/github.com/sirupsen/logrus/logger.go
generated
vendored
|
@ -11,7 +11,7 @@ import (
|
|||
type Logger struct {
|
||||
// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
|
||||
// file, or leave it default which is `os.Stderr`. You can also set this to
|
||||
// something more adventorous, such as logging to Kafka.
|
||||
// something more adventurous, such as logging to Kafka.
|
||||
Out io.Writer
|
||||
// Hooks for the logger instance. These allow firing events based on logging
|
||||
// levels and log entries. For example, to send errors to an error tracking
|
||||
|
@ -24,6 +24,10 @@ type Logger struct {
|
|||
// own that implements the `Formatter` interface, see the `README` or included
|
||||
// formatters for examples.
|
||||
Formatter Formatter
|
||||
|
||||
// Flag for whether to log caller info (off by default)
|
||||
ReportCaller bool
|
||||
|
||||
// The logging level the logger should log at. This is typically (and defaults
|
||||
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
|
||||
// logged.
|
||||
|
@ -32,8 +36,12 @@ type Logger struct {
|
|||
mu MutexWrap
|
||||
// Reusable empty entry
|
||||
entryPool sync.Pool
|
||||
// Function to exit the application, defaults to `os.Exit()`
|
||||
ExitFunc exitFunc
|
||||
}
|
||||
|
||||
type exitFunc func(int)
|
||||
|
||||
type MutexWrap struct {
|
||||
lock sync.Mutex
|
||||
disabled bool
|
||||
|
@ -69,10 +77,12 @@ func (mw *MutexWrap) Disable() {
|
|||
// It's recommended to make this a global instance called `log`.
|
||||
func New() *Logger {
|
||||
return &Logger{
|
||||
Out: os.Stderr,
|
||||
Formatter: new(TextFormatter),
|
||||
Hooks: make(LevelHooks),
|
||||
Level: InfoLevel,
|
||||
Out: os.Stderr,
|
||||
Formatter: new(TextFormatter),
|
||||
Hooks: make(LevelHooks),
|
||||
Level: InfoLevel,
|
||||
ExitFunc: os.Exit,
|
||||
ReportCaller: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,6 +95,7 @@ func (logger *Logger) newEntry() *Entry {
|
|||
}
|
||||
|
||||
func (logger *Logger) releaseEntry(entry *Entry) {
|
||||
entry.Data = map[string]interface{}{}
|
||||
logger.entryPool.Put(entry)
|
||||
}
|
||||
|
||||
|
@ -120,20 +131,24 @@ func (logger *Logger) WithTime(t time.Time) *Entry {
|
|||
return entry.WithTime(t)
|
||||
}
|
||||
|
||||
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
||||
if logger.level() >= DebugLevel {
|
||||
func (logger *Logger) Logf(level Level, format string, args ...interface{}) {
|
||||
if logger.IsLevelEnabled(level) {
|
||||
entry := logger.newEntry()
|
||||
entry.Debugf(format, args...)
|
||||
entry.Logf(level, format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Tracef(format string, args ...interface{}) {
|
||||
logger.Logf(TraceLevel, format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
||||
logger.Logf(DebugLevel, format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Infof(format string, args ...interface{}) {
|
||||
if logger.level() >= InfoLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Infof(format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Logf(InfoLevel, format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Printf(format string, args ...interface{}) {
|
||||
|
@ -143,60 +158,44 @@ func (logger *Logger) Printf(format string, args ...interface{}) {
|
|||
}
|
||||
|
||||
func (logger *Logger) Warnf(format string, args ...interface{}) {
|
||||
if logger.level() >= WarnLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Warnf(format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Logf(WarnLevel, format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Warningf(format string, args ...interface{}) {
|
||||
if logger.level() >= WarnLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Warnf(format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Warnf(format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Errorf(format string, args ...interface{}) {
|
||||
if logger.level() >= ErrorLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Errorf(format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Logf(ErrorLevel, format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
||||
if logger.level() >= FatalLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Fatalf(format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
Exit(1)
|
||||
logger.Logf(FatalLevel, format, args...)
|
||||
logger.Exit(1)
|
||||
}
|
||||
|
||||
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
||||
if logger.level() >= PanicLevel {
|
||||
logger.Logf(PanicLevel, format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Log(level Level, args ...interface{}) {
|
||||
if logger.IsLevelEnabled(level) {
|
||||
entry := logger.newEntry()
|
||||
entry.Panicf(format, args...)
|
||||
entry.Log(level, args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Trace(args ...interface{}) {
|
||||
logger.Log(TraceLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Debug(args ...interface{}) {
|
||||
if logger.level() >= DebugLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Debug(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Log(DebugLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Info(args ...interface{}) {
|
||||
if logger.level() >= InfoLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Info(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Log(InfoLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Print(args ...interface{}) {
|
||||
|
@ -206,60 +205,44 @@ func (logger *Logger) Print(args ...interface{}) {
|
|||
}
|
||||
|
||||
func (logger *Logger) Warn(args ...interface{}) {
|
||||
if logger.level() >= WarnLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Warn(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Log(WarnLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Warning(args ...interface{}) {
|
||||
if logger.level() >= WarnLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Warn(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Warn(args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Error(args ...interface{}) {
|
||||
if logger.level() >= ErrorLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Error(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Log(ErrorLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Fatal(args ...interface{}) {
|
||||
if logger.level() >= FatalLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Fatal(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
Exit(1)
|
||||
logger.Log(FatalLevel, args...)
|
||||
logger.Exit(1)
|
||||
}
|
||||
|
||||
func (logger *Logger) Panic(args ...interface{}) {
|
||||
if logger.level() >= PanicLevel {
|
||||
logger.Log(PanicLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Logln(level Level, args ...interface{}) {
|
||||
if logger.IsLevelEnabled(level) {
|
||||
entry := logger.newEntry()
|
||||
entry.Panic(args...)
|
||||
entry.Logln(level, args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Traceln(args ...interface{}) {
|
||||
logger.Logln(TraceLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Debugln(args ...interface{}) {
|
||||
if logger.level() >= DebugLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Debugln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Logln(DebugLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Infoln(args ...interface{}) {
|
||||
if logger.level() >= InfoLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Infoln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Logln(InfoLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Println(args ...interface{}) {
|
||||
|
@ -269,44 +252,32 @@ func (logger *Logger) Println(args ...interface{}) {
|
|||
}
|
||||
|
||||
func (logger *Logger) Warnln(args ...interface{}) {
|
||||
if logger.level() >= WarnLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Warnln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Logln(WarnLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Warningln(args ...interface{}) {
|
||||
if logger.level() >= WarnLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Warnln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Warn(args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Errorln(args ...interface{}) {
|
||||
if logger.level() >= ErrorLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Errorln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Logln(ErrorLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Fatalln(args ...interface{}) {
|
||||
if logger.level() >= FatalLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Fatalln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
Exit(1)
|
||||
logger.Logln(FatalLevel, args...)
|
||||
logger.Exit(1)
|
||||
}
|
||||
|
||||
func (logger *Logger) Panicln(args ...interface{}) {
|
||||
if logger.level() >= PanicLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Panicln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
logger.Logln(PanicLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Exit(code int) {
|
||||
runHandlers()
|
||||
if logger.ExitFunc == nil {
|
||||
logger.ExitFunc = os.Exit
|
||||
}
|
||||
logger.ExitFunc(code)
|
||||
}
|
||||
|
||||
//When file is opened with appending mode, it's safe to
|
||||
|
@ -320,18 +291,53 @@ func (logger *Logger) level() Level {
|
|||
return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
|
||||
}
|
||||
|
||||
// SetLevel sets the logger 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
|
||||
// GetLevel returns the logger level.
|
||||
func (logger *Logger) GetLevel() Level {
|
||||
return logger.level()
|
||||
}
|
||||
|
||||
// AddHook adds a hook to the logger hooks.
|
||||
func (logger *Logger) AddHook(hook Hook) {
|
||||
logger.mu.Lock()
|
||||
defer logger.mu.Unlock()
|
||||
logger.Hooks.Add(hook)
|
||||
}
|
||||
|
||||
// IsLevelEnabled checks if the log level of the logger is greater than the level param
|
||||
func (logger *Logger) IsLevelEnabled(level Level) bool {
|
||||
return logger.level() >= level
|
||||
}
|
||||
|
||||
// SetFormatter sets the logger formatter.
|
||||
func (logger *Logger) SetFormatter(formatter Formatter) {
|
||||
logger.mu.Lock()
|
||||
defer logger.mu.Unlock()
|
||||
logger.Formatter = formatter
|
||||
}
|
||||
|
||||
// SetOutput sets the logger output.
|
||||
func (logger *Logger) SetOutput(output io.Writer) {
|
||||
logger.mu.Lock()
|
||||
defer logger.mu.Unlock()
|
||||
logger.Out = output
|
||||
}
|
||||
|
||||
func (logger *Logger) SetReportCaller(reportCaller bool) {
|
||||
logger.mu.Lock()
|
||||
defer logger.mu.Unlock()
|
||||
logger.ReportCaller = reportCaller
|
||||
}
|
||||
|
||||
// ReplaceHooks replaces the logger hooks and returns the old ones
|
||||
func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks {
|
||||
logger.mu.Lock()
|
||||
oldHooks := logger.Hooks
|
||||
logger.Hooks = hooks
|
||||
logger.mu.Unlock()
|
||||
return oldHooks
|
||||
}
|
||||
|
|
75
vendor/github.com/sirupsen/logrus/logrus.go
generated
vendored
75
vendor/github.com/sirupsen/logrus/logrus.go
generated
vendored
|
@ -14,22 +14,11 @@ type Level uint32
|
|||
|
||||
// Convert the Level to a string. E.g. PanicLevel becomes "panic".
|
||||
func (level Level) String() string {
|
||||
switch level {
|
||||
case DebugLevel:
|
||||
return "debug"
|
||||
case InfoLevel:
|
||||
return "info"
|
||||
case WarnLevel:
|
||||
return "warning"
|
||||
case ErrorLevel:
|
||||
return "error"
|
||||
case FatalLevel:
|
||||
return "fatal"
|
||||
case PanicLevel:
|
||||
return "panic"
|
||||
if b, err := level.MarshalText(); err == nil {
|
||||
return string(b)
|
||||
} else {
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// ParseLevel takes a string level and returns the Logrus log level constant.
|
||||
|
@ -47,12 +36,47 @@ func ParseLevel(lvl string) (Level, error) {
|
|||
return InfoLevel, nil
|
||||
case "debug":
|
||||
return DebugLevel, nil
|
||||
case "trace":
|
||||
return TraceLevel, nil
|
||||
}
|
||||
|
||||
var l Level
|
||||
return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
|
||||
}
|
||||
|
||||
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||
func (level *Level) UnmarshalText(text []byte) error {
|
||||
l, err := ParseLevel(string(text))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*level = Level(l)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (level Level) MarshalText() ([]byte, error) {
|
||||
switch level {
|
||||
case TraceLevel:
|
||||
return []byte("trace"), nil
|
||||
case DebugLevel:
|
||||
return []byte("debug"), nil
|
||||
case InfoLevel:
|
||||
return []byte("info"), nil
|
||||
case WarnLevel:
|
||||
return []byte("warning"), nil
|
||||
case ErrorLevel:
|
||||
return []byte("error"), nil
|
||||
case FatalLevel:
|
||||
return []byte("fatal"), nil
|
||||
case PanicLevel:
|
||||
return []byte("panic"), nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("not a valid lorus level %q", level)
|
||||
}
|
||||
|
||||
// A constant exposing all logging levels
|
||||
var AllLevels = []Level{
|
||||
PanicLevel,
|
||||
|
@ -61,6 +85,7 @@ var AllLevels = []Level{
|
|||
WarnLevel,
|
||||
InfoLevel,
|
||||
DebugLevel,
|
||||
TraceLevel,
|
||||
}
|
||||
|
||||
// These are the different logging levels. You can set the logging level to log
|
||||
|
@ -69,7 +94,7 @@ const (
|
|||
// PanicLevel level, highest level of severity. Logs and then calls panic with the
|
||||
// message passed to Debug, Info, ...
|
||||
PanicLevel Level = iota
|
||||
// FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the
|
||||
// FatalLevel level. Logs and then calls `logger.Exit(1)`. It will exit even if the
|
||||
// logging level is set to Panic.
|
||||
FatalLevel
|
||||
// ErrorLevel level. Logs. Used for errors that should definitely be noted.
|
||||
|
@ -82,6 +107,8 @@ const (
|
|||
InfoLevel
|
||||
// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
|
||||
DebugLevel
|
||||
// TraceLevel level. Designates finer-grained informational events than the Debug.
|
||||
TraceLevel
|
||||
)
|
||||
|
||||
// Won't compile if StdLogger can't be realized by a log.Logger
|
||||
|
@ -140,4 +167,20 @@ type FieldLogger interface {
|
|||
Errorln(args ...interface{})
|
||||
Fatalln(args ...interface{})
|
||||
Panicln(args ...interface{})
|
||||
|
||||
// IsDebugEnabled() bool
|
||||
// IsInfoEnabled() bool
|
||||
// IsWarnEnabled() bool
|
||||
// IsErrorEnabled() bool
|
||||
// IsFatalEnabled() bool
|
||||
// IsPanicEnabled() bool
|
||||
}
|
||||
|
||||
// Ext1FieldLogger (the first extension to FieldLogger) is superfluous, it is
|
||||
// here for consistancy. Do not use. Use Logger or Entry instead.
|
||||
type Ext1FieldLogger interface {
|
||||
FieldLogger
|
||||
Tracef(format string, args ...interface{})
|
||||
Trace(args ...interface{})
|
||||
Traceln(args ...interface{})
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue