summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/container_config.go23
-rw-r--r--libpod/container_inspect.go6
-rw-r--r--libpod/container_internal.go4
-rw-r--r--libpod/container_log.go14
-rw-r--r--libpod/container_log_linux.go3
-rw-r--r--libpod/container_log_unsupported.go2
-rw-r--r--libpod/define/version.go2
-rw-r--r--libpod/kube.go2
-rw-r--r--libpod/logs/log.go33
-rw-r--r--libpod/networking_linux.go11
-rw-r--r--libpod/networking_slirp4netns.go107
-rw-r--r--libpod/oci_conmon_linux.go2
-rw-r--r--libpod/pod_api.go4
13 files changed, 136 insertions, 77 deletions
diff --git a/libpod/container_config.go b/libpod/container_config.go
index 0d9cd5723..ea644764c 100644
--- a/libpod/container_config.go
+++ b/libpod/container_config.go
@@ -8,6 +8,7 @@ import (
"github.com/containers/common/pkg/secrets"
"github.com/containers/image/v5/manifest"
"github.com/containers/podman/v4/pkg/namespaces"
+ "github.com/containers/podman/v4/pkg/specgen"
"github.com/containers/storage"
spec "github.com/opencontainers/runtime-spec/specs-go"
)
@@ -405,13 +406,19 @@ type ContainerMiscConfig struct {
InitContainerType string `json:"init_container_type,omitempty"`
}
+// InfraInherit contains the compatible options inheritable from the infra container
type InfraInherit struct {
- InfraSecurity ContainerSecurityConfig
- InfraLabels []string `json:"labelopts,omitempty"`
- InfraVolumes []*ContainerNamedVolume `json:"namedVolumes,omitempty"`
- InfraOverlay []*ContainerOverlayVolume `json:"overlayVolumes,omitempty"`
- InfraImageVolumes []*ContainerImageVolume `json:"ctrImageVolumes,omitempty"`
- InfraUserVolumes []string `json:"userVolumes,omitempty"`
- InfraResources *spec.LinuxResources `json:"resources,omitempty"`
- InfraDevices []spec.LinuxDevice `json:"device_host_src,omitempty"`
+ ApparmorProfile string `json:"apparmor_profile,omitempty"`
+ CapAdd []string `json:"cap_add,omitempty"`
+ CapDrop []string `json:"cap_drop,omitempty"`
+ HostDeviceList []spec.LinuxDevice `json:"host_device_list,omitempty"`
+ ImageVolumes []*specgen.ImageVolume `json:"image_volumes,omitempty"`
+ InfraResources *spec.LinuxResources `json:"resource_limits,omitempty"`
+ Mounts []spec.Mount `json:"mounts,omitempty"`
+ NoNewPrivileges bool `json:"no_new_privileges,omitempty"`
+ OverlayVolumes []*specgen.OverlayVolume `json:"overlay_volumes,omitempty"`
+ SeccompPolicy string `json:"seccomp_policy,omitempty"`
+ SeccompProfilePath string `json:"seccomp_profile_path,omitempty"`
+ SelinuxOpts []string `json:"selinux_opts,omitempty"`
+ Volumes []*specgen.NamedVolume `json:"volumes,omitempty"`
}
diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go
index 5fb32bd90..f2a2c2d16 100644
--- a/libpod/container_inspect.go
+++ b/libpod/container_inspect.go
@@ -103,8 +103,8 @@ func (c *Container) getContainerInspectData(size bool, driverData *define.Driver
}
}
- namedVolumes, mounts := c.sortUserVolumes(ctrSpec)
- inspectMounts, err := c.GetInspectMounts(namedVolumes, c.config.ImageVolumes, mounts)
+ namedVolumes, mounts := c.SortUserVolumes(ctrSpec)
+ inspectMounts, err := c.GetMounts(namedVolumes, c.config.ImageVolumes, mounts)
if err != nil {
return nil, err
}
@@ -222,7 +222,7 @@ func (c *Container) getContainerInspectData(size bool, driverData *define.Driver
// Get inspect-formatted mounts list.
// Only includes user-specified mounts. Only includes bind mounts and named
// volumes, not tmpfs volumes.
-func (c *Container) GetInspectMounts(namedVolumes []*ContainerNamedVolume, imageVolumes []*ContainerImageVolume, mounts []spec.Mount) ([]define.InspectMount, error) {
+func (c *Container) GetMounts(namedVolumes []*ContainerNamedVolume, imageVolumes []*ContainerImageVolume, mounts []spec.Mount) ([]define.InspectMount, error) {
inspectMounts := []define.InspectMount{}
// No mounts, return early
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 0db59f2fe..f1f467879 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -2235,9 +2235,9 @@ func (c *Container) prepareCheckpointExport() error {
return nil
}
-// sortUserVolumes sorts the volumes specified for a container
+// SortUserVolumes sorts the volumes specified for a container
// between named and normal volumes
-func (c *Container) sortUserVolumes(ctrSpec *spec.Spec) ([]*ContainerNamedVolume, []spec.Mount) {
+func (c *Container) SortUserVolumes(ctrSpec *spec.Spec) ([]*ContainerNamedVolume, []spec.Mount) {
namedUserVolumes := []*ContainerNamedVolume{}
userMounts := []spec.Mount{}
diff --git a/libpod/container_log.go b/libpod/container_log.go
index dd5c36e26..7a9eb2dbf 100644
--- a/libpod/container_log.go
+++ b/libpod/container_log.go
@@ -23,8 +23,8 @@ func init() {
// Log is a runtime function that can read one or more container logs.
func (r *Runtime) Log(ctx context.Context, containers []*Container, options *logs.LogOptions, logChannel chan *logs.LogLine) error {
- for _, ctr := range containers {
- if err := ctr.ReadLog(ctx, options, logChannel); err != nil {
+ for c, ctr := range containers {
+ if err := ctr.ReadLog(ctx, options, logChannel, int64(c)); err != nil {
return err
}
}
@@ -32,26 +32,26 @@ 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 {
+func (c *Container) ReadLog(ctx context.Context, options *logs.LogOptions, logChannel chan *logs.LogLine, colorID int64) 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:
- return c.readFromJournal(ctx, options, logChannel)
+ return c.readFromJournal(ctx, options, logChannel, colorID)
case define.JSONLogging:
// TODO provide a separate implementation of this when Conmon
// has support.
fallthrough
case define.KubernetesLogging, "":
- return c.readFromLogFile(ctx, options, logChannel)
+ return c.readFromLogFile(ctx, options, logChannel, colorID)
default:
return errors.Wrapf(define.ErrInternal, "unrecognized log driver %q, cannot read logs", c.LogDriver())
}
}
-func (c *Container) readFromLogFile(ctx context.Context, options *logs.LogOptions, logChannel chan *logs.LogLine) error {
+func (c *Container) readFromLogFile(ctx context.Context, options *logs.LogOptions, logChannel chan *logs.LogLine, colorID int64) error {
t, tailLog, err := logs.GetLogFile(c.LogPath(), options)
if err != nil {
// If the log file does not exist, this is not fatal.
@@ -65,6 +65,7 @@ func (c *Container) readFromLogFile(ctx context.Context, options *logs.LogOption
for _, nll := range tailLog {
nll.CID = c.ID()
nll.CName = c.Name()
+ nll.ColorID = colorID
if nll.Since(options.Since) && nll.Until(options.Until) {
logChannel <- nll
}
@@ -97,6 +98,7 @@ func (c *Container) readFromLogFile(ctx context.Context, options *logs.LogOption
}
nll.CID = c.ID()
nll.CName = c.Name()
+ nll.ColorID = colorID
if nll.Since(options.Since) && nll.Until(options.Until) {
logChannel <- nll
}
diff --git a/libpod/container_log_linux.go b/libpod/container_log_linux.go
index 8ae8ff2c0..d96647e51 100644
--- a/libpod/container_log_linux.go
+++ b/libpod/container_log_linux.go
@@ -45,7 +45,7 @@ func (c *Container) initializeJournal(ctx context.Context) error {
return journal.Send("", journal.PriInfo, m)
}
-func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOptions, logChannel chan *logs.LogLine) error {
+func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOptions, logChannel chan *logs.LogLine, colorID int64) error {
// We need the container's events in the same journal to guarantee
// consistency, see #10323.
if options.Follow && c.runtime.config.Engine.EventsLogger != "journald" {
@@ -231,6 +231,7 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption
}
logLine, err := logs.NewJournaldLogLine(message, options.Multi)
+ logLine.ColorID = colorID
if err != nil {
logrus.Errorf("Failed parse log line: %v", err)
return
diff --git a/libpod/container_log_unsupported.go b/libpod/container_log_unsupported.go
index 4f50f9f4c..c84a578cc 100644
--- a/libpod/container_log_unsupported.go
+++ b/libpod/container_log_unsupported.go
@@ -11,7 +11,7 @@ import (
"github.com/pkg/errors"
)
-func (c *Container) readFromJournal(_ context.Context, _ *logs.LogOptions, _ chan *logs.LogLine) error {
+func (c *Container) readFromJournal(_ context.Context, _ *logs.LogOptions, _ chan *logs.LogLine, colorID int64) error {
return errors.Wrapf(define.ErrOSNotSupported, "Journald logging only enabled with systemd on linux")
}
diff --git a/libpod/define/version.go b/libpod/define/version.go
index 039b0ff27..2c17e6e92 100644
--- a/libpod/define/version.go
+++ b/libpod/define/version.go
@@ -27,6 +27,7 @@ type Version struct {
BuiltTime string
Built int64
OsArch string
+ Os string
}
// GetVersion returns a VersionOutput struct for API and podman
@@ -49,5 +50,6 @@ func GetVersion() (Version, error) {
BuiltTime: time.Unix(buildTime, 0).Format(time.ANSIC),
Built: buildTime,
OsArch: runtime.GOOS + "/" + runtime.GOARCH,
+ Os: runtime.GOOS,
}, nil
}
diff --git a/libpod/kube.go b/libpod/kube.go
index a193df2cb..22fbb5f9f 100644
--- a/libpod/kube.go
+++ b/libpod/kube.go
@@ -773,7 +773,7 @@ func libpodEnvVarsToKubeEnvVars(envs []string, imageEnvs []string) ([]v1.EnvVar,
// libpodMountsToKubeVolumeMounts converts the containers mounts to a struct kube understands
func libpodMountsToKubeVolumeMounts(c *Container) ([]v1.VolumeMount, []v1.Volume, map[string]string, error) {
- namedVolumes, mounts := c.sortUserVolumes(c.config.Spec)
+ namedVolumes, mounts := c.SortUserVolumes(c.config.Spec)
vms := make([]v1.VolumeMount, 0, len(mounts))
vos := make([]v1.Volume, 0, len(mounts))
annotations := make(map[string]string)
diff --git a/libpod/logs/log.go b/libpod/logs/log.go
index 9672f6ee1..0eb3bb922 100644
--- a/libpod/logs/log.go
+++ b/libpod/logs/log.go
@@ -27,6 +27,9 @@ const (
// FullLogType signifies a log line is full
FullLogType = "F"
+
+ //ANSIEscapeResetCode is a code that resets all colors and text effects
+ ANSIEscapeResetCode = "\033[0m"
)
// LogOptions is the options you can use for logs
@@ -37,6 +40,7 @@ type LogOptions struct {
Until time.Time
Tail int64
Timestamps bool
+ Colors bool
Multi bool
WaitGroup *sync.WaitGroup
UseName bool
@@ -50,6 +54,7 @@ type LogLine struct {
Msg string
CID string
CName string
+ ColorID int64
}
// GetLogFile returns an hp tail for a container given options
@@ -162,6 +167,24 @@ func getTailLog(path string, tail int) ([]*LogLine, error) {
return tailLog, nil
}
+//getColor returns a ANSI escape code for color based on the colorID
+func getColor(colorID int64) string {
+ colors := map[int64]string{
+ 0: "\033[37m", // Light Gray
+ 1: "\033[31m", // Red
+ 2: "\033[33m", // Yellow
+ 3: "\033[34m", // Blue
+ 4: "\033[35m", // Magenta
+ 5: "\033[36m", // Cyan
+ 6: "\033[32m", // Green
+ }
+ return colors[colorID%int64(len(colors))]
+}
+
+func (l *LogLine) colorize(prefix string) string {
+ return getColor(l.ColorID) + prefix + l.Msg + ANSIEscapeResetCode
+}
+
// String converts a log line to a string for output given whether a detail
// bool is specified.
func (l *LogLine) String(options *LogOptions) string {
@@ -177,10 +200,18 @@ func (l *LogLine) String(options *LogOptions) string {
out = fmt.Sprintf("%s ", cid)
}
}
+
if options.Timestamps {
out += fmt.Sprintf("%s ", l.Time.Format(LogTimeFormat))
}
- return out + l.Msg
+
+ if options.Colors {
+ out = l.colorize(out)
+ } else {
+ out += l.Msg
+ }
+
+ return out
}
// Since returns a bool as to whether a log line occurred after a given time
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index db36ac75d..71e29f18f 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -498,10 +498,13 @@ func (r *Runtime) GetRootlessNetNs(new bool) (*RootlessNetNS, error) {
return nil, err
}
- // move to systemd scope to prevent systemd from killing it
- err = utils.MoveRootlessNetnsSlirpProcessToUserSlice(cmd.Process.Pid)
- if err != nil {
- logrus.Errorf("failed to move the rootless netns slirp4netns process to the systemd user.slice: %v", err)
+ if utils.RunsOnSystemd() {
+ // move to systemd scope to prevent systemd from killing it
+ err = utils.MoveRootlessNetnsSlirpProcessToUserSlice(cmd.Process.Pid)
+ if err != nil {
+ // only log this, it is not fatal but can lead to issues when running podman inside systemd units
+ logrus.Errorf("failed to move the rootless netns slirp4netns process to the systemd user.slice: %v", err)
+ }
}
// build a new resolv.conf file which uses the slirp4netns dns server address
diff --git a/libpod/networking_slirp4netns.go b/libpod/networking_slirp4netns.go
index 3f6c4bef2..3f2842d4c 100644
--- a/libpod/networking_slirp4netns.go
+++ b/libpod/networking_slirp4netns.go
@@ -614,60 +614,73 @@ func (r *Runtime) setupRootlessPortMappingViaSlirp(ctr *Container, cmd *exec.Cmd
// for each port we want to add we need to open a connection to the slirp4netns control socket
// and send the add_hostfwd command.
- for _, i := range ctr.convertPortMappings() {
- conn, err := net.Dial("unix", apiSocket)
- if err != nil {
- return errors.Wrapf(err, "cannot open connection to %s", apiSocket)
- }
- defer func() {
- if err := conn.Close(); err != nil {
- logrus.Errorf("Unable to close connection: %q", err)
+ for _, port := range ctr.convertPortMappings() {
+ protocols := strings.Split(port.Protocol, ",")
+ for _, protocol := range protocols {
+ hostIP := port.HostIP
+ if hostIP == "" {
+ hostIP = "0.0.0.0"
+ }
+ for i := uint16(0); i < port.Range; i++ {
+ if err := openSlirp4netnsPort(apiSocket, protocol, hostIP, port.HostPort+i, port.ContainerPort+i); err != nil {
+ return err
+ }
}
- }()
- hostIP := i.HostIP
- if hostIP == "" {
- hostIP = "0.0.0.0"
- }
- apiCmd := slirp4netnsCmd{
- Execute: "add_hostfwd",
- Args: slirp4netnsCmdArg{
- Proto: i.Protocol,
- HostAddr: hostIP,
- HostPort: i.HostPort,
- GuestPort: i.ContainerPort,
- },
- }
- // create the JSON payload and send it. Mark the end of request shutting down writes
- // to the socket, as requested by slirp4netns.
- data, err := json.Marshal(&apiCmd)
- if err != nil {
- return errors.Wrapf(err, "cannot marshal JSON for slirp4netns")
- }
- if _, err := conn.Write([]byte(fmt.Sprintf("%s\n", data))); err != nil {
- return errors.Wrapf(err, "cannot write to control socket %s", apiSocket)
- }
- if err := conn.(*net.UnixConn).CloseWrite(); err != nil {
- return errors.Wrapf(err, "cannot shutdown the socket %s", apiSocket)
- }
- buf := make([]byte, 2048)
- readLength, err := conn.Read(buf)
- if err != nil {
- return errors.Wrapf(err, "cannot read from control socket %s", apiSocket)
- }
- // if there is no 'error' key in the received JSON data, then the operation was
- // successful.
- var y map[string]interface{}
- if err := json.Unmarshal(buf[0:readLength], &y); err != nil {
- return errors.Wrapf(err, "error parsing error status from slirp4netns")
- }
- if e, found := y["error"]; found {
- return errors.Errorf("from slirp4netns while setting up port redirection: %v", e)
}
}
logrus.Debug("slirp4netns port-forwarding setup via add_hostfwd is ready")
return nil
}
+// openSlirp4netnsPort sends the slirp4netns pai quey to the given socket
+func openSlirp4netnsPort(apiSocket, proto, hostip string, hostport, guestport uint16) error {
+ conn, err := net.Dial("unix", apiSocket)
+ if err != nil {
+ return errors.Wrapf(err, "cannot open connection to %s", apiSocket)
+ }
+ defer func() {
+ if err := conn.Close(); err != nil {
+ logrus.Errorf("Unable to close slirp4netns connection: %q", err)
+ }
+ }()
+ apiCmd := slirp4netnsCmd{
+ Execute: "add_hostfwd",
+ Args: slirp4netnsCmdArg{
+ Proto: proto,
+ HostAddr: hostip,
+ HostPort: hostport,
+ GuestPort: guestport,
+ },
+ }
+ // create the JSON payload and send it. Mark the end of request shutting down writes
+ // to the socket, as requested by slirp4netns.
+ data, err := json.Marshal(&apiCmd)
+ if err != nil {
+ return errors.Wrapf(err, "cannot marshal JSON for slirp4netns")
+ }
+ if _, err := conn.Write([]byte(fmt.Sprintf("%s\n", data))); err != nil {
+ return errors.Wrapf(err, "cannot write to control socket %s", apiSocket)
+ }
+ if err := conn.(*net.UnixConn).CloseWrite(); err != nil {
+ return errors.Wrapf(err, "cannot shutdown the socket %s", apiSocket)
+ }
+ buf := make([]byte, 2048)
+ readLength, err := conn.Read(buf)
+ if err != nil {
+ return errors.Wrapf(err, "cannot read from control socket %s", apiSocket)
+ }
+ // if there is no 'error' key in the received JSON data, then the operation was
+ // successful.
+ var y map[string]interface{}
+ if err := json.Unmarshal(buf[0:readLength], &y); err != nil {
+ return errors.Wrapf(err, "error parsing error status from slirp4netns")
+ }
+ if e, found := y["error"]; found {
+ return errors.Errorf("from slirp4netns while setting up port redirection: %v", e)
+ }
+ return nil
+}
+
func getRootlessPortChildIP(c *Container, netStatus map[string]types.StatusBlock) string {
if c.config.NetMode.IsSlirp4netns() {
slirp4netnsIP, err := GetSlirp4netnsIP(c.slirp4netnsSubnet)
diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go
index 38bf85834..264236dc1 100644
--- a/libpod/oci_conmon_linux.go
+++ b/libpod/oci_conmon_linux.go
@@ -661,7 +661,7 @@ func (r *ConmonOCIRuntime) HTTPAttach(ctr *Container, req *http.Request, w http.
}
errChan <- err
}()
- if err := ctr.ReadLog(context.Background(), logOpts, logChan); err != nil {
+ if err := ctr.ReadLog(context.Background(), logOpts, logChan, 0); err != nil {
return err
}
go func() {
diff --git a/libpod/pod_api.go b/libpod/pod_api.go
index be726d8d1..48049798b 100644
--- a/libpod/pod_api.go
+++ b/libpod/pod_api.go
@@ -602,8 +602,8 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) {
infraConfig.CPUSetCPUs = p.ResourceLim().CPU.Cpus
infraConfig.PidNS = p.PidMode()
infraConfig.UserNS = p.UserNSMode()
- namedVolumes, mounts := infra.sortUserVolumes(infra.config.Spec)
- inspectMounts, err = infra.GetInspectMounts(namedVolumes, infra.config.ImageVolumes, mounts)
+ namedVolumes, mounts := infra.SortUserVolumes(infra.config.Spec)
+ inspectMounts, err = infra.GetMounts(namedVolumes, infra.config.ImageVolumes, mounts)
infraSecurity = infra.GetSecurityOptions()
if err != nil {
return nil, err