summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/container.go5
-rw-r--r--libpod/container_top_linux.go18
-rw-r--r--libpod/kube.go65
-rw-r--r--libpod/networking_linux.go26
4 files changed, 86 insertions, 28 deletions
diff --git a/libpod/container.go b/libpod/container.go
index 482af43f3..2b74a1943 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -939,6 +939,11 @@ func (c *Container) cGroupPath() (string, error) {
procPath := fmt.Sprintf("/proc/%d/cgroup", c.state.PID)
lines, err := ioutil.ReadFile(procPath)
if err != nil {
+ // If the file doesn't exist, it means the container could have been terminated
+ // so report it.
+ if os.IsNotExist(err) {
+ return "", errors.Wrapf(define.ErrCtrStopped, "cannot get cgroup path unless container %s is running", c.ID())
+ }
return "", err
}
diff --git a/libpod/container_top_linux.go b/libpod/container_top_linux.go
index 0d4cba85e..d4f4ddfc1 100644
--- a/libpod/container_top_linux.go
+++ b/libpod/container_top_linux.go
@@ -4,6 +4,7 @@ package libpod
import (
"bufio"
+ "fmt"
"os"
"strconv"
"strings"
@@ -11,6 +12,7 @@ import (
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/psgo"
+ "github.com/google/shlex"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -51,7 +53,21 @@ func (c *Container) Top(descriptors []string) ([]string, error) {
return nil, psgoErr
}
- output, err = c.execPS(descriptors)
+ // Note that the descriptors to ps(1) must be shlexed (see #12452).
+ psDescriptors := []string{}
+ for _, d := range descriptors {
+ shSplit, err := shlex.Split(d)
+ if err != nil {
+ return nil, fmt.Errorf("parsing ps args: %v", err)
+ }
+ for _, s := range shSplit {
+ if s != "" {
+ psDescriptors = append(psDescriptors, s)
+ }
+ }
+ }
+
+ output, err = c.execPS(psDescriptors)
if err != nil {
return nil, errors.Wrapf(err, "error executing ps(1) in the container")
}
diff --git a/libpod/kube.go b/libpod/kube.go
index 351c49c9a..4e61b5377 100644
--- a/libpod/kube.go
+++ b/libpod/kube.go
@@ -79,7 +79,11 @@ func (p *Pod) GenerateForKube(ctx context.Context) (*v1.Pod, []v1.ServicePort, e
if err != nil {
return nil, servicePorts, err
}
- servicePorts = containerPortsToServicePorts(ports)
+ spState := newServicePortState()
+ servicePorts, err = spState.containerPortsToServicePorts(ports)
+ if err != nil {
+ return nil, servicePorts, err
+ }
hostNetwork = infraContainer.NetworkMode() == string(namespaces.NetworkMode(specgen.Host))
}
pod, err := p.podWithContainers(ctx, allContainers, ports, hostNetwork)
@@ -242,13 +246,17 @@ func ConvertV1PodToYAMLPod(pod *v1.Pod) *YAMLPod {
}
// GenerateKubeServiceFromV1Pod creates a v1 service object from a v1 pod object
-func GenerateKubeServiceFromV1Pod(pod *v1.Pod, servicePorts []v1.ServicePort) YAMLService {
+func GenerateKubeServiceFromV1Pod(pod *v1.Pod, servicePorts []v1.ServicePort) (YAMLService, error) {
service := YAMLService{}
selector := make(map[string]string)
selector["app"] = pod.Labels["app"]
ports := servicePorts
if len(ports) == 0 {
- ports = containersToServicePorts(pod.Spec.Containers)
+ p, err := containersToServicePorts(pod.Spec.Containers)
+ if err != nil {
+ return service, err
+ }
+ ports = p
}
serviceSpec := v1.ServiceSpec{
Ports: ports,
@@ -262,15 +270,43 @@ func GenerateKubeServiceFromV1Pod(pod *v1.Pod, servicePorts []v1.ServicePort) YA
APIVersion: pod.TypeMeta.APIVersion,
}
service.TypeMeta = tm
- return service
+ return service, nil
+}
+
+// servicePortState allows calling containerPortsToServicePorts for a single service
+type servicePortState struct {
+ // A program using the shared math/rand state with the default seed will produce the same sequence of pseudo-random numbers
+ // for each execution. Use a private RNG state not to interfere with other users.
+ rng *rand.Rand
+ usedPorts map[int]struct{}
+}
+
+func newServicePortState() servicePortState {
+ return servicePortState{
+ rng: rand.New(rand.NewSource(time.Now().UnixNano())),
+ usedPorts: map[int]struct{}{},
+ }
}
// containerPortsToServicePorts takes a slice of containerports and generates a
// slice of service ports
-func containerPortsToServicePorts(containerPorts []v1.ContainerPort) []v1.ServicePort {
+func (state *servicePortState) containerPortsToServicePorts(containerPorts []v1.ContainerPort) ([]v1.ServicePort, error) {
sps := make([]v1.ServicePort, 0, len(containerPorts))
for _, cp := range containerPorts {
- nodePort := 30000 + rand.Intn(32767-30000+1)
+ var nodePort int
+ attempt := 0
+ for {
+ // Legal nodeport range is 30000-32767
+ nodePort = 30000 + state.rng.Intn(32767-30000+1)
+ if _, found := state.usedPorts[nodePort]; !found {
+ state.usedPorts[nodePort] = struct{}{}
+ break
+ }
+ attempt++
+ if attempt >= 100 {
+ return nil, fmt.Errorf("too many attempts trying to generate a unique NodePort number")
+ }
+ }
servicePort := v1.ServicePort{
Protocol: cp.Protocol,
Port: cp.ContainerPort,
@@ -280,21 +316,22 @@ func containerPortsToServicePorts(containerPorts []v1.ContainerPort) []v1.Servic
}
sps = append(sps, servicePort)
}
- return sps
+ return sps, nil
}
// containersToServicePorts takes a slice of v1.Containers and generates an
// inclusive list of serviceports to expose
-func containersToServicePorts(containers []v1.Container) []v1.ServicePort {
- // Without the call to rand.Seed, a program will produce the same sequence of pseudo-random numbers
- // for each execution. Legal nodeport range is 30000-32767
- rand.Seed(time.Now().UnixNano())
-
+func containersToServicePorts(containers []v1.Container) ([]v1.ServicePort, error) {
+ state := newServicePortState()
sps := make([]v1.ServicePort, 0, len(containers))
for _, ctr := range containers {
- sps = append(sps, containerPortsToServicePorts(ctr.Ports)...)
+ ports, err := state.containerPortsToServicePorts(ctr.Ports)
+ if err != nil {
+ return nil, err
+ }
+ sps = append(sps, ports...)
}
- return sps
+ return sps, nil
}
func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, ports []v1.ContainerPort, hostNetwork bool) (*v1.Pod, error) {
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index 7d1214183..b734b9c95 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -322,17 +322,14 @@ func (r *RootlessNetNS) Do(toRun func() error) error {
// Cleanup the rootless network namespace if needed.
// It checks if we have running containers with the bridge network mode.
-// Cleanup() will try to lock RootlessNetNS, therefore you have to call
-// it with an unlocked lock.
+// Cleanup() expects that r.Lock is locked
func (r *RootlessNetNS) Cleanup(runtime *Runtime) error {
_, err := os.Stat(r.dir)
if os.IsNotExist(err) {
// the directory does not exists no need for cleanup
return nil
}
- r.Lock.Lock()
- defer r.Lock.Unlock()
- running := func(c *Container) bool {
+ activeNetns := func(c *Container) bool {
// no bridge => no need to check
if !c.config.NetMode.IsBridge() {
return false
@@ -352,15 +349,18 @@ func (r *RootlessNetNS) Cleanup(runtime *Runtime) error {
return false
}
- state := c.state.State
- return state == define.ContainerStateRunning
+ // only check for an active netns, we cannot use the container state
+ // because not running does not mean that the netns does not need cleanup
+ // only if the netns is empty we know that we do not need cleanup
+ return c.state.NetNS != nil
}
- ctrs, err := runtime.GetContainersWithoutLock(running)
+ ctrs, err := runtime.GetContainersWithoutLock(activeNetns)
if err != nil {
return err
}
- // no cleanup if we found containers
- if len(ctrs) > 0 {
+ // no cleanup if we found no other containers with a netns
+ // we will always find one container (the container cleanup that is currently calling us)
+ if len(ctrs) > 1 {
return nil
}
logrus.Debug("Cleaning up rootless network namespace")
@@ -809,10 +809,10 @@ func (r *Runtime) teardownNetwork(ns string, opts types.NetworkOptions) error {
if rootlessNetNS != nil {
// execute the cni setup in the rootless net ns
err = rootlessNetNS.Do(tearDownPod)
- rootlessNetNS.Lock.Unlock()
- if err == nil {
- err = rootlessNetNS.Cleanup(r)
+ if cerr := rootlessNetNS.Cleanup(r); cerr != nil {
+ logrus.WithError(err).Error("failed to cleanup rootless netns")
}
+ rootlessNetNS.Lock.Unlock()
} else {
err = tearDownPod()
}