diff options
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/adapter/containers.go | 27 | ||||
-rw-r--r-- | pkg/adapter/containers_remote.go | 47 | ||||
-rw-r--r-- | pkg/inspect/inspect.go | 1 | ||||
-rw-r--r-- | pkg/rootless/rootless_linux.go | 2 | ||||
-rw-r--r-- | pkg/spec/createconfig.go | 2 | ||||
-rw-r--r-- | pkg/util/utils.go | 57 | ||||
-rw-r--r-- | pkg/varlinkapi/containers.go | 54 |
7 files changed, 156 insertions, 34 deletions
diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go index 756369196..932d209cd 100644 --- a/pkg/adapter/containers.go +++ b/pkg/adapter/containers.go @@ -4,7 +4,9 @@ package adapter import ( "context" + "fmt" "strconv" + "sync" "syscall" "time" @@ -127,3 +129,28 @@ func (r *LocalRuntime) WaitOnContainers(ctx context.Context, cli *cliconfig.Wait } return ok, failures, err } + +// Log logs one or more containers +func (r *LocalRuntime) Log(c *cliconfig.LogsValues, options *libpod.LogOptions) error { + var wg sync.WaitGroup + options.WaitGroup = &wg + if len(c.InputArgs) > 1 { + options.Multi = true + } + logChannel := make(chan *libpod.LogLine, int(c.Tail)*len(c.InputArgs)+1) + containers, err := shortcuts.GetContainersByContext(false, c.Latest, c.InputArgs, r.Runtime) + if err != nil { + return err + } + if err := r.Runtime.Log(containers, options, logChannel); err != nil { + return err + } + go func() { + wg.Wait() + close(logChannel) + }() + for line := range logChannel { + fmt.Println(line.String(options)) + } + return nil +} diff --git a/pkg/adapter/containers_remote.go b/pkg/adapter/containers_remote.go index 5646d2297..a8146567a 100644 --- a/pkg/adapter/containers_remote.go +++ b/pkg/adapter/containers_remote.go @@ -5,18 +5,19 @@ package adapter import ( "context" "encoding/json" - "errors" + "fmt" "strconv" "syscall" "time" "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/shared" - "github.com/sirupsen/logrus" - - iopodman "github.com/containers/libpod/cmd/podman/varlink" + "github.com/containers/libpod/cmd/podman/varlink" "github.com/containers/libpod/libpod" "github.com/containers/libpod/pkg/inspect" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "github.com/varlink/go/varlink" ) // Inspect returns an inspect struct from varlink @@ -223,3 +224,41 @@ func BatchContainerOp(ctr *Container, opts shared.PsOptions) (shared.BatchContai } return bcs, nil } + +// Logs one or more containers over a varlink connection +func (r *LocalRuntime) Log(c *cliconfig.LogsValues, options *libpod.LogOptions) error { + //GetContainersLogs + reply, err := iopodman.GetContainersLogs().Send(r.Conn, uint64(varlink.More), c.InputArgs, c.Follow, c.Latest, options.Since.Format(time.RFC3339Nano), int64(c.Tail), c.Timestamps) + if err != nil { + return errors.Wrapf(err, "failed to get container logs") + } + if len(c.InputArgs) > 1 { + options.Multi = true + } + for { + log, flags, err := reply() + if err != nil { + return err + } + if log.Time == "" && log.Msg == "" { + // We got a blank log line which can signal end of stream + break + } + lTime, err := time.Parse(time.RFC3339Nano, log.Time) + if err != nil { + return errors.Wrapf(err, "unable to parse time of log %s", log.Time) + } + logLine := libpod.LogLine{ + Device: log.Device, + ParseLogType: log.ParseLogType, + Time: lTime, + Msg: log.Msg, + CID: log.Cid, + } + fmt.Println(logLine.String(options)) + if flags&varlink.Continues == 0 { + break + } + } + return nil +} diff --git a/pkg/inspect/inspect.go b/pkg/inspect/inspect.go index 82fe37f18..270e431ad 100644 --- a/pkg/inspect/inspect.go +++ b/pkg/inspect/inspect.go @@ -158,6 +158,7 @@ type ContainerInspectData struct { HostsPath string `json:"HostsPath"` StaticDir string `json:"StaticDir"` LogPath string `json:"LogPath"` + ConmonPidFile string `json:"ConmonPidFile"` Name string `json:"Name"` RestartCount int32 `json:"RestartCount"` //TODO Driver string `json:"Driver"` diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go index b2677f7d9..baceebee3 100644 --- a/pkg/rootless/rootless_linux.go +++ b/pkg/rootless/rootless_linux.go @@ -72,7 +72,7 @@ func GetRootlessUID() int { u, _ := strconv.Atoi(uidEnv) return u } - return os.Getuid() + return os.Geteuid() } func tryMappingTool(tool string, pid int, hostID int, mappings []idtools.IDMap) error { diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go index a61c88d58..118fbad72 100644 --- a/pkg/spec/createconfig.go +++ b/pkg/spec/createconfig.go @@ -363,7 +363,7 @@ func (c *CreateConfig) createExitCommand() []string { command = append(command, []string{"--storage-driver", config.StorageConfig.GraphDriverName}...) } if c.Syslog { - command = append(command, "--syslog") + command = append(command, "--syslog", "true") } command = append(command, []string{"container", "cleanup"}...) diff --git a/pkg/util/utils.go b/pkg/util/utils.go index d7e1ddd38..a408ad34b 100644 --- a/pkg/util/utils.go +++ b/pkg/util/utils.go @@ -190,15 +190,15 @@ func GetRootlessRuntimeDir() (string, error) { tmpDir := filepath.Join("/run", "user", uid) os.MkdirAll(tmpDir, 0700) st, err := os.Stat(tmpDir) - if err == nil && int(st.Sys().(*syscall.Stat_t).Uid) == os.Getuid() && st.Mode().Perm() == 0700 { + if err == nil && int(st.Sys().(*syscall.Stat_t).Uid) == os.Geteuid() && st.Mode().Perm() == 0700 { runtimeDir = tmpDir } } if runtimeDir == "" { - tmpDir := filepath.Join(os.TempDir(), "user", uid) + tmpDir := filepath.Join(os.TempDir(), fmt.Sprintf("run-%s", uid)) os.MkdirAll(tmpDir, 0700) st, err := os.Stat(tmpDir) - if err == nil && int(st.Sys().(*syscall.Stat_t).Uid) == os.Getuid() && st.Mode().Perm() == 0700 { + if err == nil && int(st.Sys().(*syscall.Stat_t).Uid) == os.Geteuid() && st.Mode().Perm() == 0700 { runtimeDir = tmpDir } } @@ -311,36 +311,37 @@ func GetDefaultStoreOptions() (storage.StoreOptions, error) { storageOpts = storage.StoreOptions{} storage.ReloadConfigurationFile(storageConf, &storageOpts) } - - if rootless.IsRootless() { - if os.IsNotExist(err) { - os.MkdirAll(filepath.Dir(storageConf), 0755) - file, err := os.OpenFile(storageConf, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666) - if err != nil { - return storageOpts, errors.Wrapf(err, "cannot open %s", storageConf) - } - - tomlConfiguration := getTomlStorage(&storageOpts) - defer file.Close() - enc := toml.NewEncoder(file) - if err := enc.Encode(tomlConfiguration); err != nil { - os.Remove(storageConf) - } - } else if err == nil { - // If the file did not specify a graphroot or runroot, - // set sane defaults so we don't try and use root-owned - // directories - if storageOpts.RunRoot == "" { - storageOpts.RunRoot = defaultRootlessRunRoot - } - if storageOpts.GraphRoot == "" { - storageOpts.GraphRoot = defaultRootlessGraphRoot - } + if rootless.IsRootless() && err == nil { + // If the file did not specify a graphroot or runroot, + // set sane defaults so we don't try and use root-owned + // directories + if storageOpts.RunRoot == "" { + storageOpts.RunRoot = defaultRootlessRunRoot + } + if storageOpts.GraphRoot == "" { + storageOpts.GraphRoot = defaultRootlessGraphRoot } } return storageOpts, nil } +// WriteStorageConfigFile writes the configuration to a file +func WriteStorageConfigFile(storageOpts *storage.StoreOptions, storageConf string) error { + os.MkdirAll(filepath.Dir(storageConf), 0755) + file, err := os.OpenFile(storageConf, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666) + if err != nil { + return errors.Wrapf(err, "cannot open %s", storageConf) + } + tomlConfiguration := getTomlStorage(storageOpts) + defer file.Close() + enc := toml.NewEncoder(file) + if err := enc.Encode(tomlConfiguration); err != nil { + os.Remove(storageConf) + return err + } + return nil +} + // StorageConfigFile returns the path to the storage config file used func StorageConfigFile() string { if rootless.IsRootless() { diff --git a/pkg/varlinkapi/containers.go b/pkg/varlinkapi/containers.go index fe38a7cdc..3185ba0e9 100644 --- a/pkg/varlinkapi/containers.go +++ b/pkg/varlinkapi/containers.go @@ -7,6 +7,7 @@ import ( "io" "io/ioutil" "os" + "sync" "syscall" "time" @@ -602,3 +603,56 @@ func ContainerStatsToLibpodContainerStats(stats iopodman.ContainerStats) libpod. } return cstats } + +// GetContainersLogs is the varlink endpoint to obtain one or more container logs +func (i *LibpodAPI) GetContainersLogs(call iopodman.VarlinkCall, names []string, follow, latest bool, since string, tail int64, timestamps bool) error { + var wg sync.WaitGroup + if call.WantsMore() { + call.Continues = true + } + sinceTime, err := time.Parse(time.RFC3339Nano, since) + if err != nil { + return call.ReplyErrorOccurred(err.Error()) + } + options := libpod.LogOptions{ + Follow: follow, + Since: sinceTime, + Tail: uint64(tail), + Timestamps: timestamps, + } + + options.WaitGroup = &wg + if len(names) > 1 { + options.Multi = true + } + logChannel := make(chan *libpod.LogLine, int(tail)*len(names)+1) + containers, err := shortcuts.GetContainersByContext(false, latest, names, i.Runtime) + if err != nil { + return call.ReplyErrorOccurred(err.Error()) + } + if err := i.Runtime.Log(containers, &options, logChannel); err != nil { + return err + } + go func() { + wg.Wait() + close(logChannel) + }() + for line := range logChannel { + call.ReplyGetContainersLogs(newPodmanLogLine(line)) + if !call.Continues { + break + } + + } + return call.ReplyGetContainersLogs(iopodman.LogLine{}) +} + +func newPodmanLogLine(line *libpod.LogLine) iopodman.LogLine { + return iopodman.LogLine{ + Device: line.Device, + ParseLogType: line.ParseLogType, + Time: line.Time.Format(time.RFC3339Nano), + Msg: line.Msg, + Cid: line.CID, + } +} |