Skip to content

Commit

Permalink
logging: new mode -l passthrough
Browse files Browse the repository at this point in the history
it allows to pass the current std streams down to the container.

conmon support: containers/conmon#289

[NO TESTS NEEDED] it needs a new conmon.

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
  • Loading branch information
giuseppe committed Sep 9, 2021
1 parent 2352737 commit 401583c
Show file tree
Hide file tree
Showing 13 changed files with 71 additions and 24 deletions.
4 changes: 2 additions & 2 deletions cmd/podman/common/completion.go
Expand Up @@ -777,10 +777,10 @@ func AutocompleteImageVolume(cmd *cobra.Command, args []string, toComplete strin
}

// AutocompleteLogDriver - Autocomplete log-driver options.
// -> "journald", "none", "k8s-file"
// -> "journald", "none", "k8s-file", "passthrough"
func AutocompleteLogDriver(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
// don't show json-file
logDrivers := []string{define.JournaldLogging, define.NoLogging, define.KubernetesLogging}
logDrivers := []string{define.JournaldLogging, define.NoLogging, define.KubernetesLogging, define.PassthroughLogging}
return logDrivers, cobra.ShellCompDirectiveNoFileComp
}

Expand Down
13 changes: 12 additions & 1 deletion cmd/podman/containers/create.go
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/specgenutil"
"github.com/containers/podman/v3/pkg/util"
"github.com/mattn/go-isatty"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -161,7 +162,9 @@ func create(cmd *cobra.Command, args []string) error {
}
}

fmt.Println(report.Id)
if cliVals.LogDriver != define.PassthroughLogging {
fmt.Println(report.Id)
}
return nil
}

Expand All @@ -188,6 +191,14 @@ func CreateInit(c *cobra.Command, vals entities.ContainerCreateOptions, isInfra
vals.UserNS = "private"
}
}
if cliVals.LogDriver == define.PassthroughLogging {
if isatty.IsTerminal(0) || isatty.IsTerminal(1) || isatty.IsTerminal(2) {
return vals, errors.New("the '--log-driver passthrough' option cannot be used on a TTY")
}
if registry.IsRemote() {
return vals, errors.New("the '--log-driver passthrough' option is not supported in remote mode")
}
}

