summaryrefslogtreecommitdiff
path: root/pkg/domain
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/domain')
-rw-r--r--pkg/domain/entities/engine_container.go2
-rw-r--r--pkg/domain/entities/images.go8
-rw-r--r--pkg/domain/entities/network.go15
-rw-r--r--pkg/domain/entities/play.go4
-rw-r--r--pkg/domain/entities/types.go1
-rw-r--r--pkg/domain/infra/abi/containers.go100
-rw-r--r--pkg/domain/infra/abi/cp.go6
-rw-r--r--pkg/domain/infra/abi/images.go10
-rw-r--r--pkg/domain/infra/abi/manifest.go23
-rw-r--r--pkg/domain/infra/abi/network.go17
-rw-r--r--pkg/domain/infra/abi/play.go558
-rw-r--r--pkg/domain/infra/abi/play_test.go169
-rw-r--r--pkg/domain/infra/abi/pods.go17
-rw-r--r--pkg/domain/infra/abi/system.go21
-rw-r--r--pkg/domain/infra/abi/terminal/sigproxy_linux.go8
-rw-r--r--pkg/domain/infra/runtime_libpod.go24
-rw-r--r--pkg/domain/infra/tunnel/containers.go25
-rw-r--r--pkg/domain/infra/tunnel/network.go10
18 files changed, 268 insertions, 750 deletions
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 8ab72dbd8..b051d3eec 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -50,7 +50,9 @@ type ContainerEngine interface {
SystemPrune(ctx context.Context, options SystemPruneOptions) (*SystemPruneReport, error)
HealthCheckRun(ctx context.Context, nameOrID string, options HealthCheckOptions) (*define.HealthCheckResults, error)
Info(ctx context.Context) (*define.Info, error)
+ NetworkConnect(ctx context.Context, networkname string, options NetworkConnectOptions) error
NetworkCreate(ctx context.Context, name string, options NetworkCreateOptions) (*NetworkCreateReport, error)
+ NetworkDisconnect(ctx context.Context, networkname string, options NetworkDisconnectOptions) error
NetworkInspect(ctx context.Context, namesOrIds []string, options InspectOptions) ([]NetworkInspectReport, []error, error)
NetworkList(ctx context.Context, options NetworkListOptions) ([]*NetworkListReport, error)
NetworkRm(ctx context.Context, namesOrIds []string, options NetworkRmOptions) ([]*NetworkRmReport, error)
diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go
index 101542a98..ab545d882 100644
--- a/pkg/domain/entities/images.go
+++ b/pkg/domain/entities/images.go
@@ -51,10 +51,10 @@ func (i *Image) Id() string { // nolint
}
type ImageSummary struct {
- ID string `json:"Id"`
- ParentId string `json:",omitempty"` // nolint
- RepoTags []string `json:",omitempty"`
- Created int64 `json:",omitempty"`
+ ID string `json:"Id"`
+ ParentId string // nolint
+ RepoTags []string `json:",omitempty"`
+ Created int64
Size int64 `json:",omitempty"`
SharedSize int `json:",omitempty"`
VirtualSize int64 `json:",omitempty"`
diff --git a/pkg/domain/entities/network.go b/pkg/domain/entities/network.go
index 0bab672a7..86c2e1bcd 100644
--- a/pkg/domain/entities/network.go
+++ b/pkg/domain/entities/network.go
@@ -42,9 +42,24 @@ type NetworkCreateOptions struct {
MacVLAN string
Range net.IPNet
Subnet net.IPNet
+ IPv6 bool
}
// NetworkCreateReport describes a created network for the cli
type NetworkCreateReport struct {
Filename string
}
+
+// NetworkDisconnectOptions describes options for disconnecting
+// containers from networks
+type NetworkDisconnectOptions struct {
+ Container string
+ Force bool
+}
+
+// NetworkConnectOptions describes options for connecting
+// a container to a network
+type NetworkConnectOptions struct {
+ Aliases []string
+ Container string
+}
diff --git a/pkg/domain/entities/play.go b/pkg/domain/entities/play.go
index 356e6869d..0b42e1a3f 100644
--- a/pkg/domain/entities/play.go
+++ b/pkg/domain/entities/play.go
@@ -26,6 +26,10 @@ type PlayKubeOptions struct {
SeccompProfileRoot string
// ConfigMaps - slice of pathnames to kubernetes configmap YAMLs.
ConfigMaps []string
+ // LogDriver for the container. For example: journald
+ LogDriver string
+ // Start - don't start the pod if false
+ Start types.OptionalBool
}
// PlayKubePod represents a single pod and associated containers created by play kube
diff --git a/pkg/domain/entities/types.go b/pkg/domain/entities/types.go
index d8ad2d891..12135c2b1 100644
--- a/pkg/domain/entities/types.go
+++ b/pkg/domain/entities/types.go
@@ -32,6 +32,7 @@ type VolumeDeleteReport struct{ Report }
// pods and containers
type NetOptions struct {
AddHosts []string
+ Aliases []string
CNINetworks []string
UseImageResolvConf bool
DNSOptions []string
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 98b886845..ff4277a2e 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -205,15 +205,13 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
}
func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.ContainerPruneOptions) (*entities.ContainerPruneReport, error) {
- var filterFuncs []libpod.ContainerFilter
+ filterFuncs := make([]libpod.ContainerFilter, 0, len(options.Filters))
for k, v := range options.Filters {
- for _, val := range v {
- generatedFunc, err := lpfilters.GenerateContainerFilterFuncs(k, val, ic.Libpod)
- if err != nil {
- return nil, err
- }
- filterFuncs = append(filterFuncs, generatedFunc)
+ generatedFunc, err := lpfilters.GenerateContainerFilterFuncs(k, v, ic.Libpod)
+ if err != nil {
+ return nil, err
}
+ filterFuncs = append(filterFuncs, generatedFunc)
}
return ic.pruneContainersHelper(filterFuncs)
}
@@ -913,7 +911,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
} else {
report.ExitCode = int(ecode)
}
- if opts.Rm {
+ if opts.Rm && !ctr.ShouldRestart(ctx) {
if err := ic.Libpod.RemoveContainer(ctx, ctr, false, true); err != nil {
if errors.Cause(err) == define.ErrNoSuchCtr ||
errors.Cause(err) == define.ErrCtrRemoved {
@@ -994,7 +992,7 @@ func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []st
return []*entities.ContainerCleanupReport{}, nil
}
- if options.Remove {
+ if options.Remove && !ctr.ShouldRestart(ctx) {
err = ic.Libpod.RemoveContainer(ctx, ctr, false, true)
if err != nil {
report.RmErr = errors.Wrapf(err, "failed to cleanup and remove container %v", ctr.ID())
@@ -1017,6 +1015,7 @@ func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []st
_, err = ic.Libpod.RemoveImage(ctx, ctrImage, false)
report.RmiErr = err
}
+
reports = append(reports, &report)
}
return reports, nil
@@ -1058,11 +1057,23 @@ func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIDs []strin
os.Exit(ret)
}
}
- ctrs, err := getContainersByContext(options.All, options.Latest, nameOrIDs, ic.Libpod)
+ reports := []*entities.ContainerMountReport{}
+ // Attempt to mount named containers directly from storage,
+ // this will fail and code will fall through to removing the container from libpod.`
+ names := []string{}
+ for _, ctr := range nameOrIDs {
+ report := entities.ContainerMountReport{Id: ctr}
+ if report.Path, report.Err = ic.Libpod.MountStorageContainer(ctr); report.Err != nil {
+ names = append(names, ctr)
+ } else {
+ reports = append(reports, &report)
+ }
+ }
+
+ ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod)
if err != nil {
return nil, err
}
- reports := make([]*entities.ContainerMountReport, 0, len(ctrs))
for _, ctr := range ctrs {
report := entities.ContainerMountReport{Id: ctr.ID()}
report.Path, report.Err = ctr.Mount()
@@ -1072,6 +1083,30 @@ func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIDs []strin
return reports, nil
}
+ storageCtrs, err := ic.Libpod.StorageContainers()
+ if err != nil {
+ return nil, err
+ }
+
+ for _, sctr := range storageCtrs {
+ mounted, path, err := ic.Libpod.IsStorageContainerMounted(sctr.ID)
+ if err != nil {
+ return nil, err
+ }
+
+ var name string
+ if len(sctr.Names) > 0 {
+ name = sctr.Names[0]
+ }
+ if mounted {
+ reports = append(reports, &entities.ContainerMountReport{
+ Id: sctr.ID,
+ Name: name,
+ Path: path,
+ })
+ }
+ }
+
// No containers were passed, so we send back what is mounted
ctrs, err = getContainersByContext(true, false, []string{}, ic.Libpod)
if err != nil {
@@ -1091,15 +1126,44 @@ func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIDs []strin
})
}
}
+
return reports, nil
}
func (ic *ContainerEngine) ContainerUnmount(ctx context.Context, nameOrIDs []string, options entities.ContainerUnmountOptions) ([]*entities.ContainerUnmountReport, error) {
- ctrs, err := getContainersByContext(options.All, options.Latest, nameOrIDs, ic.Libpod)
+ reports := []*entities.ContainerUnmountReport{}
+ names := []string{}
+ if options.All {
+ storageCtrs, err := ic.Libpod.StorageContainers()
+ if err != nil {
+ return nil, err
+ }
+ for _, sctr := range storageCtrs {
+ mounted, _, _ := ic.Libpod.IsStorageContainerMounted(sctr.ID)
+ if mounted {
+ report := entities.ContainerUnmountReport{Id: sctr.ID}
+ if _, report.Err = ic.Libpod.UnmountStorageContainer(sctr.ID, options.Force); report.Err != nil {
+ if errors.Cause(report.Err) != define.ErrCtrExists {
+ reports = append(reports, &report)
+ }
+ } else {
+ reports = append(reports, &report)
+ }
+ }
+ }
+ }
+ for _, ctr := range nameOrIDs {
+ report := entities.ContainerUnmountReport{Id: ctr}
+ if _, report.Err = ic.Libpod.UnmountStorageContainer(ctr, options.Force); report.Err != nil {
+ names = append(names, ctr)
+ } else {
+ reports = append(reports, &report)
+ }
+ }
+ ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod)
if err != nil {
return nil, err
}
- reports := []*entities.ContainerUnmountReport{}
for _, ctr := range ctrs {
state, err := ctr.State()
if err != nil {
@@ -1251,3 +1315,13 @@ func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []stri
return statsChan, nil
}
+
+// ShouldRestart returns whether the container should be restarted
+func (ic *ContainerEngine) ShouldRestart(ctx context.Context, nameOrID string) (*entities.BoolReport, error) {
+ ctr, err := ic.Libpod.LookupContainer(nameOrID)
+ if err != nil {
+ return nil, err
+ }
+
+ return &entities.BoolReport{Value: ctr.ShouldRestart(ctx)}, nil
+}
diff --git a/pkg/domain/infra/abi/cp.go b/pkg/domain/infra/abi/cp.go
index ab90c8183..8f4f5d3d7 100644
--- a/pkg/domain/infra/abi/cp.go
+++ b/pkg/domain/infra/abi/cp.go
@@ -214,7 +214,7 @@ func getPathInfo(path string) (string, os.FileInfo, error) {
}
srcfi, err := os.Stat(path)
if err != nil {
- return "", nil, errors.Wrapf(err, "error reading path %q", path)
+ return "", nil, err
}
return path, srcfi, nil
}
@@ -245,7 +245,7 @@ func containerCopy(srcPath, destPath, src, dest string, idMappingOpts storage.ID
}
_, err = os.Stat(destdir)
if err != nil && !os.IsNotExist(err) {
- return errors.Wrapf(err, "error checking directory %q", destdir)
+ return err
}
destDirIsExist := err == nil
if err = os.MkdirAll(destdir, 0755); err != nil {
@@ -292,7 +292,7 @@ func containerCopy(srcPath, destPath, src, dest string, idMappingOpts storage.ID
destfi, err := os.Stat(destPath)
if err != nil {
if !os.IsNotExist(err) || strings.HasSuffix(dest, string(os.PathSeparator)) {
- return errors.Wrapf(err, "failed to get stat of dest path %s", destPath)
+ return err
}
}
if destfi != nil && destfi.IsDir() {
diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go
index 25335cf11..ef0e15264 100644
--- a/pkg/domain/infra/abi/images.go
+++ b/pkg/domain/infra/abi/images.go
@@ -39,8 +39,14 @@ const SignatureStoreDir = "/var/lib/containers/sigstore"
func (ir *ImageEngine) Exists(_ context.Context, nameOrID string) (*entities.BoolReport, error) {
_, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrID)
- if err != nil && errors.Cause(err) != define.ErrNoSuchImage {
- return nil, err
+ if err != nil {
+ if errors.Cause(err) == define.ErrMultipleImages {
+ return &entities.BoolReport{Value: true}, nil
+ } else {
+ if errors.Cause(err) != define.ErrNoSuchImage {
+ return nil, err
+ }
+ }
}
return &entities.BoolReport{Value: err == nil}, nil
}
diff --git a/pkg/domain/infra/abi/manifest.go b/pkg/domain/infra/abi/manifest.go
index 6c518e678..ad7128b42 100644
--- a/pkg/domain/infra/abi/manifest.go
+++ b/pkg/domain/infra/abi/manifest.go
@@ -25,6 +25,7 @@ import (
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/opencontainers/go-digest"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
+ "github.com/sirupsen/logrus"
"github.com/pkg/errors"
)
@@ -90,10 +91,6 @@ func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte
continue
}
- if !manifest.MIMETypeIsMultiImage(manifestType) {
- appendErr(errors.Errorf("manifest is of type %s (not a list type)", manifestType))
- continue
- }
result = manifestBytes
manType = manifestType
break
@@ -101,7 +98,18 @@ func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte
if len(result) == 0 && latestErr != nil {
return nil, latestErr
}
- if manType != manifest.DockerV2ListMediaType {
+
+ switch manType {
+ case manifest.DockerV2Schema2MediaType:
+ logrus.Warnf("Warning! The manifest type %s is not a manifest list but a single image.", manType)
+ schema2Manifest, err := manifest.Schema2FromManifest(result)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error parsing manifest blob %q as a %q", string(result), manType)
+ }
+ if result, err = schema2Manifest.Serialize(); err != nil {
+ return nil, err
+ }
+ default:
listBlob, err := manifest.ListFromBlob(result, manType)
if err != nil {
return nil, errors.Wrapf(err, "error parsing manifest blob %q as a %q", string(result), manType)
@@ -113,10 +121,9 @@ func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte
if result, err = list.Serialize(); err != nil {
return nil, err
}
-
}
- err = json.Indent(&b, result, "", " ")
- if err != nil {
+
+ if err = json.Indent(&b, result, "", " "); err != nil {
return nil, errors.Wrapf(err, "error rendering manifest %s for display", name)
}
return b.Bytes(), nil
diff --git a/pkg/domain/infra/abi/network.go b/pkg/domain/infra/abi/network.go
index 4f572fb88..c52584565 100644
--- a/pkg/domain/infra/abi/network.go
+++ b/pkg/domain/infra/abi/network.go
@@ -96,7 +96,7 @@ func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, o
if err := ic.Libpod.RemovePod(ctx, pod, true, true); err != nil {
return reports, err
}
- } else if err := ic.Libpod.RemoveContainer(ctx, c, true, true); err != nil {
+ } else if err := ic.Libpod.RemoveContainer(ctx, c, true, true); err != nil && errors.Cause(err) != define.ErrNoSuchCtr {
return reports, err
}
}
@@ -110,7 +110,11 @@ func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, o
}
func (ic *ContainerEngine) NetworkCreate(ctx context.Context, name string, options entities.NetworkCreateOptions) (*entities.NetworkCreateReport, error) {
- return network.Create(name, options, ic.Libpod)
+ runtimeConfig, err := ic.Libpod.GetConfig()
+ if err != nil {
+ return nil, err
+ }
+ return network.Create(name, options, runtimeConfig)
}
func ifPassesFilterTest(netconf *libcni.NetworkConfigList, filter []string) bool {
@@ -134,3 +138,12 @@ func ifPassesFilterTest(netconf *libcni.NetworkConfigList, filter []string) bool
}
return result
}
+
+// NetworkDisconnect removes a container from a given network
+func (ic *ContainerEngine) NetworkDisconnect(ctx context.Context, networkname string, options entities.NetworkDisconnectOptions) error {
+ return ic.Libpod.DisconnectContainerFromNetwork(options.Container, networkname, options.Force)
+}
+
+func (ic *ContainerEngine) NetworkConnect(ctx context.Context, networkname string, options entities.NetworkConnectOptions) error {
+ return ic.Libpod.ConnectContainerToNetwork(options.Container, networkname, options.Aliases)
+}
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
index 348570a20..3aeb6a2ee 100644
--- a/pkg/domain/infra/abi/play.go
+++ b/pkg/domain/infra/abi/play.go
@@ -6,38 +6,21 @@ import (
"io"
"io/ioutil"
"os"
- "path/filepath"
"strings"
- "github.com/containers/buildah/pkg/parse"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/image"
- ann "github.com/containers/podman/v2/pkg/annotations"
"github.com/containers/podman/v2/pkg/domain/entities"
- envLib "github.com/containers/podman/v2/pkg/env"
- ns "github.com/containers/podman/v2/pkg/namespaces"
- createconfig "github.com/containers/podman/v2/pkg/spec"
"github.com/containers/podman/v2/pkg/specgen/generate"
+ "github.com/containers/podman/v2/pkg/specgen/generate/kube"
"github.com/containers/podman/v2/pkg/util"
- "github.com/containers/storage"
- "github.com/cri-o/ocicni/pkg/ocicni"
"github.com/docker/distribution/reference"
"github.com/ghodss/yaml"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
v1apps "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/api/resource"
-)
-
-const (
- // https://kubernetes.io/docs/concepts/storage/volumes/#hostpath
- kubeDirectoryPermission = 0755
- // https://kubernetes.io/docs/concepts/storage/volumes/#hostpath
- kubeFilePermission = 0644
- // Kubernetes sets CPUPeriod to 100000us (100ms): https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/
- defaultCPUPeriod = 100000
)
func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
@@ -112,7 +95,6 @@ func (ic *ContainerEngine) playKubeDeployment(ctx context.Context, deploymentYAM
func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
var (
- pod *libpod.Pod
registryCreds *types.DockerAuthConfig
writer io.Writer
playKubePod entities.PlayKubePod
@@ -131,49 +113,10 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
}
}
- podOptions := []libpod.PodCreateOption{
- libpod.WithInfraContainer(),
- libpod.WithPodName(podName),
- }
-
- if podYAML.ObjectMeta.Labels != nil {
- podOptions = append(podOptions, libpod.WithPodLabels(podYAML.ObjectMeta.Labels))
- }
-
- // TODO we only configure Process namespace. We also need to account for Host{IPC,Network,PID}
- // which is not currently possible with pod create
- if podYAML.Spec.ShareProcessNamespace != nil && *podYAML.Spec.ShareProcessNamespace {
- podOptions = append(podOptions, libpod.WithPodPID())
- }
-
- hostname := podYAML.Spec.Hostname
- if hostname == "" {
- hostname = podName
- }
- podOptions = append(podOptions, libpod.WithPodHostname(hostname))
-
- if podYAML.Spec.HostNetwork {
- podOptions = append(podOptions, libpod.WithPodHostNetwork())
- }
-
- if podYAML.Spec.HostAliases != nil {
- hosts := make([]string, 0, len(podYAML.Spec.HostAliases))
- for _, hostAlias := range podYAML.Spec.HostAliases {
- for _, host := range hostAlias.Hostnames {
- hosts = append(hosts, host+":"+hostAlias.IP)
- }
- }
- podOptions = append(podOptions, libpod.WithPodHosts(hosts))
- }
-
- nsOptions, err := generate.GetNamespaceOptions(strings.Split(createconfig.DefaultKernelNamespaces, ","))
+ p, err := kube.ToPodGen(ctx, podName, podYAML)
if err != nil {
return nil, err
}
- podOptions = append(podOptions, nsOptions...)
- podPorts := getPodPorts(podYAML.Spec.Containers)
- podOptions = append(podOptions, libpod.WithInfraContainerPorts(podPorts))
-
if options.Network != "" {
switch strings.ToLower(options.Network) {
case "bridge", "host":
@@ -185,12 +128,12 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
// networks.
networks := strings.Split(options.Network, ",")
logrus.Debugf("Pod joining CNI networks: %v", networks)
- podOptions = append(podOptions, libpod.WithPodNetworks(networks))
+ p.CNINetworks = append(p.CNINetworks, networks...)
}
}
// Create the Pod
- pod, err = ic.Libpod.NewPod(ctx, podOptions...)
+ pod, err := generate.MakePod(p, ic.Libpod)
if err != nil {
return nil, err
}
@@ -199,29 +142,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
if err != nil {
return nil, err
}
- hasUserns := false
- if podInfraID != "" {
- podCtr, err := ic.Libpod.GetContainer(podInfraID)
- if err != nil {
- return nil, err
- }
- mappings, err := podCtr.IDMappings()
- if err != nil {
- return nil, err
- }
- hasUserns = len(mappings.UIDMap) > 0
- }
- namespaces := map[string]string{
- // Disabled during code review per mheon
- //"pid": fmt.Sprintf("container:%s", podInfraID),
- "net": fmt.Sprintf("container:%s", podInfraID),
- "ipc": fmt.Sprintf("container:%s", podInfraID),
- "uts": fmt.Sprintf("container:%s", podInfraID),
- }
- if hasUserns {
- namespaces["user"] = fmt.Sprintf("container:%s", podInfraID)
- }
if !options.Quiet {
writer = os.Stderr
}
@@ -239,65 +160,12 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
DockerInsecureSkipTLSVerify: options.SkipTLSVerify,
}
- // map from name to mount point
- volumes := make(map[string]string)
- for _, volume := range podYAML.Spec.Volumes {
- hostPath := volume.VolumeSource.HostPath
- if hostPath == nil {
- return nil, errors.Errorf("HostPath is currently the only supported VolumeSource")
- }
- if hostPath.Type != nil {
- switch *hostPath.Type {
- case v1.HostPathDirectoryOrCreate:
- if _, err := os.Stat(hostPath.Path); os.IsNotExist(err) {
- if err := os.Mkdir(hostPath.Path, kubeDirectoryPermission); err != nil {
- return nil, errors.Errorf("error creating HostPath %s", volume.Name)
- }
- }
- // Label a newly created volume
- if err := libpod.LabelVolumePath(hostPath.Path); err != nil {
- return nil, errors.Wrapf(err, "error giving %s a label", hostPath.Path)
- }
- case v1.HostPathFileOrCreate:
- if _, err := os.Stat(hostPath.Path); os.IsNotExist(err) {
- f, err := os.OpenFile(hostPath.Path, os.O_RDONLY|os.O_CREATE, kubeFilePermission)
- if err != nil {
- return nil, errors.Errorf("error creating HostPath %s", volume.Name)
- }
- if err := f.Close(); err != nil {
- logrus.Warnf("Error in closing newly created HostPath file: %v", err)
- }
- }
- // unconditionally label a newly created volume
- if err := libpod.LabelVolumePath(hostPath.Path); err != nil {
- return nil, errors.Wrapf(err, "error giving %s a label", hostPath.Path)
- }
- case v1.HostPathSocket:
- st, err := os.Stat(hostPath.Path)
- if err != nil {
- return nil, errors.Wrap(err, "error checking HostPathSocket")
- }
- if st.Mode()&os.ModeSocket != os.ModeSocket {
- return nil, errors.Errorf("error checking HostPathSocket: path %s is not a socket", hostPath.Path)
- }
-
- case v1.HostPathDirectory:
- case v1.HostPathFile:
- case v1.HostPathUnset:
- // do nothing here because we will verify the path exists in validateVolumeHostDir
- break
- default:
- return nil, errors.Errorf("Invalid HostPath type %v", hostPath.Type)
- }
- }
-
- if err := parse.ValidateVolumeHostDir(hostPath.Path); err != nil {
- return nil, errors.Wrapf(err, "error in parsing HostPath in YAML")
- }
- volumes[volume.Name] = hostPath.Path
+ volumes, err := kube.InitializeVolumes(podYAML.Spec.Volumes)
+ if err != nil {
+ return nil, err
}
- seccompPaths, err := initializeSeccompPaths(podYAML.ObjectMeta.Annotations, options.SeccompProfileRoot)
+ seccompPaths, err := kube.InitializeSeccompPaths(podYAML.ObjectMeta.Annotations, options.SeccompProfileRoot)
if err != nil {
return nil, err
}
@@ -349,29 +217,42 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
pullPolicy = util.PullImageAlways
}
}
+
+ // This ensures the image is the image store
newImage, err := ic.Libpod.ImageRuntime().New(ctx, container.Image, options.SignaturePolicy, options.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, pullPolicy)
if err != nil {
return nil, err
}
- conf, err := kubeContainerToCreateConfig(ctx, container, newImage, namespaces, volumes, pod.ID(), podName, podInfraID, configMaps, seccompPaths)
+
+ specGen, err := kube.ToSpecGen(ctx, container, container.Image, newImage, volumes, pod.ID(), podName, podInfraID, configMaps, seccompPaths, ctrRestartPolicy)
if err != nil {
return nil, err
}
- conf.RestartPolicy = ctrRestartPolicy
- ctr, err := createconfig.CreateContainerFromCreateConfig(ctx, ic.Libpod, conf, pod)
+
+ ctr, err := generate.MakeContainer(ctx, ic.Libpod, specGen)
if err != nil {
return nil, err
}
containers = append(containers, ctr)
}
- // start the containers
- for _, ctr := range containers {
- if err := ctr.Start(ctx, true); err != nil {
- // Making this a hard failure here to avoid a mess
- // the other containers are in created status
+ if options.Start != types.OptionalBoolFalse {
+ //start the containers
+ podStartErrors, err := pod.Start(ctx)
+ if err != nil {
return nil, err
}
+
+ // Previous versions of playkube started containers individually and then
+ // looked for errors. Because we now use the uber-Pod start call, we should
+ // iterate the map of possible errors and return one if there is a problem. This
+ // keeps the behavior the same
+
+ for _, e := range podStartErrors {
+ if e != nil {
+ return nil, e
+ }
+ }
}
playKubePod.ID = pod.ID()
@@ -384,265 +265,6 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
return &report, nil
}
-// getPodPorts converts a slice of kube container descriptions to an
-// array of ocicni portmapping descriptions usable in libpod
-func getPodPorts(containers []v1.Container) []ocicni.PortMapping {
- var infraPorts []ocicni.PortMapping
- for _, container := range containers {
- for _, p := range container.Ports {
- if p.HostPort != 0 && p.ContainerPort == 0 {
- p.ContainerPort = p.HostPort
- }
- if p.Protocol == "" {
- p.Protocol = "tcp"
- }
- portBinding := ocicni.PortMapping{
- HostPort: p.HostPort,
- ContainerPort: p.ContainerPort,
- Protocol: strings.ToLower(string(p.Protocol)),
- HostIP: p.HostIP,
- }
- // only hostPort is utilized in podman context, all container ports
- // are accessible inside the shared network namespace
- if p.HostPort != 0 {
- infraPorts = append(infraPorts, portBinding)
- }
-
- }
- }
- return infraPorts
-}
-
-func setupSecurityContext(securityConfig *createconfig.SecurityConfig, userConfig *createconfig.UserConfig, containerYAML v1.Container) {
- if containerYAML.SecurityContext == nil {
- return
- }
- if containerYAML.SecurityContext.ReadOnlyRootFilesystem != nil {
- securityConfig.ReadOnlyRootfs = *containerYAML.SecurityContext.ReadOnlyRootFilesystem
- }
- if containerYAML.SecurityContext.Privileged != nil {
- securityConfig.Privileged = *containerYAML.SecurityContext.Privileged
- }
-
- if containerYAML.SecurityContext.AllowPrivilegeEscalation != nil {
- securityConfig.NoNewPrivs = !*containerYAML.SecurityContext.AllowPrivilegeEscalation
- }
-
- if seopt := containerYAML.SecurityContext.SELinuxOptions; seopt != nil {
- if seopt.User != "" {
- securityConfig.SecurityOpts = append(securityConfig.SecurityOpts, fmt.Sprintf("label=user:%s", seopt.User))
- securityConfig.LabelOpts = append(securityConfig.LabelOpts, fmt.Sprintf("user:%s", seopt.User))
- }
- if seopt.Role != "" {
- securityConfig.SecurityOpts = append(securityConfig.SecurityOpts, fmt.Sprintf("label=role:%s", seopt.Role))
- securityConfig.LabelOpts = append(securityConfig.LabelOpts, fmt.Sprintf("role:%s", seopt.Role))
- }
- if seopt.Type != "" {
- securityConfig.SecurityOpts = append(securityConfig.SecurityOpts, fmt.Sprintf("label=type:%s", seopt.Type))
- securityConfig.LabelOpts = append(securityConfig.LabelOpts, fmt.Sprintf("type:%s", seopt.Type))
- }
- if seopt.Level != "" {
- securityConfig.SecurityOpts = append(securityConfig.SecurityOpts, fmt.Sprintf("label=level:%s", seopt.Level))
- securityConfig.LabelOpts = append(securityConfig.LabelOpts, fmt.Sprintf("level:%s", seopt.Level))
- }
- }
- if caps := containerYAML.SecurityContext.Capabilities; caps != nil {
- for _, capability := range caps.Add {
- securityConfig.CapAdd = append(securityConfig.CapAdd, string(capability))
- }
- for _, capability := range caps.Drop {
- securityConfig.CapDrop = append(securityConfig.CapDrop, string(capability))
- }
- }
- if containerYAML.SecurityContext.RunAsUser != nil {
- userConfig.User = fmt.Sprintf("%d", *containerYAML.SecurityContext.RunAsUser)
- }
- if containerYAML.SecurityContext.RunAsGroup != nil {
- if userConfig.User == "" {
- userConfig.User = "0"
- }
- userConfig.User = fmt.Sprintf("%s:%d", userConfig.User, *containerYAML.SecurityContext.RunAsGroup)
- }
-}
-
-// kubeContainerToCreateConfig takes a v1.Container and returns a createconfig describing a container
-func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container, newImage *image.Image, namespaces map[string]string, volumes map[string]string, podID, podName, infraID string, configMaps []v1.ConfigMap, seccompPaths *kubeSeccompPaths) (*createconfig.CreateConfig, error) {
- var (
- containerConfig createconfig.CreateConfig
- pidConfig createconfig.PidConfig
- networkConfig createconfig.NetworkConfig
- cgroupConfig createconfig.CgroupConfig
- utsConfig createconfig.UtsConfig
- ipcConfig createconfig.IpcConfig
- userConfig createconfig.UserConfig
- securityConfig createconfig.SecurityConfig
- )
-
- // The default for MemorySwappiness is -1, not 0
- containerConfig.Resources.MemorySwappiness = -1
-
- containerConfig.Image = containerYAML.Image
- containerConfig.ImageID = newImage.ID()
-
- // podName should be non-empty for Deployment objects to be able to create
- // multiple pods having containers with unique names
- if podName == "" {
- return nil, errors.Errorf("kubeContainerToCreateConfig got empty podName")
- }
- containerConfig.Name = fmt.Sprintf("%s-%s", podName, containerYAML.Name)
-
- containerConfig.Tty = containerYAML.TTY
-
- containerConfig.Pod = podID
-
- imageData, _ := newImage.Inspect(ctx)
-
- userConfig.User = "0"
- if imageData != nil {
- userConfig.User = imageData.Config.User
- }
-
- setupSecurityContext(&securityConfig, &userConfig, containerYAML)
-
- // Since we prefix the container name with pod name to work-around the uniqueness requirement,
- // the seccom profile should reference the actual container name from the YAML
- // but apply to the containers with the prefixed name
- securityConfig.SeccompProfilePath = seccompPaths.findForContainer(containerYAML.Name)
-
- var err error
- milliCPU, err := quantityToInt64(containerYAML.Resources.Limits.Cpu())
- if err != nil {
- return nil, errors.Wrap(err, "Failed to set CPU quota")
- }
- if milliCPU > 0 {
- containerConfig.Resources.CPUPeriod = defaultCPUPeriod
- // CPU quota is a fraction of the period: milliCPU / 1000.0 * period
- // Or, without floating point math:
- containerConfig.Resources.CPUQuota = milliCPU * defaultCPUPeriod / 1000
- }
-
- containerConfig.Resources.Memory, err = quantityToInt64(containerYAML.Resources.Limits.Memory())
- if err != nil {
- return nil, errors.Wrap(err, "Failed to set memory limit")
- }
- containerConfig.Resources.MemoryReservation, err = quantityToInt64(containerYAML.Resources.Requests.Memory())
- if err != nil {
- return nil, errors.Wrap(err, "Failed to set memory reservation")
- }
-
- containerConfig.Command = []string{}
- if imageData != nil && imageData.Config != nil {
- containerConfig.Command = imageData.Config.Entrypoint
- }
- if len(containerYAML.Command) != 0 {
- containerConfig.Command = containerYAML.Command
- }
- // doc https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#notes
- if len(containerYAML.Args) != 0 {
- containerConfig.Command = append(containerConfig.Command, containerYAML.Args...)
- } else if len(containerYAML.Command) == 0 {
- // Add the Cmd from the image config only if containerYAML.Command and containerYAML.Args are empty
- containerConfig.Command = append(containerConfig.Command, imageData.Config.Cmd...)
- }
- if imageData != nil && len(containerConfig.Command) == 0 {
- return nil, errors.Errorf("No command specified in container YAML or as CMD or ENTRYPOINT in this image for %s", containerConfig.Name)
- }
-
- containerConfig.UserCommand = containerConfig.Command
-
- containerConfig.StopSignal = 15
-
- containerConfig.WorkDir = "/"
- if imageData != nil {
- // FIXME,
- // we are currently ignoring imageData.Config.ExposedPorts
- containerConfig.BuiltinImgVolumes = imageData.Config.Volumes
- if imageData.Config.WorkingDir != "" {
- containerConfig.WorkDir = imageData.Config.WorkingDir
- }
- containerConfig.Labels = imageData.Config.Labels
- if imageData.Config.StopSignal != "" {
- stopSignal, err := util.ParseSignal(imageData.Config.StopSignal)
- if err != nil {
- return nil, err
- }
- containerConfig.StopSignal = stopSignal
- }
- }
-
- if containerYAML.WorkingDir != "" {
- containerConfig.WorkDir = containerYAML.WorkingDir
- }
- // If the user does not pass in ID mappings, just set to basics
- if userConfig.IDMappings == nil {
- userConfig.IDMappings = &storage.IDMappingOptions{}
- }
-
- networkConfig.NetMode = ns.NetworkMode(namespaces["net"])
- ipcConfig.IpcMode = ns.IpcMode(namespaces["ipc"])
- utsConfig.UtsMode = ns.UTSMode(namespaces["uts"])
- // disabled in code review per mheon
- //containerConfig.PidMode = ns.PidMode(namespaces["pid"])
- userConfig.UsernsMode = ns.UsernsMode(namespaces["user"])
- if len(containerConfig.WorkDir) == 0 {
- containerConfig.WorkDir = "/"
- }
-
- containerConfig.Pid = pidConfig
- containerConfig.Network = networkConfig
- containerConfig.Uts = utsConfig
- containerConfig.Ipc = ipcConfig
- containerConfig.Cgroup = cgroupConfig
- containerConfig.User = userConfig
- containerConfig.Security = securityConfig
-
- annotations := make(map[string]string)
- if infraID != "" {
- annotations[ann.SandboxID] = infraID
- annotations[ann.ContainerType] = ann.ContainerTypeContainer
- }
- containerConfig.Annotations = annotations
-
- // Environment Variables
- envs := map[string]string{}
- if imageData != nil {
- imageEnv, err := envLib.ParseSlice(imageData.Config.Env)
- if err != nil {
- return nil, errors.Wrap(err, "error parsing image environment variables")
- }
- envs = imageEnv
- }
- for _, env := range containerYAML.Env {
- value := envVarValue(env, configMaps)
-
- envs[env.Name] = value
- }
- for _, envFrom := range containerYAML.EnvFrom {
- cmEnvs := envVarsFromConfigMap(envFrom, configMaps)
-
- for k, v := range cmEnvs {
- envs[k] = v
- }
- }
- containerConfig.Env = envs
-
- for _, volume := range containerYAML.VolumeMounts {
- var readonly string
- hostPath, exists := volumes[volume.Name]
- if !exists {
- return nil, errors.Errorf("Volume mount %s specified for container but not configured in volumes", volume.Name)
- }
- if err := parse.ValidateVolumeCtrDir(volume.MountPath); err != nil {
- return nil, errors.Wrapf(err, "error in parsing MountPath")
- }
- if volume.ReadOnly {
- readonly = ":ro"
- }
- containerConfig.Volumes = append(containerConfig.Volumes, fmt.Sprintf("%s:%s%s", hostPath, volume.MountPath, readonly))
- }
- return &containerConfig, nil
-}
-
// readConfigMapFromFile returns a kubernetes configMap obtained from --configmap flag
func readConfigMapFromFile(r io.Reader) (v1.ConfigMap, error) {
var cm v1.ConfigMap
@@ -662,125 +284,3 @@ func readConfigMapFromFile(r io.Reader) (v1.ConfigMap, error) {
return cm, nil
}
-
-// envVarsFromConfigMap returns all key-value pairs as env vars from a configMap that matches the envFrom setting of a container
-func envVarsFromConfigMap(envFrom v1.EnvFromSource, configMaps []v1.ConfigMap) map[string]string {
- envs := map[string]string{}
-
- if envFrom.ConfigMapRef != nil {
- cmName := envFrom.ConfigMapRef.Name
-
- for _, c := range configMaps {
- if cmName == c.Name {
- envs = c.Data
- break
- }
- }
- }
-
- return envs
-}
-
-// envVarValue returns the environment variable value configured within the container's env setting.
-// It gets the value from a configMap if specified, otherwise returns env.Value
-func envVarValue(env v1.EnvVar, configMaps []v1.ConfigMap) string {
- for _, c := range configMaps {
- if env.ValueFrom != nil {
- if env.ValueFrom.ConfigMapKeyRef != nil {
- if env.ValueFrom.ConfigMapKeyRef.Name == c.Name {
- if value, ok := c.Data[env.ValueFrom.ConfigMapKeyRef.Key]; ok {
- return value
- }
- }
- }
- }
- }
-
- return env.Value
-}
-
-// kubeSeccompPaths holds information about a pod YAML's seccomp configuration
-// it holds both container and pod seccomp paths
-type kubeSeccompPaths struct {
- containerPaths map[string]string
- podPath string
-}
-
-// findForContainer checks whether a container has a seccomp path configured for it
-// if not, it returns the podPath, which should always have a value
-func (k *kubeSeccompPaths) findForContainer(ctrName string) string {
- if path, ok := k.containerPaths[ctrName]; ok {
- return path
- }
- return k.podPath
-}
-
-// initializeSeccompPaths takes annotations from the pod object metadata and finds annotations pertaining to seccomp
-// it parses both pod and container level
-// if the annotation is of the form "localhost/%s", the seccomp profile will be set to profileRoot/%s
-func initializeSeccompPaths(annotations map[string]string, profileRoot string) (*kubeSeccompPaths, error) {
- seccompPaths := &kubeSeccompPaths{containerPaths: make(map[string]string)}
- var err error
- if annotations != nil {
- for annKeyValue, seccomp := range annotations {
- // check if it is prefaced with container.seccomp.security.alpha.kubernetes.io/
- prefixAndCtr := strings.Split(annKeyValue, "/")
- if prefixAndCtr[0]+"/" != v1.SeccompContainerAnnotationKeyPrefix {
- continue
- } else if len(prefixAndCtr) != 2 {
- // this could be caused by a user inputting either of
- // container.seccomp.security.alpha.kubernetes.io{,/}
- // both of which are invalid
- return nil, errors.Errorf("Invalid seccomp path: %s", prefixAndCtr[0])
- }
-
- path, err := verifySeccompPath(seccomp, profileRoot)
- if err != nil {
- return nil, err
- }
- seccompPaths.containerPaths[prefixAndCtr[1]] = path
- }
-
- podSeccomp, ok := annotations[v1.SeccompPodAnnotationKey]
- if ok {
- seccompPaths.podPath, err = verifySeccompPath(podSeccomp, profileRoot)
- } else {
- seccompPaths.podPath, err = libpod.DefaultSeccompPath()
- }
- if err != nil {
- return nil, err
- }
- }
- return seccompPaths, nil
-}
-
-// verifySeccompPath takes a path and checks whether it is a default, unconfined, or a path
-// the available options are parsed as defined in https://kubernetes.io/docs/concepts/policy/pod-security-policy/#seccomp
-func verifySeccompPath(path string, profileRoot string) (string, error) {
- switch path {
- case v1.DeprecatedSeccompProfileDockerDefault:
- fallthrough
- case v1.SeccompProfileRuntimeDefault:
- return libpod.DefaultSeccompPath()
- case "unconfined":
- return path, nil
- default:
- parts := strings.Split(path, "/")
- if parts[0] == "localhost" {
- return filepath.Join(profileRoot, parts[1]), nil
- }
- return "", errors.Errorf("invalid seccomp path: %s", path)
- }
-}
-
-func quantityToInt64(quantity *resource.Quantity) (int64, error) {
- if i, ok := quantity.AsInt64(); ok {
- return i, nil
- }
-
- if i, ok := quantity.AsDec().Unscaled(); ok {
- return i, nil
- }
-
- return 0, errors.Errorf("Quantity cannot be represented as int64: %v", quantity)
-}
diff --git a/pkg/domain/infra/abi/play_test.go b/pkg/domain/infra/abi/play_test.go
index 5595476c3..4354a3835 100644
--- a/pkg/domain/infra/abi/play_test.go
+++ b/pkg/domain/infra/abi/play_test.go
@@ -6,34 +6,9 @@ import (
"github.com/stretchr/testify/assert"
v1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
-var configMapList = []v1.ConfigMap{
- {
- TypeMeta: metav1.TypeMeta{
- Kind: "ConfigMap",
- },
- ObjectMeta: metav1.ObjectMeta{
- Name: "bar",
- },
- Data: map[string]string{
- "myvar": "bar",
- },
- },
- {
- TypeMeta: metav1.TypeMeta{
- Kind: "ConfigMap",
- },
- ObjectMeta: metav1.ObjectMeta{
- Name: "foo",
- },
- Data: map[string]string{
- "myvar": "foo",
- },
- },
-}
-
func TestReadConfigMapFromFile(t *testing.T) {
tests := []struct {
name string
@@ -55,11 +30,11 @@ data:
false,
"",
v1.ConfigMap{
- TypeMeta: metav1.TypeMeta{
+ TypeMeta: v12.TypeMeta{
Kind: "ConfigMap",
APIVersion: "v1",
},
- ObjectMeta: metav1.ObjectMeta{
+ ObjectMeta: v12.ObjectMeta{
Name: "foo",
},
Data: map[string]string{
@@ -114,141 +89,3 @@ data:
})
}
}
-
-func TestEnvVarsFromConfigMap(t *testing.T) {
- tests := []struct {
- name string
- envFrom v1.EnvFromSource
- configMapList []v1.ConfigMap
- expected map[string]string
- }{
- {
- "ConfigMapExists",
- v1.EnvFromSource{
- ConfigMapRef: &v1.ConfigMapEnvSource{
- LocalObjectReference: v1.LocalObjectReference{
- Name: "foo",
- },
- },
- },
- configMapList,
- map[string]string{
- "myvar": "foo",
- },
- },
- {
- "ConfigMapDoesNotExist",
- v1.EnvFromSource{
- ConfigMapRef: &v1.ConfigMapEnvSource{
- LocalObjectReference: v1.LocalObjectReference{
- Name: "doesnotexist",
- },
- },
- },
- configMapList,
- map[string]string{},
- },
- {
- "EmptyConfigMapList",
- v1.EnvFromSource{
- ConfigMapRef: &v1.ConfigMapEnvSource{
- LocalObjectReference: v1.LocalObjectReference{
- Name: "foo",
- },
- },
- },
- []v1.ConfigMap{},
- map[string]string{},
- },
- }
-
- for _, test := range tests {
- test := test
- t.Run(test.name, func(t *testing.T) {
- result := envVarsFromConfigMap(test.envFrom, test.configMapList)
- assert.Equal(t, test.expected, result)
- })
- }
-}
-
-func TestEnvVarValue(t *testing.T) {
- tests := []struct {
- name string
- envVar v1.EnvVar
- configMapList []v1.ConfigMap
- expected string
- }{
- {
- "ConfigMapExists",
- v1.EnvVar{
- Name: "FOO",
- ValueFrom: &v1.EnvVarSource{
- ConfigMapKeyRef: &v1.ConfigMapKeySelector{
- LocalObjectReference: v1.LocalObjectReference{
- Name: "foo",
- },
- Key: "myvar",
- },
- },
- },
- configMapList,
- "foo",
- },
- {
- "ContainerKeyDoesNotExistInConfigMap",
- v1.EnvVar{
- Name: "FOO",
- ValueFrom: &v1.EnvVarSource{
- ConfigMapKeyRef: &v1.ConfigMapKeySelector{
- LocalObjectReference: v1.LocalObjectReference{
- Name: "foo",
- },
- Key: "doesnotexist",
- },
- },
- },
- configMapList,
- "",
- },
- {
- "ConfigMapDoesNotExist",
- v1.EnvVar{
- Name: "FOO",
- ValueFrom: &v1.EnvVarSource{
- ConfigMapKeyRef: &v1.ConfigMapKeySelector{
- LocalObjectReference: v1.LocalObjectReference{
- Name: "doesnotexist",
- },
- Key: "myvar",
- },
- },
- },
- configMapList,
- "",
- },
- {
- "EmptyConfigMapList",
- v1.EnvVar{
- Name: "FOO",
- ValueFrom: &v1.EnvVarSource{
- ConfigMapKeyRef: &v1.ConfigMapKeySelector{
- LocalObjectReference: v1.LocalObjectReference{
- Name: "foo",
- },
- Key: "myvar",
- },
- },
- },
- []v1.ConfigMap{},
- "",
- },
- }
-
- for _, test := range tests {
- test := test
- t.Run(test.name, func(t *testing.T) {
- result := envVarValue(test.envVar, test.configMapList)
- assert.Equal(t, test.expected, result)
- })
- }
-}
diff --git a/pkg/domain/infra/abi/pods.go b/pkg/domain/infra/abi/pods.go
index 258640a81..11374e513 100644
--- a/pkg/domain/infra/abi/pods.go
+++ b/pkg/domain/infra/abi/pods.go
@@ -282,20 +282,17 @@ func (ic *ContainerEngine) PodTop(ctx context.Context, options entities.PodTopOp
func (ic *ContainerEngine) PodPs(ctx context.Context, options entities.PodPSOptions) ([]*entities.ListPodsReport, error) {
var (
- err error
- filters = []libpod.PodFilter{}
- pds = []*libpod.Pod{}
+ err error
+ pds = []*libpod.Pod{}
)
+ filters := make([]libpod.PodFilter, 0, len(options.Filters))
for k, v := range options.Filters {
- for _, filter := range v {
- f, err := lpfilters.GeneratePodFilterFunc(k, filter)
- if err != nil {
- return nil, err
- }
- filters = append(filters, f)
-
+ f, err := lpfilters.GeneratePodFilterFunc(k, v)
+ if err != nil {
+ return nil, err
}
+ filters = append(filters, f)
}
if options.Latest {
pod, err := ic.Libpod.GetLatestPod()
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index 57c098166..72fd98ac1 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -17,6 +17,7 @@ import (
"github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/podman/v2/pkg/util"
"github.com/containers/podman/v2/utils"
+ "github.com/containers/storage"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -123,7 +124,7 @@ func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command)
}
}
if err != nil {
- logrus.Error(err)
+ logrus.Error(errors.Wrapf(err, "invalid internal status, try resetting the pause process with %q", os.Args[0]+" system migrate"))
os.Exit(1)
}
if became {
@@ -231,17 +232,25 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System
dfContainers := make([]*entities.SystemDfContainerReport, 0, len(cons))
for _, c := range cons {
iid, _ := c.Image()
- conSize, err := c.RootFsSize()
+ state, err := c.State()
if err != nil {
- return nil, err
+ return nil, errors.Wrapf(err, "Failed to get state of container %s", c.ID())
}
- state, err := c.State()
+ conSize, err := c.RootFsSize()
if err != nil {
- return nil, err
+ if errors.Cause(err) == storage.ErrContainerUnknown {
+ logrus.Error(errors.Wrapf(err, "Failed to get root file system size of container %s", c.ID()))
+ } else {
+ return nil, errors.Wrapf(err, "Failed to get root file system size of container %s", c.ID())
+ }
}
rwsize, err := c.RWSize()
if err != nil {
- return nil, err
+ if errors.Cause(err) == storage.ErrContainerUnknown {
+ logrus.Error(errors.Wrapf(err, "Failed to get read/write size of container %s", c.ID()))
+ } else {
+ return nil, errors.Wrapf(err, "Failed to get read/write size of container %s", c.ID())
+ }
}
report := entities.SystemDfContainerReport{
ContainerID: c.ID(),
diff --git a/pkg/domain/infra/abi/terminal/sigproxy_linux.go b/pkg/domain/infra/abi/terminal/sigproxy_linux.go
index 0c586cf5c..2aca8f22d 100644
--- a/pkg/domain/infra/abi/terminal/sigproxy_linux.go
+++ b/pkg/domain/infra/abi/terminal/sigproxy_linux.go
@@ -5,8 +5,10 @@ import (
"syscall"
"github.com/containers/podman/v2/libpod"
+ "github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/libpod/shutdown"
"github.com/containers/podman/v2/pkg/signal"
+ "github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -33,12 +35,16 @@ func ProxySignals(ctr *libpod.Container) {
}
if err := ctr.Kill(uint(s.(syscall.Signal))); err != nil {
+ if errors.Cause(err) == define.ErrCtrStateInvalid {
+ logrus.Infof("Ceasing signal forwarding to container %s as it has stopped", ctr.ID())
+ } else {
+ logrus.Errorf("Error forwarding signal %d to container %s: %v", s, ctr.ID(), err)
+ }
// If the container dies, and we find out here,
// we need to forward that one signal to
// ourselves so that it is not lost, and then
// we terminate the proxy and let the defaults
// play out.
- logrus.Errorf("Error forwarding signal %d to container %s: %v", s, ctr.ID(), err)
signal.StopCatch(sigBuffer)
if err := syscall.Kill(syscall.Getpid(), s.(syscall.Signal)); err != nil {
logrus.Errorf("failed to kill pid %d", syscall.Getpid())
diff --git a/pkg/domain/infra/runtime_libpod.go b/pkg/domain/infra/runtime_libpod.go
index 26c9c7e2e..b786a5fbf 100644
--- a/pkg/domain/infra/runtime_libpod.go
+++ b/pkg/domain/infra/runtime_libpod.go
@@ -6,8 +6,10 @@ import (
"context"
"fmt"
"os"
+ "os/signal"
"sync"
+ "github.com/containers/podman/v2/cmd/podman/utils"
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/pkg/cgroups"
"github.com/containers/podman/v2/pkg/domain/entities"
@@ -16,6 +18,7 @@ import (
"github.com/containers/storage"
"github.com/containers/storage/pkg/idtools"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
flag "github.com/spf13/pflag"
)
@@ -348,3 +351,24 @@ func ParseIDMapping(mode namespaces.UsernsMode, uidMapSlice, gidMapSlice []strin
}
return &options, nil
}
+
+// StartWatcher starts a new SIGHUP go routine for the current config.
+func StartWatcher(rt *libpod.Runtime) {
+ // Setup the signal notifier
+ ch := make(chan os.Signal, 1)
+ signal.Notify(ch, utils.SIGHUP)
+
+ go func() {
+ for {
+ // Block until the signal is received
+ logrus.Debugf("waiting for SIGHUP to reload configuration")
+ <-ch
+ if err := rt.Reload(); err != nil {
+ logrus.Errorf("unable to reload configuration: %v", err)
+ continue
+ }
+ }
+ }()
+
+ logrus.Debugf("registered SIGHUP watcher for config")
+}
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index 8066e1c00..1aa5afbe7 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -595,12 +595,20 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
// Defer the removal, so we can return early if needed and
// de-spaghetti the code.
defer func() {
- if err := containers.Remove(ic.ClientCxt, con.ID, bindings.PFalse, bindings.PTrue); err != nil {
- if errorhandling.Contains(err, define.ErrNoSuchCtr) ||
- errorhandling.Contains(err, define.ErrCtrRemoved) {
- logrus.Warnf("Container %s does not exist: %v", con.ID, err)
- } else {
- logrus.Errorf("Error removing container %s: %v", con.ID, err)
+ shouldRestart, err := containers.ShouldRestart(ic.ClientCxt, con.ID)
+ if err != nil {
+ logrus.Errorf("Failed to check if %s should restart: %v", con.ID, err)
+ return
+ }
+
+ if !shouldRestart {
+ if err := containers.Remove(ic.ClientCxt, con.ID, bindings.PFalse, bindings.PTrue); err != nil {
+ if errorhandling.Contains(err, define.ErrNoSuchCtr) ||
+ errorhandling.Contains(err, define.ErrCtrRemoved) {
+ logrus.Warnf("Container %s does not exist: %v", con.ID, err)
+ } else {
+ logrus.Errorf("Error removing container %s: %v", con.ID, err)
+ }
}
}
}()
@@ -737,3 +745,8 @@ func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []stri
}
return containers.Stats(ic.ClientCxt, namesOrIds, &options.Stream)
}
+
+// ShouldRestart reports back whether the containre will restart
+func (ic *ContainerEngine) ShouldRestart(_ context.Context, id string) (bool, error) {
+ return containers.ShouldRestart(ic.ClientCxt, id)
+}
diff --git a/pkg/domain/infra/tunnel/network.go b/pkg/domain/infra/tunnel/network.go
index 15527e02c..10ae03045 100644
--- a/pkg/domain/infra/tunnel/network.go
+++ b/pkg/domain/infra/tunnel/network.go
@@ -55,3 +55,13 @@ func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, o
func (ic *ContainerEngine) NetworkCreate(ctx context.Context, name string, options entities.NetworkCreateOptions) (*entities.NetworkCreateReport, error) {
return network.Create(ic.ClientCxt, options, &name)
}
+
+// NetworkDisconnect removes a container from a given network
+func (ic *ContainerEngine) NetworkDisconnect(ctx context.Context, networkname string, options entities.NetworkDisconnectOptions) error {
+ return network.Disconnect(ic.ClientCxt, networkname, options)
+}
+
+// NetworkConnect removes a container from a given network
+func (ic *ContainerEngine) NetworkConnect(ctx context.Context, networkname string, options entities.NetworkConnectOptions) error {
+ return network.Connect(ic.ClientCxt, networkname, options)
+}