summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/container_internal_linux.go156
-rw-r--r--libpod/container_log_linux.go2
-rw-r--r--libpod/healthcheck.go36
-rw-r--r--libpod/networking_linux.go55
-rw-r--r--libpod/oci_conmon_exec_linux.go2
-rw-r--r--libpod/options.go2
6 files changed, 197 insertions, 56 deletions
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 86d8586d0..afa351c17 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -2045,19 +2045,8 @@ func (c *Container) generateResolvConf() (string, error) {
}
}
- ipv6 := false
- // If network status is set check for ipv6 and dns namesevers
netStatus := c.getNetworkStatus()
for _, status := range netStatus {
- for _, netInt := range status.Interfaces {
- for _, netAddress := range netInt.Subnets {
- // Note: only using To16() does not work since it also returns a valid ip for ipv4
- if netAddress.IPNet.IP.To4() == nil && netAddress.IPNet.IP.To16() != nil {
- ipv6 = true
- }
- }
- }
-
if status.DNSServerIPs != nil {
for _, nsIP := range status.DNSServerIPs {
networkNameServers = append(networkNameServers, nsIP.String())
@@ -2070,16 +2059,9 @@ func (c *Container) generateResolvConf() (string, error) {
}
}
- if c.config.NetMode.IsSlirp4netns() {
- ctrNetworkSlipOpts := []string{}
- if c.config.NetworkOptions != nil {
- ctrNetworkSlipOpts = append(ctrNetworkSlipOpts, c.config.NetworkOptions["slirp4netns"]...)
- }
- slirpOpts, err := parseSlirp4netnsNetworkOptions(c.runtime, ctrNetworkSlipOpts)
- if err != nil {
- return "", err
- }
- ipv6 = slirpOpts.enableIPv6
+ ipv6, err := c.checkForIPv6(netStatus)
+ if err != nil {
+ return "", err
}
// Ensure that the container's /etc/resolv.conf is compatible with its
@@ -2099,38 +2081,38 @@ func (c *Container) generateResolvConf() (string, error) {
}
dnsServers := append(dns, c.config.DNSServer...)
// If the user provided dns, it trumps all; then dns masq; then resolv.conf
+ var search []string
switch {
case len(dnsServers) > 0:
-
// We store DNS servers as net.IP, so need to convert to string
for _, server := range dnsServers {
nameservers = append(nameservers, server.String())
}
- case len(networkNameServers) > 0:
- nameservers = append(nameservers, networkNameServers...)
default:
// Make a new resolv.conf
- nameservers = resolvconf.GetNameservers(resolv.Content)
- // slirp4netns has a built in DNS server.
+ // first add the nameservers from the networks status
+ nameservers = append(nameservers, networkNameServers...)
+ // when we add network dns server we also have to add the search domains
+ search = networkSearchDomains
+ // slirp4netns has a built in DNS forwarder.
if c.config.NetMode.IsSlirp4netns() {
slirp4netnsDNS, err := GetSlirp4netnsDNS(c.slirp4netnsSubnet)
if err != nil {
logrus.Warn("Failed to determine Slirp4netns DNS: ", err.Error())
} else {
- nameservers = append([]string{slirp4netnsDNS.String()}, nameservers...)
+ nameservers = append(nameservers, slirp4netnsDNS.String())
}
}
+ nameservers = append(nameservers, resolvconf.GetNameservers(resolv.Content)...)
}
- var search []string
- if len(c.config.DNSSearch) > 0 || len(c.runtime.config.Containers.DNSSearches) > 0 || len(networkSearchDomains) > 0 {
+ if len(c.config.DNSSearch) > 0 || len(c.runtime.config.Containers.DNSSearches) > 0 {
if !util.StringInSlice(".", c.config.DNSSearch) {
- search = c.runtime.config.Containers.DNSSearches
+ search = append(search, c.runtime.config.Containers.DNSSearches...)
search = append(search, c.config.DNSSearch...)
- search = append(search, networkSearchDomains...)
}
} else {
- search = resolvconf.GetSearchDomains(resolv.Content)
+ search = append(search, resolvconf.GetSearchDomains(resolv.Content)...)
}
var options []string
@@ -2160,6 +2142,116 @@ func (c *Container) generateResolvConf() (string, error) {
return destPath, nil
}
+// Check if a container uses IPv6.
+func (c *Container) checkForIPv6(netStatus map[string]types.StatusBlock) (bool, error) {
+ for _, status := range netStatus {
+ for _, netInt := range status.Interfaces {
+ for _, netAddress := range netInt.Subnets {
+ // Note: only using To16() does not work since it also returns a valid ip for ipv4
+ if netAddress.IPNet.IP.To4() == nil && netAddress.IPNet.IP.To16() != nil {
+ return true, nil
+ }
+ }
+ }
+ }
+
+ if c.config.NetMode.IsSlirp4netns() {
+ ctrNetworkSlipOpts := []string{}
+ if c.config.NetworkOptions != nil {
+ ctrNetworkSlipOpts = append(ctrNetworkSlipOpts, c.config.NetworkOptions["slirp4netns"]...)
+ }
+ slirpOpts, err := parseSlirp4netnsNetworkOptions(c.runtime, ctrNetworkSlipOpts)
+ if err != nil {
+ return false, err
+ }
+ return slirpOpts.enableIPv6, nil
+ }
+
+ return false, nil
+}
+
+// Add a new nameserver to the container's resolv.conf, ensuring that it is the
+// first nameserver present.
+// Usable only with running containers.
+func (c *Container) addNameserver(ips []string) error {
+ // Take no action if container is not running.
+ if !c.ensureState(define.ContainerStateRunning, define.ContainerStateCreated) {
+ return nil
+ }
+
+ // Do we have a resolv.conf at all?
+ path, ok := c.state.BindMounts["/etc/resolv.conf"]
+ if !ok {
+ return nil
+ }
+
+ // Read in full contents, parse out existing nameservers
+ contents, err := ioutil.ReadFile(path)
+ if err != nil {
+ return err
+ }
+ ns := resolvconf.GetNameservers(contents)
+ options := resolvconf.GetOptions(contents)
+ search := resolvconf.GetSearchDomains(contents)
+
+ // We could verify that it doesn't already exist
+ // but extra nameservers shouldn't harm anything.
+ // Ensure we are the first entry in resolv.conf though, otherwise we
+ // might be after user-added servers.
+ ns = append(ips, ns...)
+
+ // We're rewriting the container's resolv.conf as part of this, but we
+ // hold the container lock, so there should be no risk of parallel
+ // modification.
+ if _, err := resolvconf.Build(path, ns, search, options); err != nil {
+ return errors.Wrapf(err, "error adding new nameserver to container %s resolv.conf", c.ID())
+ }
+
+ return nil
+}
+
+// Remove an entry from the existing resolv.conf of the container.
+// Usable only with running containers.
+func (c *Container) removeNameserver(ips []string) error {
+ // Take no action if container is not running.
+ if !c.ensureState(define.ContainerStateRunning, define.ContainerStateCreated) {
+ return nil
+ }
+
+ // Do we have a resolv.conf at all?
+ path, ok := c.state.BindMounts["/etc/resolv.conf"]
+ if !ok {
+ return nil
+ }
+
+ // Read in full contents, parse out existing nameservers
+ contents, err := ioutil.ReadFile(path)
+ if err != nil {
+ return err
+ }
+ ns := resolvconf.GetNameservers(contents)
+ options := resolvconf.GetOptions(contents)
+ search := resolvconf.GetSearchDomains(contents)
+
+ toRemove := make(map[string]bool)
+ for _, ip := range ips {
+ toRemove[ip] = true
+ }
+
+ newNS := make([]string, 0, len(ns))
+ for _, server := range ns {
+ if !toRemove[server] {
+ newNS = append(newNS, server)
+ }
+ }
+
+ if _, err := resolvconf.Build(path, newNS, search, options); err != nil {
+ return errors.Wrapf(err, "error removing nameservers from container %s resolv.conf", c.ID())
+ }
+
+ return nil
+}
+
// updateHosts updates the container's hosts file
func (c *Container) updateHosts(path string) error {
var hosts string
diff --git a/libpod/container_log_linux.go b/libpod/container_log_linux.go
index 6b7cb4aa6..6150973ca 100644
--- a/libpod/container_log_linux.go
+++ b/libpod/container_log_linux.go
@@ -226,7 +226,7 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption
}
if formatError != nil {
- logrus.Errorf("Failed to parse journald log entry: %v", err)
+ logrus.Errorf("Failed to parse journald log entry: %v", formatError)
return
}
diff --git a/libpod/healthcheck.go b/libpod/healthcheck.go
index 53bad47b4..40af9aec3 100644
--- a/libpod/healthcheck.go
+++ b/libpod/healthcheck.go
@@ -2,7 +2,6 @@ package libpod
import (
"bufio"
- "bytes"
"io/ioutil"
"os"
"path/filepath"
@@ -22,16 +21,6 @@ const (
MaxHealthCheckLogLength = 500
)
-// hcWriteCloser allows us to use bufio as a WriteCloser
-type hcWriteCloser struct {
- *bufio.Writer
-}
-
-// Used to add a closer to bufio
-func (hcwc hcWriteCloser) Close() error {
- return nil
-}
-
// HealthCheck verifies the state and validity of the healthcheck configuration
// on the container and then executes the healthcheck
func (r *Runtime) HealthCheck(name string) (define.HealthCheckStatus, error) {
@@ -51,7 +40,6 @@ func (c *Container) runHealthCheck() (define.HealthCheckStatus, error) {
var (
newCommand []string
returnCode int
- capture bytes.Buffer
inStartPeriod bool
)
hcCommand := c.HealthCheckConfig().Test
@@ -73,20 +61,30 @@ func (c *Container) runHealthCheck() (define.HealthCheckStatus, error) {
if len(newCommand) < 1 || newCommand[0] == "" {
return define.HealthCheckNotDefined, errors.Errorf("container %s has no defined healthcheck", c.ID())
}
- captureBuffer := bufio.NewWriter(&capture)
- hcw := hcWriteCloser{
- captureBuffer,
+ rPipe, wPipe, err := os.Pipe()
+ if err != nil {
+ return define.HealthCheckInternalError, errors.Wrapf(err, "unable to create pipe for healthcheck session")
}
+ defer wPipe.Close()
+ defer rPipe.Close()
+
streams := new(define.AttachStreams)
- streams.OutputStream = hcw
- streams.ErrorStream = hcw
streams.InputStream = bufio.NewReader(os.Stdin)
-
+ streams.OutputStream = wPipe
+ streams.ErrorStream = wPipe
streams.AttachOutput = true
streams.AttachError = true
streams.AttachInput = true
+ stdout := []string{}
+ go func() {
+ scanner := bufio.NewScanner(rPipe)
+ for scanner.Scan() {
+ stdout = append(stdout, scanner.Text())
+ }
+ }()
+
logrus.Debugf("executing health check command %s for %s", strings.Join(newCommand, " "), c.ID())
timeStart := time.Now()
hcResult := define.HealthCheckSuccess
@@ -119,7 +117,7 @@ func (c *Container) runHealthCheck() (define.HealthCheckStatus, error) {
}
}
- eventLog := capture.String()
+ eventLog := strings.Join(stdout, "\n")
if len(eventLog) > MaxHealthCheckLogLength {
eventLog = eventLog[:MaxHealthCheckLogLength]
}
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index f490ac626..19d5c7f76 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -28,6 +28,7 @@ import (
"github.com/containers/podman/v4/pkg/resolvconf"
"github.com/containers/podman/v4/pkg/rootless"
"github.com/containers/podman/v4/pkg/util"
+ "github.com/containers/podman/v4/utils"
"github.com/containers/storage/pkg/lockfile"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
@@ -495,6 +496,12 @@ 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)
+ }
+
// build a new resolv.conf file which uses the slirp4netns dns server address
resolveIP, err := GetSlirp4netnsDNS(nil)
if err != nil {
@@ -1163,6 +1170,7 @@ func (c *Container) NetworkDisconnect(nameOrID, netName string, force bool) erro
}
// update network status if container is running
+ oldStatus, statusExist := networkStatus[netName]
delete(networkStatus, netName)
c.state.NetworkStatus = networkStatus
err = c.save()
@@ -1173,8 +1181,26 @@ func (c *Container) NetworkDisconnect(nameOrID, netName string, force bool) erro
// Reload ports when there are still connected networks, maybe we removed the network interface with the child ip.
// Reloading without connected networks does not make sense, so we can skip this step.
if rootless.IsRootless() && len(networkStatus) > 0 {
- return c.reloadRootlessRLKPortMapping()
+ if err := c.reloadRootlessRLKPortMapping(); err != nil {
+ return err
+ }
+ }
+
+ // Update resolv.conf if required
+ if statusExist {
+ stringIPs := make([]string, 0, len(oldStatus.DNSServerIPs))
+ for _, ip := range oldStatus.DNSServerIPs {
+ stringIPs = append(stringIPs, ip.String())
+ }
+ if len(stringIPs) == 0 {
+ return nil
+ }
+ logrus.Debugf("Removing DNS Servers %v from resolv.conf", stringIPs)
+ if err := c.removeNameserver(stringIPs); err != nil {
+ return err
+ }
}
+
return nil
}
@@ -1256,11 +1282,36 @@ func (c *Container) NetworkConnect(nameOrID, netName string, netOpts types.PerNe
if err != nil {
return err
}
+
// The first network needs a port reload to set the correct child ip for the rootlessport process.
// Adding a second network does not require a port reload because the child ip is still valid.
if rootless.IsRootless() && len(networks) == 0 {
- return c.reloadRootlessRLKPortMapping()
+ if err := c.reloadRootlessRLKPortMapping(); err != nil {
+ return err
+ }
}
+
+ ipv6, err := c.checkForIPv6(networkStatus)
+ if err != nil {
+ return err
+ }
+
+ // Update resolv.conf if required
+ stringIPs := make([]string, 0, len(results[netName].DNSServerIPs))
+ for _, ip := range results[netName].DNSServerIPs {
+ if (ip.To4() == nil) && !ipv6 {
+ continue
+ }
+ stringIPs = append(stringIPs, ip.String())
+ }
+ if len(stringIPs) == 0 {
+ return nil
+ }
+ logrus.Debugf("Adding DNS Servers %v to resolv.conf", stringIPs)
+ if err := c.addNameserver(stringIPs); err != nil {
+ return err
+ }
+
return nil
}
diff --git a/libpod/oci_conmon_exec_linux.go b/libpod/oci_conmon_exec_linux.go
index 04deaac83..aa970bbde 100644
--- a/libpod/oci_conmon_exec_linux.go
+++ b/libpod/oci_conmon_exec_linux.go
@@ -257,7 +257,7 @@ func (r *ConmonOCIRuntime) ExecStopContainer(ctr *Container, sessionID string, t
}
// Wait for the PID to stop
- if err := waitPidStop(pid, killContainerTimeout*time.Second); err != nil {
+ if err := waitPidStop(pid, killContainerTimeout); err != nil {
return errors.Wrapf(err, "timed out waiting for container %s exec session %s PID %d to stop after SIGKILL", ctr.ID(), sessionID, pid)
}
diff --git a/libpod/options.go b/libpod/options.go
index 4f9e49d0f..e0502a72d 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -1865,7 +1865,7 @@ func WithPodCgroupParent(path string) PodCreateOption {
// this pod.
// This can still be overridden at the container level by explicitly specifying
// a Cgroup parent.
-func WithPodCgroups() PodCreateOption {
+func WithPodParent() PodCreateOption {
return func(pod *Pod) error {
if pod.valid {
return define.ErrPodFinalized