if !isInfra {
if c.Flag("shm-size").Changed {
Expand Down
8 changes: 7 additions & 1 deletion cmd/podman/containers/run.go
Expand Up @@ -158,8 +158,13 @@ func run(cmd *cobra.Command, args []string) error {
runOpts.InputStream = nil
}

passthrough := cliVals.LogDriver == define.PassthroughLogging

// If attach is set, clear stdin/stdout/stderr and only attach requested
if cmd.Flag("attach").Changed {
if passthrough {
return errors.Wrapf(define.ErrInvalidArg, "cannot specify --attach with --log-driver=passthrough")
}
runOpts.OutputStream = nil
runOpts.ErrorStream = nil
if !cliVals.Interactive {
Expand All @@ -179,6 +184,7 @@ func run(cmd *cobra.Command, args []string) error {
}
}
}

cliVals.PreserveFDs = runOpts.PreserveFDs
s := specgen.NewSpecGenerator(imageName, cliVals.RootFS)
if err := specgenutil.FillOutSpecGen(s, &cliVals, args); err != nil {
Expand All @@ -200,7 +206,7 @@ func run(cmd *cobra.Command, args []string) error {
return err
}

if runOpts.Detach {
if runOpts.Detach && !passthrough {
fmt.Println(report.Id)
return nil
}
Expand Down
6 changes: 5 additions & 1 deletion docs/source/markdown/podman-create.1.md
Expand Up @@ -513,7 +513,11 @@ Not implemented

#### **--log-driver**="*k8s-file*"

Logging driver for the container. Currently available options are *k8s-file*, *journald*, and *none*, with *json-file* aliased to *k8s-file* for scripting compatibility.
Logging driver for the container. Currently available options are *k8s-file*, *journald*, *none* and *passthrough*, with *json-file* aliased to *k8s-file* for scripting compatibility.

The *passthrough* driver passes down the standard streams (stdin, stdout, stderr) to the
container. It is not allowed with the remote Podman client and on a tty, since it is
vulnerable to attacks via TIOCSTI.

#### **--log-opt**=*name*=*value*

Expand Down
7 changes: 6 additions & 1 deletion docs/source/markdown/podman-run.1.md
Expand Up @@ -538,7 +538,12 @@ Not implemented.

#### **--log-driver**="*driver*"

Logging driver for the container. Currently available options are **k8s-file**, **journald**, and **none**, with **json-file** aliased to **k8s-file** for scripting compatibility.
Logging driver for the container. Currently available options are **k8s-file**, **journald**, **none** and **passthrough**, with **json-file** aliased to **k8s-file** for scripting compatibility.

The **passthrough** driver passes down the standard streams (stdin, stdout, stderr) to the
container. It is not allowed with the remote Podman client and on a tty, since it is
vulnerable to attacks via TIOCSTI.


#### **--log-opt**=*name*=*value*

Expand Down
1 change: 1 addition & 0 deletions go.mod
Expand Up @@ -41,6 +41,7 @@ require (
github.com/hpcloud/tail v1.0.0
github.com/json-iterator/go v1.1.11
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-isatty v0.0.12
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635
github.com/mrunalp/fileutils v0.5.0
github.com/onsi/ginkgo v1.16.4
Expand Down
4 changes: 4 additions & 0 deletions libpod/container_api.go
Expand Up @@ -229,6 +229,10 @@ func (c *Container) Kill(signal uint) error {
// This function returns when the attach finishes. It does not hold the lock for
// the duration of its runtime, only using it at the beginning to verify state.
func (c *Container) Attach(streams *define.AttachStreams, keys string, resize <-chan define.TerminalSize) error {
switch c.LogDriver() {
case define.PassthroughLogging:
return errors.Wrapf(define.ErrNoLogs, "this container is using the 'passthrough' log driver, cannot attach")
}
if !c.batched {
c.lock.Lock()
if err := c.syncContainer(); err != nil {
Expand Down
4 changes: 3 additions & 1 deletion libpod/container_log.go
Expand Up @@ -18,7 +18,7 @@ import (
var logDrivers []string

func init() {
logDrivers = append(logDrivers, define.KubernetesLogging, define.NoLogging)
logDrivers = append(logDrivers, define.KubernetesLogging, define.NoLogging, define.PassthroughLogging)
}

// Log is a runtime function that can read one or more container logs.
Expand All @@ -34,6 +34,8 @@ func (r *Runtime) Log(ctx context.Context, containers []*Container, options *log
// ReadLog reads a containers log based on the input options and returns log lines over a channel.
func (c *Container) ReadLog(ctx context.Context, options *logs.LogOptions, logChannel chan *logs.LogLine) error {
switch c.LogDriver() {
case define.PassthroughLogging:
return errors.Wrapf(define.ErrNoLogs, "this container is using the 'passthrough' log driver, cannot read logs")
case define.NoLogging:
return errors.Wrapf(define.ErrNoLogs, "this container is using the 'none' log driver, cannot read logs")
case define.JournaldLogging:
Expand Down
3 changes: 3 additions & 0 deletions libpod/define/config.go
Expand Up @@ -78,6 +78,9 @@ const JSONLogging = "json-file"
// NoLogging is the string conmon expects when specifying to use no log driver whatsoever
const NoLogging = "none"

// PassthroughLogging is the string conmon expects when specifying to use the passthrough driver
const PassthroughLogging = "passthrough"

// Strings used for --sdnotify option to podman
const (
SdNotifyModeContainer = "container"
Expand Down
39 changes: 24 additions & 15 deletions libpod/oci_attach_linux.go
Expand Up @@ -40,7 +40,9 @@ func openUnixSocket(path string) (*net.UnixConn, error) {
// Does not check if state is appropriate
// started is only required if startContainer is true
func (c *Container) attach(streams *define.AttachStreams, keys string, resize <-chan define.TerminalSize, startContainer bool, started chan bool, attachRdy chan<- bool) error {
if !streams.AttachOutput && !streams.AttachError && !streams.AttachInput {
passthrough := c.LogDriver() == define.PassthroughLogging

if !streams.AttachOutput && !streams.AttachError && !streams.AttachInput && !passthrough {
return errors.Wrapf(define.ErrInvalidArg, "must provide at least one stream to attach to")
}
if startContainer && started == nil {
Expand All @@ -52,24 +54,27 @@ func (c *Container) attach(streams *define.AttachStreams, keys string, resize <-
return err
}

logrus.Debugf("Attaching to container %s", c.ID())
var conn *net.UnixConn
if !passthrough {
logrus.Debugf("Attaching to container %s", c.ID())

registerResizeFunc(resize, c.bundlePath())
registerResizeFunc(resize, c.bundlePath())

attachSock, err := c.AttachSocketPath()
if err != nil {
return err
}
attachSock, err := c.AttachSocketPath()
if err != nil {
return err
}

conn, err := openUnixSocket(attachSock)
if err != nil {
return errors.Wrapf(err, "failed to connect to container's attach socket: %v", attachSock)
}
defer func() {
if err := conn.Close(); err != nil {
logrus.Errorf("unable to close socket: %q", err)
conn, err = openUnixSocket(attachSock)
if err != nil {
return errors.Wrapf(err, "failed to connect to container's attach socket: %v", attachSock)
}
}()
defer func() {
if err := conn.Close(); err != nil {
logrus.Errorf("unable to close socket: %q", err)
}
}()
}

// If starting was requested, start the container and notify when that's
// done.
Expand All @@ -80,6 +85,10 @@ func (c *Container) attach(streams *define.AttachStreams, keys string, resize <-
started <- true
}

if passthrough {
return nil
}

receiveStdoutError, stdinDone := setupStdioChannels(streams, conn, detachKeys)
if attachRdy != nil {
attachRdy <- true
Expand Down
2 changes: 2 additions & 0 deletions libpod/oci_conmon_linux.go
Expand Up @@ -1285,6 +1285,8 @@ func (r *ConmonOCIRuntime) sharedConmonArgs(ctr *Container, cuuid, bundlePath, p
logDriverArg = define.JournaldLogging
case define.NoLogging:
logDriverArg = define.NoLogging
case define.PassthroughLogging:
logDriverArg = define.PassthroughLogging
case define.JSONLogging:
fallthrough
//lint:ignore ST1015 the default case has to be here
Expand Down
2 changes: 1 addition & 1 deletion libpod/options.go
Expand Up @@ -1114,7 +1114,7 @@ func WithLogDriver(driver string) CtrCreateOption {
switch driver {
case "":
return errors.Wrapf(define.ErrInvalidArg, "log driver must be set")
case define.JournaldLogging, define.KubernetesLogging, define.JSONLogging, define.NoLogging:
case define.JournaldLogging, define.KubernetesLogging, define.JSONLogging, define.NoLogging, define.PassthroughLogging:
break
default:
return errors.Wrapf(define.ErrInvalidArg, "invalid log driver")
Expand Down
2 changes: 1 addition & 1 deletion libpod/runtime_ctr.go
Expand Up @@ -474,7 +474,7 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai
}

switch ctr.config.LogDriver {
case define.NoLogging:
case define.NoLogging, define.PassthroughLogging:
break
case define.JournaldLogging:
ctr.initializeJournal(ctx)
Expand Down

0 comments on commit 401583c

Please sign in to comment.