summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/compat/containers_prune.go62
-rw-r--r--pkg/api/handlers/compat/images.go45
-rw-r--r--pkg/api/handlers/compat/images_prune.go75
-rw-r--r--pkg/api/handlers/compat/volumes.go32
-rw-r--r--pkg/api/handlers/libpod/containers.go1
-rw-r--r--pkg/api/handlers/libpod/images.go7
-rw-r--r--pkg/api/handlers/libpod/pods.go11
-rw-r--r--pkg/api/handlers/libpod/system.go21
-rw-r--r--pkg/api/handlers/libpod/volumes.go12
-rw-r--r--pkg/api/handlers/utils/pods.go87
-rw-r--r--pkg/api/server/docs.go2
-rw-r--r--pkg/api/server/register_networks.go13
-rw-r--r--pkg/api/server/swagger.go3
-rw-r--r--pkg/bindings/containers/containers.go5
-rw-r--r--pkg/bindings/images/images.go8
-rw-r--r--pkg/bindings/test/containers_test.go15
-rw-r--r--pkg/bindings/test/images_test.go3
-rw-r--r--pkg/bindings/test/system_test.go35
-rw-r--r--pkg/bindings/test/volumes_test.go3
-rw-r--r--pkg/bindings/volumes/volumes.go5
-rw-r--r--pkg/checkpoint/checkpoint_restore.go29
-rw-r--r--pkg/domain/entities/container_ps.go2
-rw-r--r--pkg/domain/entities/containers.go12
-rw-r--r--pkg/domain/entities/engine_container.go5
-rw-r--r--pkg/domain/entities/engine_image.go3
-rw-r--r--pkg/domain/entities/images.go5
-rw-r--r--pkg/domain/entities/play.go3
-rw-r--r--pkg/domain/entities/pods.go6
-rw-r--r--pkg/domain/entities/reports/prune.go40
-rw-r--r--pkg/domain/entities/system.go10
-rw-r--r--pkg/domain/entities/volumes.go5
-rw-r--r--pkg/domain/filters/containers.go22
-rw-r--r--pkg/domain/filters/pods.go26
-rw-r--r--pkg/domain/filters/volumes.go4
-rw-r--r--pkg/domain/infra/abi/containers.go44
-rw-r--r--pkg/domain/infra/abi/images.go17
-rw-r--r--pkg/domain/infra/abi/images_list.go5
-rw-r--r--pkg/domain/infra/abi/manifest.go3
-rw-r--r--pkg/domain/infra/abi/play.go17
-rw-r--r--pkg/domain/infra/abi/pods.go12
-rw-r--r--pkg/domain/infra/abi/system.go41
-rw-r--r--pkg/domain/infra/abi/volumes.go14
-rw-r--r--pkg/domain/infra/tunnel/containers.go3
-rw-r--r--pkg/domain/infra/tunnel/images.go15
-rw-r--r--pkg/domain/infra/tunnel/volumes.go3
-rw-r--r--pkg/netns/netns_linux.go4
-rw-r--r--pkg/ps/ps.go6
-rw-r--r--pkg/rootless/rootless.go153
-rw-r--r--pkg/rootless/rootless_test.go101
-rw-r--r--pkg/signal/signal_linux_mipsx.go2
-rw-r--r--pkg/specgen/generate/config_linux.go3
-rw-r--r--pkg/specgen/generate/container.go30
-rw-r--r--pkg/specgen/generate/namespaces.go4
-rw-r--r--pkg/specgen/generate/oci.go2
-rw-r--r--pkg/specgen/generate/security.go13
-rw-r--r--pkg/specgen/generate/storage.go8
-rw-r--r--pkg/specgen/generate/validate.go2
-rw-r--r--pkg/systemd/generate/common.go32
-rw-r--r--pkg/systemd/generate/containers.go86
-rw-r--r--pkg/systemd/generate/containers_test.go308
-rw-r--r--pkg/systemd/generate/pods.go46
-rw-r--r--pkg/systemd/generate/pods_test.go122
62 files changed, 1188 insertions, 525 deletions
diff --git a/pkg/api/handlers/compat/containers_prune.go b/pkg/api/handlers/compat/containers_prune.go
index a1e35dd97..7bba38475 100644
--- a/pkg/api/handlers/compat/containers_prune.go
+++ b/pkg/api/handlers/compat/containers_prune.go
@@ -1,22 +1,19 @@
package compat
import (
+ "bytes"
"net/http"
"github.com/containers/podman/v2/libpod"
+ "github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/api/handlers/utils"
- "github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/containers/podman/v2/pkg/domain/filters"
- "github.com/docker/docker/api/types"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
func PruneContainers(w http.ResponseWriter, r *http.Request) {
- var (
- delContainers []string
- space int64
- )
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
@@ -37,48 +34,45 @@ func PruneContainers(w http.ResponseWriter, r *http.Request) {
filterFuncs = append(filterFuncs, generatedFunc)
}
+ report, err := PruneContainersHelper(r, filterFuncs)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+
// Libpod response differs
if utils.IsLibpodRequest(r) {
- report, err := PruneContainersHelper(w, r, filterFuncs)
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
-
utils.WriteResponse(w, http.StatusOK, report)
return
}
- prunedContainers, pruneErrors, err := runtime.PruneContainers(filterFuncs)
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
- for ctrID, size := range prunedContainers {
- if pruneErrors[ctrID] == nil {
- space += size
- delContainers = append(delContainers, ctrID)
+ var payload handlers.ContainersPruneReport
+ var errorMsg bytes.Buffer
+ for _, pr := range report {
+ if pr.Err != nil {
+ // Docker stops on first error vs. libpod which keeps going. Given API constraints, concatenate all errors
+ // and return that string.
+ errorMsg.WriteString(pr.Err.Error())
+ errorMsg.WriteString("; ")
+ continue
}
+ payload.ContainersDeleted = append(payload.ContainersDeleted, pr.Id)
+ payload.SpaceReclaimed += pr.Size
}
- report := types.ContainersPruneReport{
- ContainersDeleted: delContainers,
- SpaceReclaimed: uint64(space),
+ if errorMsg.Len() > 0 {
+ utils.InternalServerError(w, errors.New(errorMsg.String()))
+ return
}
- utils.WriteResponse(w, http.StatusOK, report)
+
+ utils.WriteResponse(w, http.StatusOK, payload)
}
-func PruneContainersHelper(w http.ResponseWriter, r *http.Request, filterFuncs []libpod.ContainerFilter) (
- *entities.ContainerPruneReport, error) {
+func PruneContainersHelper(r *http.Request, filterFuncs []libpod.ContainerFilter) ([]*reports.PruneReport, error) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
- prunedContainers, pruneErrors, err := runtime.PruneContainers(filterFuncs)
+
+ report, err := runtime.PruneContainers(filterFuncs)
if err != nil {
- utils.InternalServerError(w, err)
return nil, err
}
-
- report := &entities.ContainerPruneReport{
- Err: pruneErrors,
- ID: prunedContainers,
- }
return report, nil
}
diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go
index dc72500e4..0ae0f3bcf 100644
--- a/pkg/api/handlers/compat/images.go
+++ b/pkg/api/handlers/compat/images.go
@@ -18,7 +18,6 @@ import (
"github.com/containers/podman/v2/pkg/api/handlers/utils"
"github.com/containers/podman/v2/pkg/auth"
"github.com/containers/podman/v2/pkg/domain/entities"
- "github.com/docker/docker/api/types"
"github.com/gorilla/schema"
"github.com/opencontainers/go-digest"
"github.com/pkg/errors"
@@ -74,50 +73,6 @@ func ExportImage(w http.ResponseWriter, r *http.Request) {
utils.WriteResponse(w, http.StatusOK, rdr)
}
-func PruneImages(w http.ResponseWriter, r *http.Request) {
- var (
- filters []string
- )
- decoder := r.Context().Value("decoder").(*schema.Decoder)
- runtime := r.Context().Value("runtime").(*libpod.Runtime)
-
- query := struct {
- All bool
- Filters map[string][]string `schema:"filters"`
- }{
- // This is where you can override the golang default value for one of fields
- }
-
- if err := decoder.Decode(&query, r.URL.Query()); err != nil {
- utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
- return
- }
-
- idr := []types.ImageDeleteResponseItem{}
- for k, v := range query.Filters {
- for _, val := range v {
- filters = append(filters, fmt.Sprintf("%s=%s", k, val))
- }
- }
- pruneCids, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, filters)
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
- for _, p := range pruneCids {
- idr = append(idr, types.ImageDeleteResponseItem{
- Deleted: p,
- })
- }
-
- // FIXME/TODO to do this exactly correct, pruneimages needs to return idrs and space-reclaimed, then we are golden
- ipr := types.ImagesPruneReport{
- ImagesDeleted: idr,
- SpaceReclaimed: 1, // TODO we cannot supply this right now
- }
- utils.WriteResponse(w, http.StatusOK, handlers.ImagesPruneReport{ImagesPruneReport: ipr})
-}
-
func CommitContainer(w http.ResponseWriter, r *http.Request) {
var (
destImage string
diff --git a/pkg/api/handlers/compat/images_prune.go b/pkg/api/handlers/compat/images_prune.go
new file mode 100644
index 000000000..c7e84804b
--- /dev/null
+++ b/pkg/api/handlers/compat/images_prune.go
@@ -0,0 +1,75 @@
+package compat
+
+import (
+ "bytes"
+ "fmt"
+ "net/http"
+
+ "github.com/containers/podman/v2/libpod"
+ "github.com/containers/podman/v2/pkg/api/handlers"
+ "github.com/containers/podman/v2/pkg/api/handlers/utils"
+ "github.com/docker/docker/api/types"
+ "github.com/gorilla/schema"
+ "github.com/pkg/errors"
+)
+
+func PruneImages(w http.ResponseWriter, r *http.Request) {
+ var (
+ filters []string
+ )
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+
+ query := struct {
+ All bool
+ Filters map[string][]string `schema:"filters"`
+ }{
+ // This is where you can override the golang default value for one of fields
+ }
+
+ if err := decoder.Decode(&query, r.URL.Query()); err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
+ return
+ }
+
+ for k, v := range query.Filters {
+ for _, val := range v {
+ filters = append(filters, fmt.Sprintf("%s=%s", k, val))
+ }
+ }
+ imagePruneReports, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, filters)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+
+ idr := make([]types.ImageDeleteResponseItem, len(imagePruneReports))
+ var reclaimedSpace uint64
+ var errorMsg bytes.Buffer
+ for _, p := range imagePruneReports {
+ if p.Err != nil {
+ // Docker stops on first error vs. libpod which keeps going. Given API constraints, concatenate all errors
+ // and return that string.
+ errorMsg.WriteString(p.Err.Error())
+ errorMsg.WriteString("; ")
+ continue
+ }
+
+ idr = append(idr, types.ImageDeleteResponseItem{
+ Deleted: p.Id,
+ })
+ reclaimedSpace = reclaimedSpace + p.Size
+ }
+ if errorMsg.Len() > 0 {
+ utils.InternalServerError(w, errors.New(errorMsg.String()))
+ return
+ }
+
+ payload := handlers.ImagesPruneReport{
+ ImagesPruneReport: types.ImagesPruneReport{
+ ImagesDeleted: idr,
+ SpaceReclaimed: reclaimedSpace,
+ },
+ }
+ utils.WriteResponse(w, http.StatusOK, payload)
+}
diff --git a/pkg/api/handlers/compat/volumes.go b/pkg/api/handlers/compat/volumes.go
index f49f06b17..4903bbad4 100644
--- a/pkg/api/handlers/compat/volumes.go
+++ b/pkg/api/handlers/compat/volumes.go
@@ -1,6 +1,7 @@
package compat
import (
+ "bytes"
"encoding/json"
"net/http"
"net/url"
@@ -8,6 +9,7 @@ import (
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/define"
+ "github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/api/handlers/utils"
"github.com/containers/podman/v2/pkg/domain/filters"
"github.com/containers/podman/v2/pkg/domain/infra/abi/parse"
@@ -268,17 +270,29 @@ func PruneVolumes(w http.ResponseWriter, r *http.Request) {
utils.InternalServerError(w, err)
return
}
+
+ var errorMsg bytes.Buffer
+ var reclaimedSpace uint64
prunedIds := make([]string, 0, len(pruned))
- for k := range pruned {
- // XXX: This drops any pruning per-volume error messages on the floor
- prunedIds = append(prunedIds, k)
+ for _, v := range pruned {
+ if v.Err != nil {
+ errorMsg.WriteString(v.Err.Error())
+ errorMsg.WriteString("; ")
+ continue
+ }
+ prunedIds = append(prunedIds, v.Id)
+ reclaimedSpace += v.Size
}
- pruneResponse := docker_api_types.VolumesPruneReport{
- VolumesDeleted: prunedIds,
- // TODO: We don't have any insight into how much space was reclaimed
- // from `PruneVolumes()` but it's not nullable
- SpaceReclaimed: 0,
+ if errorMsg.Len() > 0 {
+ utils.InternalServerError(w, errors.New(errorMsg.String()))
+ return
}
- utils.WriteResponse(w, http.StatusOK, pruneResponse)
+ payload := handlers.VolumesPruneReport{
+ VolumesPruneReport: docker_api_types.VolumesPruneReport{
+ VolumesDeleted: prunedIds,
+ SpaceReclaimed: reclaimedSpace,
+ },
+ }
+ utils.WriteResponse(w, http.StatusOK, payload)
}
diff --git a/pkg/api/handlers/libpod/containers.go b/pkg/api/handlers/libpod/containers.go
index 14eb44831..6b07b1cc5 100644
--- a/pkg/api/handlers/libpod/containers.go
+++ b/pkg/api/handlers/libpod/containers.go
@@ -275,6 +275,7 @@ func Restore(w http.ResponseWriter, r *http.Request) {
Import bool `schema:"import"`
Name string `schema:"name"`
IgnoreRootFS bool `schema:"ignoreRootFS"`
+ IgnoreVolumes bool `schema:"ignoreVolumes"`
IgnoreStaticIP bool `schema:"ignoreStaticIP"`
IgnoreStaticMAC bool `schema:"ignoreStaticMAC"`
}{
diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go
index 0b8712f16..b2b93de17 100644
--- a/pkg/api/handlers/libpod/images.go
+++ b/pkg/api/handlers/libpod/images.go
@@ -16,7 +16,6 @@ import (
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/libpod/image"
- image2 "github.com/containers/podman/v2/libpod/image"
"github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/api/handlers/utils"
"github.com/containers/podman/v2/pkg/auth"
@@ -156,12 +155,12 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
}
}
- cids, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, libpodFilters)
+ imagePruneReports, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, libpodFilters)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
return
}
- utils.WriteResponse(w, http.StatusOK, cids)
+ utils.WriteResponse(w, http.StatusOK, imagePruneReports)
}
func ExportImage(w http.ResponseWriter, r *http.Request) {
@@ -524,7 +523,7 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "failed to get runtime config", http.StatusInternalServerError, errors.Wrap(err, "failed to get runtime config"))
return
}
- sc := image2.GetSystemContext(rtc.Engine.SignaturePolicyPath, "", false)
+ sc := image.GetSystemContext(rtc.Engine.SignaturePolicyPath, "", false)
tag := "latest"
options := libpod.ContainerCommitOptions{
Pause: true,
diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go
index 5422411cf..2409d3a20 100644
--- a/pkg/api/handlers/libpod/pods.go
+++ b/pkg/api/handlers/libpod/pods.go
@@ -43,6 +43,7 @@ func PodCreate(w http.ResponseWriter, r *http.Request) {
}
func Pods(w http.ResponseWriter, r *http.Request) {
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
Filters map[string][]string `schema:"filters"`
@@ -55,7 +56,11 @@ func Pods(w http.ResponseWriter, r *http.Request) {
return
}
- pods, err := utils.GetPods(w, r)
+ containerEngine := abi.ContainerEngine{Libpod: runtime}
+ podPSOptions := entities.PodPSOptions{
+ Filters: query.Filters,
+ }
+ pods, err := containerEngine.PodPs(r.Context(), podPSOptions)
if err != nil {
utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
return
@@ -235,7 +240,7 @@ func PodRestart(w http.ResponseWriter, r *http.Request) {
}
func PodPrune(w http.ResponseWriter, r *http.Request) {
- reports, err := PodPruneHelper(w, r)
+ reports, err := PodPruneHelper(r)
if err != nil {
utils.InternalServerError(w, err)
return
@@ -243,7 +248,7 @@ func PodPrune(w http.ResponseWriter, r *http.Request) {
utils.WriteResponse(w, http.StatusOK, reports)
}
-func PodPruneHelper(w http.ResponseWriter, r *http.Request) ([]*entities.PodPruneReport, error) {
+func PodPruneHelper(r *http.Request) ([]*entities.PodPruneReport, error) {
var (
runtime = r.Context().Value("runtime").(*libpod.Runtime)
)
diff --git a/pkg/api/handlers/libpod/system.go b/pkg/api/handlers/libpod/system.go
index b157dfc7b..c48c186ed 100644
--- a/pkg/api/handlers/libpod/system.go
+++ b/pkg/api/handlers/libpod/system.go
@@ -30,7 +30,7 @@ func SystemPrune(w http.ResponseWriter, r *http.Request) {
return
}
- podPruneReport, err := PodPruneHelper(w, r)
+ podPruneReport, err := PodPruneHelper(r)
if err != nil {
utils.InternalServerError(w, err)
return
@@ -38,35 +38,28 @@ func SystemPrune(w http.ResponseWriter, r *http.Request) {
systemPruneReport.PodPruneReport = podPruneReport
// We could parallelize this, should we?
- containerPruneReport, err := compat.PruneContainersHelper(w, r, nil)
+ containerPruneReports, err := compat.PruneContainersHelper(r, nil)
if err != nil {
utils.InternalServerError(w, err)
return
}
- systemPruneReport.ContainerPruneReport = containerPruneReport
+ systemPruneReport.ContainerPruneReports = containerPruneReports
- results, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, nil)
+ imagePruneReports, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, nil)
if err != nil {
utils.InternalServerError(w, err)
return
}
- report := entities.ImagePruneReport{
- Report: entities.Report{
- Id: results,
- Err: nil,
- },
- }
-
- systemPruneReport.ImagePruneReport = &report
+ systemPruneReport.ImagePruneReports = imagePruneReports
if query.Volumes {
- volumePruneReport, err := pruneVolumesHelper(r)
+ volumePruneReports, err := pruneVolumesHelper(r)
if err != nil {
utils.InternalServerError(w, err)
return
}
- systemPruneReport.VolumePruneReport = volumePruneReport
+ systemPruneReport.VolumePruneReports = volumePruneReports
}
utils.WriteResponse(w, http.StatusOK, systemPruneReport)
}
diff --git a/pkg/api/handlers/libpod/volumes.go b/pkg/api/handlers/libpod/volumes.go
index b02a6a8ce..6f9537515 100644
--- a/pkg/api/handlers/libpod/volumes.go
+++ b/pkg/api/handlers/libpod/volumes.go
@@ -9,6 +9,7 @@ import (
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/api/handlers/utils"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/containers/podman/v2/pkg/domain/filters"
"github.com/containers/podman/v2/pkg/domain/infra/abi/parse"
"github.com/gorilla/schema"
@@ -178,7 +179,7 @@ func PruneVolumes(w http.ResponseWriter, r *http.Request) {
utils.WriteResponse(w, http.StatusOK, reports)
}
-func pruneVolumesHelper(r *http.Request) ([]*entities.VolumePruneReport, error) {
+func pruneVolumesHelper(r *http.Request) ([]*reports.PruneReport, error) {
var (
runtime = r.Context().Value("runtime").(*libpod.Runtime)
decoder = r.Context().Value("decoder").(*schema.Decoder)
@@ -199,17 +200,10 @@ func pruneVolumesHelper(r *http.Request) ([]*entities.VolumePruneReport, error)
return nil, err
}
- pruned, err := runtime.PruneVolumes(r.Context(), filterFuncs)
+ reports, err := runtime.PruneVolumes(r.Context(), filterFuncs)
if err != nil {
return nil, err
}
- reports := make([]*entities.VolumePruneReport, 0, len(pruned))
- for k, v := range pruned {
- reports = append(reports, &entities.VolumePruneReport{
- Err: v,
- Id: k,
- })
- }
return reports, nil
}
func RemoveVolume(w http.ResponseWriter, r *http.Request) {
diff --git a/pkg/api/handlers/utils/pods.go b/pkg/api/handlers/utils/pods.go
deleted file mode 100644
index 0fe3a308b..000000000
--- a/pkg/api/handlers/utils/pods.go
+++ /dev/null
@@ -1,87 +0,0 @@
-package utils
-
-import (
- "net/http"
-
- "github.com/containers/podman/v2/libpod"
- "github.com/containers/podman/v2/pkg/domain/entities"
- dfilters "github.com/containers/podman/v2/pkg/domain/filters"
- "github.com/gorilla/schema"
-)
-
-func GetPods(w http.ResponseWriter, r *http.Request) ([]*entities.ListPodsReport, error) {
- var (
- pods []*libpod.Pod
- )
- runtime := r.Context().Value("runtime").(*libpod.Runtime)
- decoder := r.Context().Value("decoder").(*schema.Decoder)
-
- query := struct {
- All bool
- Filters map[string][]string `schema:"filters"`
- Digests bool
- }{}
-
- if err := decoder.Decode(&query, r.URL.Query()); err != nil {
- return nil, err
- }
- if _, found := r.URL.Query()["digests"]; found && query.Digests {
- UnSupportedParameter("digests")
- }
-
- filters := make([]libpod.PodFilter, 0, len(query.Filters))
- for k, v := range query.Filters {
- f, err := dfilters.GeneratePodFilterFunc(k, v)
- if err != nil {
- return nil, err
- }
- filters = append(filters, f)
- }
- pods, err := runtime.Pods(filters...)
- if err != nil {
- return nil, err
- }
-
- if len(pods) == 0 {
- return []*entities.ListPodsReport{}, nil
- }
-
- lps := make([]*entities.ListPodsReport, 0, len(pods))
- for _, pod := range pods {
- status, err := pod.GetPodStatus()
- if err != nil {
- return nil, err
- }
- ctrs, err := pod.AllContainers()
- if err != nil {
- return nil, err
- }
- infraID, err := pod.InfraContainerID()
- if err != nil {
- return nil, err
- }
- lp := entities.ListPodsReport{
- Cgroup: pod.CgroupParent(),
- Created: pod.CreatedTime(),
- Id: pod.ID(),
- Name: pod.Name(),
- Namespace: pod.Namespace(),
- Status: status,
- InfraId: infraID,
- Labels: pod.Labels(),
- }
- for _, ctr := range ctrs {
- state, err := ctr.State()
- if err != nil {
- return nil, err
- }
- lp.Containers = append(lp.Containers, &entities.ListPodContainer{
- Id: ctr.ID(),
- Names: ctr.Name(),
- Status: state.String(),
- })
- }
- lps = append(lps, &lp)
- }
- return lps, nil
-}
diff --git a/pkg/api/server/docs.go b/pkg/api/server/docs.go
index 1aaf31117..a99fefd7b 100644
--- a/pkg/api/server/docs.go
+++ b/pkg/api/server/docs.go
@@ -13,7 +13,7 @@
// You can then use cURL on the socket using requests documented below.
//
// NOTE: if you install the package podman-docker, it will create a symbolic
-// link for /var/run/docker.sock to /run/podman/podman.sock
+// link for /run/docker.sock to /run/podman/podman.sock
//
// See podman-service(1) for more information.
//
diff --git a/pkg/api/server/register_networks.go b/pkg/api/server/register_networks.go
index e6c85d244..967d7da76 100644
--- a/pkg/api/server/register_networks.go
+++ b/pkg/api/server/register_networks.go
@@ -9,6 +9,19 @@ import (
)
func (s *APIServer) registerNetworkHandlers(r *mux.Router) error {
+ // swagger:operation POST /networks/prune compat compatPruneNetwork
+ // ---
+ // tags:
+ // - networks (compat)
+ // Summary: Delete unused networks
+ // description: Not supported
+ // produces:
+ // - application/json
+ // responses:
+ // 404:
+ // $ref: "#/responses/NoSuchNetwork"
+ r.HandleFunc(VersionedPath("/networks/prune"), compat.UnsupportedHandler).Methods(http.MethodPost)
+ r.HandleFunc("/networks/prune", compat.UnsupportedHandler).Methods(http.MethodPost)
// swagger:operation DELETE /networks/{name} compat compatRemoveNetwork
// ---
// tags:
diff --git a/pkg/api/server/swagger.go b/pkg/api/server/swagger.go
index 6d349bb7d..45253e01a 100644
--- a/pkg/api/server/swagger.go
+++ b/pkg/api/server/swagger.go
@@ -4,6 +4,7 @@ import (
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
)
// No such image
@@ -170,7 +171,7 @@ type ok struct {
// swagger:response VolumePruneResponse
type swagVolumePruneResponse struct {
// in:body
- Body []entities.VolumePruneReport
+ Body []reports.PruneReport
}
// Volume create response
diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go
index 650aa9ac5..1081a0e61 100644
--- a/pkg/bindings/containers/containers.go
+++ b/pkg/bindings/containers/containers.go
@@ -12,6 +12,7 @@ import (
"github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -49,11 +50,11 @@ func List(ctx context.Context, options *ListOptions) ([]entities.ListContainer,
// used for more granular selection of containers. The main error returned indicates if there were runtime
// errors like finding containers. Errors specific to the removal of a container are in the PruneContainerResponse
// structure.
-func Prune(ctx context.Context, options *PruneOptions) (*entities.ContainerPruneReport, error) {
+func Prune(ctx context.Context, options *PruneOptions) ([]*reports.PruneReport, error) {
if options == nil {
options = new(PruneOptions)
}
- var reports *entities.ContainerPruneReport
+ var reports []*reports.PruneReport
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
diff --git a/pkg/bindings/images/images.go b/pkg/bindings/images/images.go
index 9beb493c8..ecdd1f553 100644
--- a/pkg/bindings/images/images.go
+++ b/pkg/bindings/images/images.go
@@ -12,6 +12,7 @@ import (
"github.com/containers/podman/v2/pkg/auth"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/pkg/errors"
)
@@ -163,9 +164,9 @@ func Export(ctx context.Context, nameOrIDs []string, w io.Writer, options *Expor
// Prune removes unused images from local storage. The optional filters can be used to further
// define which images should be pruned.
-func Prune(ctx context.Context, options *PruneOptions) ([]string, error) {
+func Prune(ctx context.Context, options *PruneOptions) ([]*reports.PruneReport, error) {
var (
- deleted []string
+ deleted []*reports.PruneReport
)
if options == nil {
options = new(PruneOptions)
@@ -182,7 +183,8 @@ func Prune(ctx context.Context, options *PruneOptions) ([]string, error) {
if err != nil {
return deleted, err
}
- return deleted, response.Process(&deleted)
+ err = response.Process(&deleted)
+ return deleted, err
}
// Tag adds an additional name to locally-stored image. Both the tag and repo parameters are required.
diff --git a/pkg/bindings/test/containers_test.go b/pkg/bindings/test/containers_test.go
index 2ab5e45d0..fa601e7e5 100644
--- a/pkg/bindings/test/containers_test.go
+++ b/pkg/bindings/test/containers_test.go
@@ -8,6 +8,7 @@ import (
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/bindings/containers"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/containers/podman/v2/pkg/specgen"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
@@ -533,8 +534,8 @@ var _ = Describe("Podman containers ", func() {
// Prune container should return no errors and one pruned container ID.
pruneResponse, err := containers.Prune(bt.conn, nil)
Expect(err).To(BeNil())
- Expect(len(pruneResponse.Err)).To(Equal(0))
- Expect(len(pruneResponse.ID)).To(Equal(1))
+ Expect(len(reports.PruneReportsErrs(pruneResponse))).To(Equal(0))
+ Expect(len(reports.PruneReportsIds(pruneResponse))).To(Equal(1))
})
It("podman prune stopped containers with filters", func() {
@@ -558,8 +559,8 @@ var _ = Describe("Podman containers ", func() {
}
pruneResponse, err = containers.Prune(bt.conn, new(containers.PruneOptions).WithFilters(filtersIncorrect))
Expect(err).To(BeNil())
- Expect(len(pruneResponse.Err)).To(Equal(0))
- Expect(len(pruneResponse.ID)).To(Equal(0))
+ Expect(len(reports.PruneReportsIds(pruneResponse))).To(Equal(0))
+ Expect(len(reports.PruneReportsErrs(pruneResponse))).To(Equal(0))
// Valid filter params container should be pruned now.
filters := map[string][]string{
@@ -567,8 +568,8 @@ var _ = Describe("Podman containers ", func() {
}
pruneResponse, err = containers.Prune(bt.conn, new(containers.PruneOptions).WithFilters(filters))
Expect(err).To(BeNil())
- Expect(len(pruneResponse.Err)).To(Equal(0))
- Expect(len(pruneResponse.ID)).To(Equal(1))
+ Expect(len(reports.PruneReportsErrs(pruneResponse))).To(Equal(0))
+ Expect(len(reports.PruneReportsIds(pruneResponse))).To(Equal(1))
})
It("podman prune running containers", func() {
@@ -585,7 +586,7 @@ var _ = Describe("Podman containers ", func() {
// Prune. Should return no error no prune response ID.
pruneResponse, err := containers.Prune(bt.conn, nil)
Expect(err).To(BeNil())
- Expect(len(pruneResponse.ID)).To(Equal(0))
+ Expect(len(pruneResponse)).To(Equal(0))
})
It("podman inspect bogus container", func() {
diff --git a/pkg/bindings/test/images_test.go b/pkg/bindings/test/images_test.go
index e178f4219..c6b9c20f9 100644
--- a/pkg/bindings/test/images_test.go
+++ b/pkg/bindings/test/images_test.go
@@ -9,6 +9,7 @@ import (
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/bindings/containers"
"github.com/containers/podman/v2/pkg/bindings/images"
+ dreports "github.com/containers/podman/v2/pkg/domain/entities/reports"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec"
@@ -355,7 +356,7 @@ var _ = Describe("Podman images", func() {
results, err := images.Prune(bt.conn, options)
Expect(err).NotTo(HaveOccurred())
Expect(len(results)).To(BeNumerically(">", 0))
- Expect(results).To(ContainElement("docker.io/library/alpine:latest"))
+ Expect(dreports.PruneReportsIds(results)).To(ContainElement("docker.io/library/alpine:latest"))
})
// TODO: we really need to extent to pull tests once we have a more sophisticated CI.
diff --git a/pkg/bindings/test/system_test.go b/pkg/bindings/test/system_test.go
index 25fda5575..44067b61d 100644
--- a/pkg/bindings/test/system_test.go
+++ b/pkg/bindings/test/system_test.go
@@ -10,6 +10,7 @@ import (
"github.com/containers/podman/v2/pkg/bindings/system"
"github.com/containers/podman/v2/pkg/bindings/volumes"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec"
@@ -80,12 +81,12 @@ var _ = Describe("Podman system", func() {
systemPruneResponse, err := system.Prune(bt.conn, options)
Expect(err).To(BeNil())
Expect(len(systemPruneResponse.PodPruneReport)).To(Equal(1))
- Expect(len(systemPruneResponse.ContainerPruneReport.ID)).To(Equal(1))
- Expect(len(systemPruneResponse.ImagePruneReport.Report.Id)).
+ Expect(len(systemPruneResponse.ContainerPruneReports)).To(Equal(1))
+ Expect(len(systemPruneResponse.ImagePruneReports)).
To(BeNumerically(">", 0))
- Expect(systemPruneResponse.ImagePruneReport.Report.Id).
+ Expect(reports.PruneReportsIds(systemPruneResponse.ImagePruneReports)).
To(ContainElement("docker.io/library/alpine:latest"))
- Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(0))
+ Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(0))
})
It("podman system prune running alpine container", func() {
@@ -114,14 +115,14 @@ var _ = Describe("Podman system", func() {
systemPruneResponse, err := system.Prune(bt.conn, options)
Expect(err).To(BeNil())
Expect(len(systemPruneResponse.PodPruneReport)).To(Equal(1))
- Expect(len(systemPruneResponse.ContainerPruneReport.ID)).To(Equal(1))
- Expect(len(systemPruneResponse.ImagePruneReport.Report.Id)).
+ Expect(len(systemPruneResponse.ContainerPruneReports)).To(Equal(1))
+ Expect(len(systemPruneResponse.ImagePruneReports)).
To(BeNumerically(">", 0))
// Alpine image should not be pruned as used by running container
- Expect(systemPruneResponse.ImagePruneReport.Report.Id).
+ Expect(reports.PruneReportsIds(systemPruneResponse.ImagePruneReports)).
ToNot(ContainElement("docker.io/library/alpine:latest"))
// Though unused volume is available it should not be pruned as flag set to false.
- Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(0))
+ Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(0))
})
It("podman system prune running alpine container volume prune", func() {
@@ -149,14 +150,14 @@ var _ = Describe("Podman system", func() {
systemPruneResponse, err := system.Prune(bt.conn, options)
Expect(err).To(BeNil())
Expect(len(systemPruneResponse.PodPruneReport)).To(Equal(0))
- Expect(len(systemPruneResponse.ContainerPruneReport.ID)).To(Equal(1))
- Expect(len(systemPruneResponse.ImagePruneReport.Report.Id)).
+ Expect(len(systemPruneResponse.ContainerPruneReports)).To(Equal(1))
+ Expect(len(systemPruneResponse.ImagePruneReports)).
To(BeNumerically(">", 0))
// Alpine image should not be pruned as used by running container
- Expect(systemPruneResponse.ImagePruneReport.Report.Id).
+ Expect(reports.PruneReportsIds(systemPruneResponse.ImagePruneReports)).
ToNot(ContainElement("docker.io/library/alpine:latest"))
// Volume should be pruned now as flag set true
- Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(1))
+ Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(1))
})
It("podman system prune running alpine container volume prune --filter", func() {
@@ -197,14 +198,14 @@ var _ = Describe("Podman system", func() {
// This check **should** be "Equal(0)" since we are passing label
// filters however the Prune function doesn't seem to pass filters
// to each component.
- Expect(len(systemPruneResponse.ContainerPruneReport.ID)).To(Equal(1))
- Expect(len(systemPruneResponse.ImagePruneReport.Report.Id)).
+ Expect(len(systemPruneResponse.ContainerPruneReports)).To(Equal(1))
+ Expect(len(systemPruneResponse.ImagePruneReports)).
To(BeNumerically(">", 0))
// Alpine image should not be pruned as used by running container
- Expect(systemPruneResponse.ImagePruneReport.Report.Id).
+ Expect(reports.PruneReportsIds(systemPruneResponse.ImagePruneReports)).
ToNot(ContainElement("docker.io/library/alpine:latest"))
// Volume shouldn't be pruned because the PruneOptions filters doesn't match
- Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(0))
+ Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(0))
// Fix filter and re prune
f["label"] = []string{"label1=value1"}
@@ -213,6 +214,6 @@ var _ = Describe("Podman system", func() {
Expect(err).To(BeNil())
// Volume should be pruned because the PruneOptions filters now match
- Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(1))
+ Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(1))
})
})
diff --git a/pkg/bindings/test/volumes_test.go b/pkg/bindings/test/volumes_test.go
index e0d854b66..1f1da3cfa 100644
--- a/pkg/bindings/test/volumes_test.go
+++ b/pkg/bindings/test/volumes_test.go
@@ -10,6 +10,7 @@ import (
"github.com/containers/podman/v2/pkg/bindings/containers"
"github.com/containers/podman/v2/pkg/bindings/volumes"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec"
@@ -166,7 +167,7 @@ var _ = Describe("Podman volumes", func() {
session.Wait(45)
vols, err = volumes.Prune(connText, nil)
Expect(err).To(BeNil())
- Expect(len(vols)).To(BeNumerically("==", 1))
+ Expect(len(reports.PruneReportsIds(vols))).To(BeNumerically("==", 1))
_, err = volumes.Inspect(connText, "homer", nil)
Expect(err).To(BeNil())
diff --git a/pkg/bindings/volumes/volumes.go b/pkg/bindings/volumes/volumes.go
index 626f52d39..fe081eb46 100644
--- a/pkg/bindings/volumes/volumes.go
+++ b/pkg/bindings/volumes/volumes.go
@@ -7,6 +7,7 @@ import (
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
jsoniter "github.com/json-iterator/go"
)
@@ -77,9 +78,9 @@ func List(ctx context.Context, options *ListOptions) ([]*entities.VolumeListRepo
}
// Prune removes unused volumes from the local filesystem.
-func Prune(ctx context.Context, options *PruneOptions) ([]*entities.VolumePruneReport, error) {
+func Prune(ctx context.Context, options *PruneOptions) ([]*reports.PruneReport, error) {
var (
- pruned []*entities.VolumePruneReport
+ pruned []*reports.PruneReport
)
conn, err := bindings.GetClient(ctx)
if err != nil {
diff --git a/pkg/checkpoint/checkpoint_restore.go b/pkg/checkpoint/checkpoint_restore.go
index 9de04266f..f6cd3b38f 100644
--- a/pkg/checkpoint/checkpoint_restore.go
+++ b/pkg/checkpoint/checkpoint_restore.go
@@ -8,6 +8,7 @@ import (
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/image"
+ "github.com/containers/podman/v2/pkg/domain/entities"
"github.com/containers/podman/v2/pkg/errorhandling"
"github.com/containers/podman/v2/pkg/util"
"github.com/containers/storage/pkg/archive"
@@ -36,10 +37,10 @@ func crImportFromJSON(filePath string, v interface{}) error {
// CRImportCheckpoint it the function which imports the information
// from checkpoint tarball and re-creates the container from that information
-func CRImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, input string, name string) ([]*libpod.Container, error) {
+func CRImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, restoreOptions entities.RestoreOptions) ([]*libpod.Container, error) {
// First get the container definition from the
// tarball to a temporary directory
- archiveFile, err := os.Open(input)
+ archiveFile, err := os.Open(restoreOptions.Import)
if err != nil {
return nil, errors.Wrap(err, "failed to open checkpoint archive for import")
}
@@ -53,6 +54,7 @@ func CRImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, input stri
"rootfs-diff.tar",
"network.status",
"deleted.files",
+ "volumes",
},
}
dir, err := ioutil.TempDir("", "checkpoint")
@@ -66,7 +68,7 @@ func CRImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, input stri
}()
err = archive.Untar(archiveFile, dir, options)
if err != nil {
- return nil, errors.Wrapf(err, "Unpacking of checkpoint archive %s failed", input)
+ return nil, errors.Wrapf(err, "Unpacking of checkpoint archive %s failed", restoreOptions.Import)
}
// Load spec.dump from temporary directory
@@ -82,17 +84,30 @@ func CRImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, input stri
}
// This should not happen as checkpoints with these options are not exported.
- if (len(config.Dependencies) > 0) || (len(config.NamedVolumes) > 0) {
- return nil, errors.Errorf("Cannot import checkpoints of containers with named volumes or dependencies")
+ if len(config.Dependencies) > 0 {
+ return nil, errors.Errorf("Cannot import checkpoints of containers with dependencies")
+ }
+
+ // Volumes included in the checkpoint should not exist
+ if !restoreOptions.IgnoreVolumes {
+ for _, vol := range config.NamedVolumes {
+ exists, err := runtime.HasVolume(vol.Name)
+ if err != nil {
+ return nil, err
+ }
+ if exists {
+ return nil, errors.Errorf("volume with name %s already exists. Use --ignore-volumes to not restore content of volumes", vol.Name)
+ }
+ }
}
ctrID := config.ID
newName := false
// Check if the restored container gets a new name
- if name != "" {
+ if restoreOptions.Name != "" {
config.ID = ""
- config.Name = name
+ config.Name = restoreOptions.Name
newName = true
}
diff --git a/pkg/domain/entities/container_ps.go b/pkg/domain/entities/container_ps.go
index ff3b087ed..6709ca48a 100644
--- a/pkg/domain/entities/container_ps.go
+++ b/pkg/domain/entities/container_ps.go
@@ -43,6 +43,8 @@ type ListContainer struct {
// Namespaces the container belongs to. Requires the
// namespace boolean to be true
Namespaces ListContainerNamespaces
+ // The network names assigned to the container
+ Networks []string
// The process id of the container
Pid int
// If the container is part of Pod, the Pod ID. Requires the pod
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index b8d49d067..96687b1de 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -173,10 +173,13 @@ type CheckpointOptions struct {
All bool
Export string
IgnoreRootFS bool
+ IgnoreVolumes bool
Keep bool
Latest bool
LeaveRunning bool
TCPEstablished bool
+ PreCheckPoint bool
+ WithPrevious bool
}
type CheckpointReport struct {
@@ -187,6 +190,7 @@ type CheckpointReport struct {
type RestoreOptions struct {
All bool
IgnoreRootFS bool
+ IgnoreVolumes bool
IgnoreStaticIP bool
IgnoreStaticMAC bool
Import string
@@ -194,6 +198,7 @@ type RestoreOptions struct {
Latest bool
Name string
TCPEstablished bool
+ ImportPrevious string
}
type RestoreReport struct {
@@ -390,13 +395,6 @@ type ContainerPruneOptions struct {
Filters url.Values `json:"filters" schema:"filters"`
}
-// ContainerPruneReport describes the results after pruning the
-// stopped containers.
-type ContainerPruneReport struct {
- ID map[string]int64
- Err map[string]error
-}
-
// ContainerPortOptions describes the options to obtain
// port information on containers
type ContainerPortOptions struct {
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 80127ea45..7d38a97f2 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -6,6 +6,7 @@ import (
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v2/libpod/define"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/containers/podman/v2/pkg/specgen"
"github.com/spf13/cobra"
)
@@ -35,7 +36,7 @@ type ContainerEngine interface {
ContainerMount(ctx context.Context, nameOrIDs []string, options ContainerMountOptions) ([]*ContainerMountReport, error)
ContainerPause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error)
ContainerPort(ctx context.Context, nameOrID string, options ContainerPortOptions) ([]*ContainerPortReport, error)
- ContainerPrune(ctx context.Context, options ContainerPruneOptions) (*ContainerPruneReport, error)
+ ContainerPrune(ctx context.Context, options ContainerPruneOptions) ([]*reports.PruneReport, error)
ContainerRestart(ctx context.Context, namesOrIds []string, options RestartOptions) ([]*RestartReport, error)
ContainerRestore(ctx context.Context, namesOrIds []string, options RestoreOptions) ([]*RestoreReport, error)
ContainerRm(ctx context.Context, namesOrIds []string, options RmOptions) ([]*RmReport, error)
@@ -85,6 +86,6 @@ type ContainerEngine interface {
VolumeCreate(ctx context.Context, opts VolumeCreateOptions) (*IDOrNameResponse, error)
VolumeInspect(ctx context.Context, namesOrIds []string, opts InspectOptions) ([]*VolumeInspectReport, []error, error)
VolumeList(ctx context.Context, opts VolumeListOptions) ([]*VolumeListReport, error)
- VolumePrune(ctx context.Context, options VolumePruneOptions) ([]*VolumePruneReport, error)
+ VolumePrune(ctx context.Context, options VolumePruneOptions) ([]*reports.PruneReport, error)
VolumeRm(ctx context.Context, namesOrIds []string, opts VolumeRmOptions) ([]*VolumeRmReport, error)
}
diff --git a/pkg/domain/entities/engine_image.go b/pkg/domain/entities/engine_image.go
index 7f33d8e9d..26a136f13 100644
--- a/pkg/domain/entities/engine_image.go
+++ b/pkg/domain/entities/engine_image.go
@@ -4,6 +4,7 @@ import (
"context"
"github.com/containers/common/pkg/config"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
)
type ImageEngine interface {
@@ -17,7 +18,7 @@ type ImageEngine interface {
List(ctx context.Context, opts ImageListOptions) ([]*ImageSummary, error)
Load(ctx context.Context, opts ImageLoadOptions) (*ImageLoadReport, error)
Mount(ctx context.Context, images []string, options ImageMountOptions) ([]*ImageMountReport, error)
- Prune(ctx context.Context, opts ImagePruneOptions) (*ImagePruneReport, error)
+ Prune(ctx context.Context, opts ImagePruneOptions) ([]*reports.PruneReport, error)
Pull(ctx context.Context, rawImage string, opts ImagePullOptions) (*ImagePullReport, error)
Push(ctx context.Context, source string, destination string, opts ImagePushOptions) error
Remove(ctx context.Context, images []string, opts ImageRemoveOptions) (*ImageRemoveReport, []error)
diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go
index 67910a34c..d5f88502a 100644
--- a/pkg/domain/entities/images.go
+++ b/pkg/domain/entities/images.go
@@ -247,11 +247,6 @@ type ImagePruneOptions struct {
Filter []string `json:"filter" schema:"filter"`
}
-type ImagePruneReport struct {
- Report Report
- Size int64
-}
-
type ImageTagOptions struct{}
type ImageUntagOptions struct{}
diff --git a/pkg/domain/entities/play.go b/pkg/domain/entities/play.go
index 0b42e1a3f..6883fe6c5 100644
--- a/pkg/domain/entities/play.go
+++ b/pkg/domain/entities/play.go
@@ -40,6 +40,9 @@ type PlayKubePod struct {
Containers []string
// Logs - non-fatal errors and log messages while processing.
Logs []string
+ // ContainerErrors - any errors that occurred while starting containers
+ // in the pod.
+ ContainerErrors []string
}
// PlayKubeReport contains the results of running play kube.
diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go
index 426419833..edb0af15a 100644
--- a/pkg/domain/entities/pods.go
+++ b/pkg/domain/entities/pods.go
@@ -28,8 +28,10 @@ type ListPodsReport struct {
InfraId string //nolint
Name string
Namespace string
- Status string
- Labels map[string]string
+ // Network names connected to infra container
+ Networks []string
+ Status string
+ Labels map[string]string
}
type ListPodContainer struct {
diff --git a/pkg/domain/entities/reports/prune.go b/pkg/domain/entities/reports/prune.go
new file mode 100644
index 000000000..5494ac3ae
--- /dev/null
+++ b/pkg/domain/entities/reports/prune.go
@@ -0,0 +1,40 @@
+package reports
+
+type PruneReport struct {
+ Id string //nolint
+ Err error
+ Size uint64
+}
+
+func PruneReportsIds(r []*PruneReport) []string {
+ ids := make([]string, 0, len(r))
+ for _, v := range r {
+ if v == nil || v.Id == "" {
+ continue
+ }
+ ids = append(ids, v.Id)
+ }
+ return ids
+}
+
+func PruneReportsErrs(r []*PruneReport) []error {
+ errs := make([]error, 0, len(r))
+ for _, v := range r {
+ if v == nil || v.Err == nil {
+ continue
+ }
+ errs = append(errs, v.Err)
+ }
+ return errs
+}
+
+func PruneReportsSize(r []*PruneReport) uint64 {
+ size := uint64(0)
+ for _, v := range r {
+ if v == nil {
+ continue
+ }
+ size = size + v.Size
+ }
+ return size
+}
diff --git a/pkg/domain/entities/system.go b/pkg/domain/entities/system.go
index d5118f6a8..99fa947f0 100644
--- a/pkg/domain/entities/system.go
+++ b/pkg/domain/entities/system.go
@@ -4,6 +4,7 @@ import (
"time"
"github.com/containers/podman/v2/libpod/define"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/docker/docker/api/types"
"github.com/spf13/cobra"
)
@@ -24,10 +25,11 @@ type SystemPruneOptions struct {
// SystemPruneReport provides report after system prune is executed.
type SystemPruneReport struct {
- PodPruneReport []*PodPruneReport
- *ContainerPruneReport
- *ImagePruneReport
- VolumePruneReport []*VolumePruneReport
+ PodPruneReport []*PodPruneReport
+ ContainerPruneReports []*reports.PruneReport
+ ImagePruneReports []*reports.PruneReport
+ VolumePruneReports []*reports.PruneReport
+ ReclaimedSpace uint64
}
// SystemMigrateOptions describes the options needed for the
diff --git a/pkg/domain/entities/volumes.go b/pkg/domain/entities/volumes.go
index e6b29e374..06438f5e9 100644
--- a/pkg/domain/entities/volumes.go
+++ b/pkg/domain/entities/volumes.go
@@ -116,11 +116,6 @@ type VolumePruneOptions struct {
Filters url.Values `json:"filters" schema:"filters"`
}
-type VolumePruneReport struct {
- Err error
- Id string //nolint
-}
-
type VolumeListOptions struct {
Filter map[string][]string
}
diff --git a/pkg/domain/filters/containers.go b/pkg/domain/filters/containers.go
index 6abdd6b57..1de5aca91 100644
--- a/pkg/domain/filters/containers.go
+++ b/pkg/domain/filters/containers.go
@@ -7,6 +7,7 @@ import (
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/define"
+ "github.com/containers/podman/v2/libpod/network"
"github.com/containers/podman/v2/pkg/timetype"
"github.com/containers/podman/v2/pkg/util"
"github.com/pkg/errors"
@@ -34,7 +35,7 @@ func GenerateContainerFilterFuncs(filter string, filterValues []string, r *libpo
filterValue = ""
}
for labelKey, labelValue := range labels {
- if labelKey == filterKey && ("" == filterValue || labelValue == filterValue) {
+ if labelKey == filterKey && (filterValue == "" || labelValue == filterValue) {
matched = true
break
}
@@ -233,7 +234,24 @@ func GenerateContainerFilterFuncs(filter string, filterValues []string, r *libpo
}
return false
}, nil
-
+ case "network":
+ return func(c *libpod.Container) bool {
+ networks, _, err := c.Networks()
+ // if err or no networks, quick out
+ if err != nil || len(networks) == 0 {
+ return false
+ }
+ for _, net := range networks {
+ netID := network.GetNetworkID(net)
+ for _, val := range filterValues {
+ // match by network name or id
+ if val == net || val == netID {
+ return true
+ }
+ }
+ }
+ return false
+ }, nil
}
return nil, errors.Errorf("%s is an invalid filter", filter)
}
diff --git a/pkg/domain/filters/pods.go b/pkg/domain/filters/pods.go
index 7e6b7f2cc..ce7028d2a 100644
--- a/pkg/domain/filters/pods.go
+++ b/pkg/domain/filters/pods.go
@@ -6,6 +6,7 @@ import (
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/define"
+ "github.com/containers/podman/v2/libpod/network"
"github.com/containers/podman/v2/pkg/util"
"github.com/pkg/errors"
)
@@ -123,7 +124,7 @@ func GeneratePodFilterFunc(filter string, filterValues []string) (
filterValue = ""
}
for labelKey, labelValue := range labels {
- if labelKey == filterKey && ("" == filterValue || labelValue == filterValue) {
+ if labelKey == filterKey && (filterValue == "" || labelValue == filterValue) {
matched = true
break
}
@@ -134,6 +135,29 @@ func GeneratePodFilterFunc(filter string, filterValues []string) (
}
return true
}, nil
+ case "network":
+ return func(p *libpod.Pod) bool {
+ infra, err := p.InfraContainer()
+ // no infra, quick out
+ if err != nil {
+ return false
+ }
+ networks, _, err := infra.Networks()
+ // if err or no networks, quick out
+ if err != nil || len(networks) == 0 {
+ return false
+ }
+ for _, net := range networks {
+ netID := network.GetNetworkID(net)
+ for _, val := range filterValues {
+ // match by network name or id
+ if val == net || val == netID {
+ return true
+ }
+ }
+ }
+ return false
+ }, nil
}
return nil, errors.Errorf("%s is an invalid filter", filter)
}
diff --git a/pkg/domain/filters/volumes.go b/pkg/domain/filters/volumes.go
index 69bef4961..7890459f5 100644
--- a/pkg/domain/filters/volumes.go
+++ b/pkg/domain/filters/volumes.go
@@ -39,7 +39,7 @@ func GenerateVolumeFilters(filters url.Values) ([]libpod.VolumeFilter, error) {
}
vf = append(vf, func(v *libpod.Volume) bool {
for labelKey, labelValue := range v.Labels() {
- if labelKey == filterKey && ("" == filterVal || labelValue == filterVal) {
+ if labelKey == filterKey && (filterVal == "" || labelValue == filterVal) {
return true
}
}
@@ -56,7 +56,7 @@ func GenerateVolumeFilters(filters url.Values) ([]libpod.VolumeFilter, error) {
}
vf = append(vf, func(v *libpod.Volume) bool {
for labelKey, labelValue := range v.Options() {
- if labelKey == filterKey && ("" == filterVal || labelValue == filterVal) {
+ if labelKey == filterKey && (filterVal == "" || labelValue == filterVal) {
return true
}
}
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index cfb3421ba..b5f5a0e91 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -21,6 +21,7 @@ import (
"github.com/containers/podman/v2/pkg/cgroups"
"github.com/containers/podman/v2/pkg/checkpoint"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
dfilters "github.com/containers/podman/v2/pkg/domain/filters"
"github.com/containers/podman/v2/pkg/domain/infra/abi/terminal"
parallelctr "github.com/containers/podman/v2/pkg/parallel/ctr"
@@ -112,15 +113,7 @@ func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []strin
}
func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) {
- var (
- err error
- )
- ctrs := []*libpod.Container{} //nolint
- if options.All {
- ctrs, err = ic.Libpod.GetAllContainers()
- } else {
- ctrs, err = getContainersByContext(false, false, namesOrIds, ic.Libpod)
- }
+ ctrs, err := getContainersByContext(options.All, false, namesOrIds, ic.Libpod)
if err != nil {
return nil, err
}
@@ -133,15 +126,7 @@ func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []stri
}
func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) {
- var (
- err error
- )
- ctrs := []*libpod.Container{} //nolint
- if options.All {
- ctrs, err = ic.Libpod.GetAllContainers()
- } else {
- ctrs, err = getContainersByContext(false, false, namesOrIds, ic.Libpod)
- }
+ ctrs, err := getContainersByContext(options.All, false, namesOrIds, ic.Libpod)
if err != nil {
return nil, err
}
@@ -204,7 +189,7 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
return reports, nil
}
-func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.ContainerPruneOptions) (*entities.ContainerPruneReport, error) {
+func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.ContainerPruneOptions) ([]*reports.PruneReport, error) {
filterFuncs := make([]libpod.ContainerFilter, 0, len(options.Filters))
for k, v := range options.Filters {
generatedFunc, err := dfilters.GenerateContainerFilterFuncs(k, v, ic.Libpod)
@@ -213,19 +198,7 @@ func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.
}
filterFuncs = append(filterFuncs, generatedFunc)
}
- return ic.pruneContainersHelper(filterFuncs)
-}
-
-func (ic *ContainerEngine) pruneContainersHelper(filterFuncs []libpod.ContainerFilter) (*entities.ContainerPruneReport, error) {
- prunedContainers, pruneErrors, err := ic.Libpod.PruneContainers(filterFuncs)
- if err != nil {
- return nil, err
- }
- report := entities.ContainerPruneReport{
- ID: prunedContainers,
- Err: pruneErrors,
- }
- return &report, nil
+ return ic.Libpod.PruneContainers(filterFuncs)
}
func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) {
@@ -498,7 +471,10 @@ func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds [
TCPEstablished: options.TCPEstablished,
TargetFile: options.Export,
IgnoreRootfs: options.IgnoreRootFS,
+ IgnoreVolumes: options.IgnoreVolumes,
KeepRunning: options.LeaveRunning,
+ PreCheckPoint: options.PreCheckPoint,
+ WithPrevious: options.WithPrevious,
}
if options.All {
@@ -536,8 +512,10 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st
TargetFile: options.Import,
Name: options.Name,
IgnoreRootfs: options.IgnoreRootFS,
+ IgnoreVolumes: options.IgnoreVolumes,
IgnoreStaticIP: options.IgnoreStaticIP,
IgnoreStaticMAC: options.IgnoreStaticMAC,
+ ImportPrevious: options.ImportPrevious,
}
filterFuncs := []libpod.ContainerFilter{
@@ -549,7 +527,7 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st
switch {
case options.Import != "":
- cons, err = checkpoint.CRImportCheckpoint(ctx, ic.Libpod, options.Import, options.Name)
+ cons, err = checkpoint.CRImportCheckpoint(ctx, ic.Libpod, options)
case options.All:
cons, err = ic.Libpod.GetContainers(filterFuncs...)
default:
diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go
index 394ba359c..3487dc3f4 100644
--- a/pkg/domain/infra/abi/images.go
+++ b/pkg/domain/infra/abi/images.go
@@ -22,8 +22,8 @@ import (
"github.com/containers/image/v5/types"
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/libpod/image"
- libpodImage "github.com/containers/podman/v2/libpod/image"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
domainUtils "github.com/containers/podman/v2/pkg/domain/utils"
"github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/podman/v2/pkg/util"
@@ -49,19 +49,12 @@ func (ir *ImageEngine) Exists(_ context.Context, nameOrID string) (*entities.Boo
return &entities.BoolReport{Value: err == nil}, nil
}
-func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) (*entities.ImagePruneReport, error) {
- results, err := ir.Libpod.ImageRuntime().PruneImages(ctx, opts.All, opts.Filter)
+func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) ([]*reports.PruneReport, error) {
+ reports, err := ir.Libpod.ImageRuntime().PruneImages(ctx, opts.All, opts.Filter)
if err != nil {
return nil, err
}
-
- report := entities.ImagePruneReport{
- Report: entities.Report{
- Id: results,
- Err: nil,
- },
- }
- return &report, nil
+ return reports, err
}
func (ir *ImageEngine) History(ctx context.Context, nameOrID string, opts entities.ImageHistoryOptions) (*entities.ImageHistoryReport, error) {
@@ -212,7 +205,7 @@ func (ir *ImageEngine) Unmount(ctx context.Context, nameOrIDs []string, options
return reports, nil
}
-func ToDomainHistoryLayer(layer *libpodImage.History) entities.ImageHistoryLayer {
+func ToDomainHistoryLayer(layer *image.History) entities.ImageHistoryLayer {
l := entities.ImageHistoryLayer{}
l.ID = layer.ID
l.Created = *layer.Created
diff --git a/pkg/domain/infra/abi/images_list.go b/pkg/domain/infra/abi/images_list.go
index c4b0b7712..2d3b9f36a 100644
--- a/pkg/domain/infra/abi/images_list.go
+++ b/pkg/domain/infra/abi/images_list.go
@@ -44,7 +44,10 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions)
}
e.Labels, err = img.Labels(ctx)
if err != nil {
- return nil, errors.Wrapf(err, "error retrieving label for image %q: you may need to remove the image to resolve the error", img.ID())
+ // Ignore empty manifest lists.
+ if errors.Cause(err) != libpodImage.ErrImageIsBareList {
+ return nil, errors.Wrapf(err, "error retrieving label for image %q: you may need to remove the image to resolve the error", img.ID())
+ }
}
ctnrs, err := img.Containers()
diff --git a/pkg/domain/infra/abi/manifest.go b/pkg/domain/infra/abi/manifest.go
index 0c734d10d..a68ed8788 100644
--- a/pkg/domain/infra/abi/manifest.go
+++ b/pkg/domain/infra/abi/manifest.go
@@ -13,7 +13,6 @@ import (
"github.com/containers/buildah/manifests"
buildahManifests "github.com/containers/buildah/pkg/manifests"
- "github.com/containers/buildah/util"
buildahUtil "github.com/containers/buildah/util"
cp "github.com/containers/image/v5/copy"
"github.com/containers/image/v5/docker"
@@ -60,7 +59,7 @@ func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte
}
}
sc := ir.Libpod.SystemContext()
- refs, err := util.ResolveNameToReferences(ir.Libpod.GetStore(), sc, name)
+ refs, err := buildahUtil.ResolveNameToReferences(ir.Libpod.GetStore(), sc, name)
if err != nil {
return nil, err
}
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
index cbc74a2f2..70c7104f1 100644
--- a/pkg/domain/infra/abi/play.go
+++ b/pkg/domain/infra/abi/play.go
@@ -10,6 +10,7 @@ import (
"github.com/containers/image/v5/types"
"github.com/containers/podman/v2/libpod"
+ "github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/libpod/image"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/containers/podman/v2/pkg/specgen/generate"
@@ -251,21 +252,13 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
}
if options.Start != types.OptionalBoolFalse {
- //start the containers
+ // Start the containers
podStartErrors, err := pod.Start(ctx)
- if err != nil {
+ if err != nil && errors.Cause(err) != define.ErrPodPartialFail {
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
- }
+ for id, err := range podStartErrors {
+ playKubePod.ContainerErrors = append(playKubePod.ContainerErrors, errors.Wrapf(err, "error starting container %s", id).Error())
}
}
diff --git a/pkg/domain/infra/abi/pods.go b/pkg/domain/infra/abi/pods.go
index f108b770c..2a8445c9f 100644
--- a/pkg/domain/infra/abi/pods.go
+++ b/pkg/domain/infra/abi/pods.go
@@ -333,6 +333,17 @@ func (ic *ContainerEngine) PodPs(ctx context.Context, options entities.PodPSOpti
if err != nil {
return nil, err
}
+ networks := []string{}
+ if len(infraID) > 0 {
+ infra, err := p.InfraContainer()
+ if err != nil {
+ return nil, err
+ }
+ networks, _, err = infra.Networks()
+ if err != nil {
+ return nil, err
+ }
+ }
reports = append(reports, &entities.ListPodsReport{
Cgroup: p.CgroupParent(),
Containers: lpcs,
@@ -341,6 +352,7 @@ func (ic *ContainerEngine) PodPs(ctx context.Context, options entities.PodPSOpti
InfraId: infraID,
Name: p.Name(),
Namespace: p.Namespace(),
+ Networks: networks,
Status: status,
Labels: p.Labels(),
})
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index 5f6c95d4f..97fa9d374 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -16,6 +16,7 @@ import (
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/cgroups"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/podman/v2/pkg/util"
"github.com/containers/podman/v2/utils"
@@ -161,15 +162,11 @@ func movePauseProcessToScope(r *libpod.Runtime) error {
return utils.RunUnderSystemdScope(int(pid), "user.slice", "podman-pause.scope")
}
-// checkInput can be used to verify any of the globalopt values
-func checkInput() error { // nolint:deadcode,unused
- return nil
-}
-
// SystemPrune removes unused data from the system. Pruning pods, containers, volumes and images.
func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.SystemPruneOptions) (*entities.SystemPruneReport, error) {
var systemPruneReport = new(entities.SystemPruneReport)
var filters []string
+ reclaimedSpace := (uint64)(0)
found := true
for found {
found = false
@@ -186,42 +183,26 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys
containerPruneOptions := entities.ContainerPruneOptions{}
containerPruneOptions.Filters = (url.Values)(options.Filters)
- containerPruneReport, err := ic.ContainerPrune(ctx, containerPruneOptions)
+ containerPruneReports, err := ic.ContainerPrune(ctx, containerPruneOptions)
if err != nil {
return nil, err
}
- if len(containerPruneReport.ID) > 0 {
- found = true
- }
- if systemPruneReport.ContainerPruneReport == nil {
- systemPruneReport.ContainerPruneReport = containerPruneReport
- } else {
- for name, val := range containerPruneReport.ID {
- systemPruneReport.ContainerPruneReport.ID[name] = val
- }
- }
+ reclaimedSpace = reclaimedSpace + reports.PruneReportsSize(containerPruneReports)
+ systemPruneReport.ContainerPruneReports = append(systemPruneReport.ContainerPruneReports, containerPruneReports...)
for k, v := range options.Filters {
filters = append(filters, fmt.Sprintf("%s=%s", k, v[0]))
}
- results, err := ic.Libpod.ImageRuntime().PruneImages(ctx, options.All, filters)
+ imagePruneReports, err := ic.Libpod.ImageRuntime().PruneImages(ctx, options.All, filters)
+ reclaimedSpace = reclaimedSpace + reports.PruneReportsSize(imagePruneReports)
if err != nil {
return nil, err
}
- if len(results) > 0 {
+ if len(imagePruneReports) > 0 {
found = true
}
- if systemPruneReport.ImagePruneReport == nil {
- systemPruneReport.ImagePruneReport = &entities.ImagePruneReport{
- Report: entities.Report{
- Id: results,
- Err: nil,
- },
- }
- } else {
- systemPruneReport.ImagePruneReport.Report.Id = append(systemPruneReport.ImagePruneReport.Report.Id, results...)
- }
+ systemPruneReport.ImagePruneReports = append(systemPruneReport.ImagePruneReports, imagePruneReports...)
if options.Volume {
volumePruneOptions := entities.VolumePruneOptions{}
volumePruneOptions.Filters = (url.Values)(options.Filters)
@@ -232,9 +213,11 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys
if len(volumePruneReport) > 0 {
found = true
}
- systemPruneReport.VolumePruneReport = append(systemPruneReport.VolumePruneReport, volumePruneReport...)
+ reclaimedSpace = reclaimedSpace + reports.PruneReportsSize(volumePruneReport)
+ systemPruneReport.VolumePruneReports = append(systemPruneReport.VolumePruneReports, volumePruneReport...)
}
}
+ systemPruneReport.ReclaimedSpace = reclaimedSpace
return systemPruneReport, nil
}
diff --git a/pkg/domain/infra/abi/volumes.go b/pkg/domain/infra/abi/volumes.go
index 515e52754..3c9dd9fc0 100644
--- a/pkg/domain/infra/abi/volumes.go
+++ b/pkg/domain/infra/abi/volumes.go
@@ -6,6 +6,7 @@ import (
"github.com/containers/podman/v2/libpod"
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/containers/podman/v2/pkg/domain/filters"
"github.com/containers/podman/v2/pkg/domain/infra/abi/parse"
"github.com/pkg/errors"
@@ -127,7 +128,7 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
return reports, errs, nil
}
-func (ic *ContainerEngine) VolumePrune(ctx context.Context, options entities.VolumePruneOptions) ([]*entities.VolumePruneReport, error) {
+func (ic *ContainerEngine) VolumePrune(ctx context.Context, options entities.VolumePruneOptions) ([]*reports.PruneReport, error) {
filterFuncs, err := filters.GenerateVolumeFilters(options.Filters)
if err != nil {
return nil, err
@@ -135,19 +136,12 @@ func (ic *ContainerEngine) VolumePrune(ctx context.Context, options entities.Vol
return ic.pruneVolumesHelper(ctx, filterFuncs)
}
-func (ic *ContainerEngine) pruneVolumesHelper(ctx context.Context, filterFuncs []libpod.VolumeFilter) ([]*entities.VolumePruneReport, error) {
+func (ic *ContainerEngine) pruneVolumesHelper(ctx context.Context, filterFuncs []libpod.VolumeFilter) ([]*reports.PruneReport, error) {
pruned, err := ic.Libpod.PruneVolumes(ctx, filterFuncs)
if err != nil {
return nil, err
}
- reports := make([]*entities.VolumePruneReport, 0, len(pruned))
- for k, v := range pruned {
- reports = append(reports, &entities.VolumePruneReport{
- Err: v,
- Id: k,
- })
- }
- return reports, nil
+ return pruned, nil
}
func (ic *ContainerEngine) VolumeList(ctx context.Context, opts entities.VolumeListOptions) ([]*entities.VolumeListReport, error) {
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index 0db985dff..3366cb425 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -18,6 +18,7 @@ import (
"github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/bindings/containers"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/containers/podman/v2/pkg/errorhandling"
"github.com/containers/podman/v2/pkg/specgen"
"github.com/containers/podman/v2/pkg/util"
@@ -196,7 +197,7 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string,
return reports, nil
}
-func (ic *ContainerEngine) ContainerPrune(ctx context.Context, opts entities.ContainerPruneOptions) (*entities.ContainerPruneReport, error) {
+func (ic *ContainerEngine) ContainerPrune(ctx context.Context, opts entities.ContainerPruneOptions) ([]*reports.PruneReport, error) {
options := new(containers.PruneOptions).WithFilters(opts.Filters)
return containers.Prune(ic.ClientCtx, options)
}
diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go
index 10bf9682c..fba60235e 100644
--- a/pkg/domain/infra/tunnel/images.go
+++ b/pkg/domain/infra/tunnel/images.go
@@ -16,6 +16,7 @@ import (
"github.com/containers/image/v5/docker/reference"
images "github.com/containers/podman/v2/pkg/bindings/images"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/containers/podman/v2/pkg/domain/utils"
utils2 "github.com/containers/podman/v2/utils"
"github.com/pkg/errors"
@@ -90,26 +91,18 @@ func (ir *ImageEngine) History(ctx context.Context, nameOrID string, opts entiti
return &history, nil
}
-func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) (*entities.ImagePruneReport, error) {
+func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) ([]*reports.PruneReport, error) {
filters := make(map[string][]string, len(opts.Filter))
for _, filter := range opts.Filter {
f := strings.Split(filter, "=")
filters[f[0]] = f[1:]
}
options := new(images.PruneOptions).WithAll(opts.All).WithFilters(filters)
- results, err := images.Prune(ir.ClientCtx, options)
+ reports, err := images.Prune(ir.ClientCtx, options)
if err != nil {
return nil, err
}
-
- report := entities.ImagePruneReport{
- Report: entities.Report{
- Id: results,
- Err: nil,
- },
- Size: 0,
- }
- return &report, nil
+ return reports, nil
}
func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, opts entities.ImagePullOptions) (*entities.ImagePullReport, error) {
diff --git a/pkg/domain/infra/tunnel/volumes.go b/pkg/domain/infra/tunnel/volumes.go
index e6ad4e0c5..10e8d7da8 100644
--- a/pkg/domain/infra/tunnel/volumes.go
+++ b/pkg/domain/infra/tunnel/volumes.go
@@ -5,6 +5,7 @@ import (
"github.com/containers/podman/v2/pkg/bindings/volumes"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/pkg/errors"
)
@@ -69,7 +70,7 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
return reports, errs, nil
}
-func (ic *ContainerEngine) VolumePrune(ctx context.Context, opts entities.VolumePruneOptions) ([]*entities.VolumePruneReport, error) {
+func (ic *ContainerEngine) VolumePrune(ctx context.Context, opts entities.VolumePruneOptions) ([]*reports.PruneReport, error) {
options := new(volumes.PruneOptions).WithFilters(opts.Filters)
return volumes.Prune(ic.ClientCtx, options)
}
diff --git a/pkg/netns/netns_linux.go b/pkg/netns/netns_linux.go
index ed5241632..6817a3abd 100644
--- a/pkg/netns/netns_linux.go
+++ b/pkg/netns/netns_linux.go
@@ -45,7 +45,7 @@ func getNSRunDir() (string, error) {
}
return filepath.Join(rootlessDir, "netns"), nil
}
- return "/var/run/netns", nil
+ return "/run/netns", nil
}
// NewNS creates a new persistent (bind-mounted) network namespace and returns
@@ -80,7 +80,7 @@ func NewNS() (ns.NetNS, error) {
return nil, fmt.Errorf("mount --make-rshared %s failed: %q", nsRunDir, err)
}
- // Recursively remount /var/run/netns on itself. The recursive flag is
+ // Recursively remount /run/netns on itself. The recursive flag is
// so that any existing netns bindmounts are carried over.
err = unix.Mount(nsRunDir, nsRunDir, "none", unix.MS_BIND|unix.MS_REC, "")
if err != nil {
diff --git a/pkg/ps/ps.go b/pkg/ps/ps.go
index 9e0dcb728..dc577890a 100644
--- a/pkg/ps/ps.go
+++ b/pkg/ps/ps.go
@@ -178,6 +178,11 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities
return entities.ListContainer{}, err
}
+ networks, _, err := ctr.Networks()
+ if err != nil {
+ return entities.ListContainer{}, err
+ }
+
ps := entities.ListContainer{
AutoRemove: ctr.AutoRemove(),
Command: conConfig.Command,
@@ -192,6 +197,7 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities
Labels: conConfig.Labels,
Mounts: ctr.UserVolumes(),
Names: []string{conConfig.Name},
+ Networks: networks,
Pid: pid,
Pod: conConfig.Pod,
Ports: portMappings,
diff --git a/pkg/rootless/rootless.go b/pkg/rootless/rootless.go
index 799c793d8..df35c0d6b 100644
--- a/pkg/rootless/rootless.go
+++ b/pkg/rootless/rootless.go
@@ -2,10 +2,12 @@ package rootless
import (
"os"
+ "sort"
"sync"
"github.com/containers/storage"
"github.com/opencontainers/runc/libcontainer/user"
+ spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
)
@@ -50,24 +52,151 @@ func TryJoinPauseProcess(pausePidPath string) (bool, int, error) {
}
var (
- availableGids int64
- availableGidsErr error
- availableGidsOnce sync.Once
+ uidMap []user.IDMap
+ uidMapError error
+ uidMapOnce sync.Once
+
+ gidMap []user.IDMap
+ gidMapError error
+ gidMapOnce sync.Once
)
-// GetAvailableGids returns how many GIDs are available in the
+// GetAvailableUidMap returns the UID mappings in the
// current user namespace.
-func GetAvailableGids() (int64, error) {
- availableGidsOnce.Do(func() {
- idMap, err := user.ParseIDMapFile("/proc/self/gid_map")
+func GetAvailableUidMap() ([]user.IDMap, error) {
+ uidMapOnce.Do(func() {
+ var err error
+ uidMap, err = user.ParseIDMapFile("/proc/self/uid_map")
if err != nil {
- availableGidsErr = err
+ uidMapError = err
return
}
- availableGids = int64(0)
- for _, r := range idMap {
- availableGids += r.Count
+ })
+ return uidMap, uidMapError
+}
+
+// GetAvailableGidMap returns the GID mappings in the
+// current user namespace.
+func GetAvailableGidMap() ([]user.IDMap, error) {
+ gidMapOnce.Do(func() {
+ var err error
+ gidMap, err = user.ParseIDMapFile("/proc/self/gid_map")
+ if err != nil {
+ gidMapError = err
+ return
}
})
- return availableGids, availableGidsErr
+ return gidMap, gidMapError
+}
+
+// GetAvailableIDMaps returns the UID and GID mappings in the
+// current user namespace.
+func GetAvailableIDMaps() ([]user.IDMap, []user.IDMap, error) {
+ u, err := GetAvailableUidMap()
+ if err != nil {
+ return nil, nil, err
+ }
+ g, err := GetAvailableGidMap()
+ if err != nil {
+ return nil, nil, err
+ }
+ return u, g, nil
+}
+
+func countAvailableIDs(mappings []user.IDMap) int64 {
+ availableUids := int64(0)
+ for _, r := range mappings {
+ availableUids += r.Count
+ }
+ return availableUids
+}
+
+// GetAvailableUids returns how many UIDs are available in the
+// current user namespace.
+func GetAvailableUids() (int64, error) {
+ uids, err := GetAvailableUidMap()
+ if err != nil {
+ return -1, err
+ }
+
+ return countAvailableIDs(uids), nil
+}
+
+// GetAvailableGids returns how many GIDs are available in the
+// current user namespace.
+func GetAvailableGids() (int64, error) {
+ gids, err := GetAvailableGidMap()
+ if err != nil {
+ return -1, err
+ }
+
+ return countAvailableIDs(gids), nil
+}
+
+// findIDInMappings find the the mapping that contains the specified ID.
+// It assumes availableMappings is sorted by ID.
+func findIDInMappings(id int64, availableMappings []user.IDMap) *user.IDMap {
+ i := sort.Search(len(availableMappings), func(i int) bool {
+ return availableMappings[i].ID >= id
+ })
+ if i < 0 || i >= len(availableMappings) {
+ return nil
+ }
+ r := &availableMappings[i]
+ if id >= r.ID && id < r.ID+r.Count {
+ return r
+ }
+ return nil
+}
+
+// MaybeSplitMappings checks whether the specified OCI mappings are possible
+// in the current user namespace or the specified ranges must be split.
+func MaybeSplitMappings(mappings []spec.LinuxIDMapping, availableMappings []user.IDMap) []spec.LinuxIDMapping {
+ var ret []spec.LinuxIDMapping
+ var overflow spec.LinuxIDMapping
+ overflow.Size = 0
+ consumed := 0
+ sort.Slice(availableMappings, func(i, j int) bool {
+ return availableMappings[i].ID < availableMappings[j].ID
+ })
+ for {
+ cur := overflow
+ // if there is no overflow left from the previous request, get the next one
+ if cur.Size == 0 {
+ if consumed == len(mappings) {
+ // all done
+ return ret
+ }
+ cur = mappings[consumed]
+ consumed++
+ }
+
+ // Find the range where the first specified ID is present
+ r := findIDInMappings(int64(cur.HostID), availableMappings)
+ if r == nil {
+ // The requested range is not available. Just return the original request
+ // and let other layers deal with it.
+ return mappings
+ }
+
+ offsetInRange := cur.HostID - uint32(r.ID)
+
+ usableIDs := uint32(r.Count) - offsetInRange
+
+ // the current range can satisfy the whole request
+ if usableIDs >= cur.Size {
+ // reset the overflow
+ overflow.Size = 0
+ } else {
+ // the current range can satisfy the request partially
+ // so move the rest to overflow
+ overflow.Size = cur.Size - usableIDs
+ overflow.ContainerID = cur.ContainerID + usableIDs
+ overflow.HostID = cur.HostID + usableIDs
+
+ // and cap to the usableIDs count
+ cur.Size = usableIDs
+ }
+ ret = append(ret, cur)
+ }
}
diff --git a/pkg/rootless/rootless_test.go b/pkg/rootless/rootless_test.go
new file mode 100644
index 000000000..ef574099c
--- /dev/null
+++ b/pkg/rootless/rootless_test.go
@@ -0,0 +1,101 @@
+package rootless
+
+import (
+ "reflect"
+ "testing"
+
+ "github.com/opencontainers/runc/libcontainer/user"
+ spec "github.com/opencontainers/runtime-spec/specs-go"
+)
+
+func TestMaybeSplitMappings(t *testing.T) {
+ mappings := []spec.LinuxIDMapping{
+ {
+ ContainerID: 0,
+ HostID: 0,
+ Size: 2,
+ },
+ }
+ desiredMappings := []spec.LinuxIDMapping{
+ {
+ ContainerID: 0,
+ HostID: 0,
+ Size: 1,
+ },
+ {
+ ContainerID: 1,
+ HostID: 1,
+ Size: 1,
+ },
+ }
+ availableMappings := []user.IDMap{
+ {
+ ID: 1,
+ ParentID: 1000000,
+ Count: 65536,
+ },
+ {
+ ID: 0,
+ ParentID: 1000,
+ Count: 1,
+ },
+ }
+ newMappings := MaybeSplitMappings(mappings, availableMappings)
+ if !reflect.DeepEqual(newMappings, desiredMappings) {
+ t.Fatal("wrong mappings generated")
+ }
+
+ mappings = []spec.LinuxIDMapping{
+ {
+ ContainerID: 0,
+ HostID: 0,
+ Size: 2,
+ },
+ }
+ desiredMappings = []spec.LinuxIDMapping{
+ {
+ ContainerID: 0,
+ HostID: 0,
+ Size: 2,
+ },
+ }
+ availableMappings = []user.IDMap{
+ {
+ ID: 0,
+ ParentID: 1000000,
+ Count: 65536,
+ },
+ }
+ newMappings = MaybeSplitMappings(mappings, availableMappings)
+
+ if !reflect.DeepEqual(newMappings, desiredMappings) {
+ t.Fatal("wrong mappings generated")
+ }
+
+ mappings = []spec.LinuxIDMapping{
+ {
+ ContainerID: 0,
+ HostID: 0,
+ Size: 1,
+ },
+ }
+ desiredMappings = []spec.LinuxIDMapping{
+ {
+ ContainerID: 0,
+ HostID: 0,
+ Size: 1,
+ },
+ }
+ availableMappings = []user.IDMap{
+ {
+ ID: 10000,
+ ParentID: 10000,
+ Count: 65536,
+ },
+ }
+
+ newMappings = MaybeSplitMappings(mappings, availableMappings)
+ if !reflect.DeepEqual(newMappings, desiredMappings) {
+ t.Fatal("wrong mappings generated")
+ }
+}
diff --git a/pkg/signal/signal_linux_mipsx.go b/pkg/signal/signal_linux_mipsx.go
index 67638e30a..45c9d5af1 100644
--- a/pkg/signal/signal_linux_mipsx.go
+++ b/pkg/signal/signal_linux_mipsx.go
@@ -19,6 +19,8 @@ import (
const (
sigrtmin = 34
sigrtmax = 127
+
+ SIGWINCH = syscall.SIGWINCH
)
// signalMap is a map of Linux signals.
diff --git a/pkg/specgen/generate/config_linux.go b/pkg/specgen/generate/config_linux.go
index e0b039fb7..1290a8eb6 100644
--- a/pkg/specgen/generate/config_linux.go
+++ b/pkg/specgen/generate/config_linux.go
@@ -21,9 +21,6 @@ var (
errNotADevice = errors.New("not a device node")
)
-func u32Ptr(i int64) *uint32 { u := uint32(i); return &u }
-func fmPtr(i int64) *os.FileMode { fm := os.FileMode(i); return &fm }
-
func addPrivilegedDevices(g *generate.Generator) error {
hostDevices, err := getDevices("/dev")
if err != nil {
diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go
index 42fea0277..2feb1d3b2 100644
--- a/pkg/specgen/generate/container.go
+++ b/pkg/specgen/generate/container.go
@@ -100,15 +100,9 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
if err != nil {
return nil, err
}
- // First transform the os env into a map. We need it for the labels later in
- // any case.
- osEnv, err := envLib.ParseSlice(os.Environ())
- if err != nil {
- return nil, errors.Wrap(err, "error parsing host environment variables")
- }
// Get Default Environment from containers.conf
- defaultEnvs, err := envLib.ParseSlice(rtc.GetDefaultEnv())
+ defaultEnvs, err := envLib.ParseSlice(rtc.GetDefaultEnvEx(s.EnvHost, s.HTTPProxy))
if err != nil {
return nil, errors.Wrap(err, "error parsing fields in containers.conf")
}
@@ -133,6 +127,12 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
defaultEnvs = envLib.Join(defaultEnvs, envs)
}
+ // First transform the os env into a map. We need it for the labels later in
+ // any case.
+ osEnv, err := envLib.ParseSlice(os.Environ())
+ if err != nil {
+ return nil, errors.Wrap(err, "error parsing host environment variables")
+ }
// Caller Specified defaults
if s.EnvHost {
defaultEnvs = envLib.Join(defaultEnvs, osEnv)
@@ -282,8 +282,8 @@ func finishThrottleDevices(s *specgen.SpecGenerator) error {
if err := unix.Stat(k, &statT); err != nil {
return err
}
- v.Major = (int64(unix.Major(statT.Rdev)))
- v.Minor = (int64(unix.Minor(statT.Rdev)))
+ v.Major = (int64(unix.Major(uint64(statT.Rdev))))
+ v.Minor = (int64(unix.Minor(uint64(statT.Rdev))))
s.ResourceLimits.BlockIO.ThrottleReadBpsDevice = append(s.ResourceLimits.BlockIO.ThrottleReadBpsDevice, v)
}
}
@@ -293,8 +293,8 @@ func finishThrottleDevices(s *specgen.SpecGenerator) error {
if err := unix.Stat(k, &statT); err != nil {
return err
}
- v.Major = (int64(unix.Major(statT.Rdev)))
- v.Minor = (int64(unix.Minor(statT.Rdev)))
+ v.Major = (int64(unix.Major(uint64(statT.Rdev))))
+ v.Minor = (int64(unix.Minor(uint64(statT.Rdev))))
s.ResourceLimits.BlockIO.ThrottleWriteBpsDevice = append(s.ResourceLimits.BlockIO.ThrottleWriteBpsDevice, v)
}
}
@@ -304,8 +304,8 @@ func finishThrottleDevices(s *specgen.SpecGenerator) error {
if err := unix.Stat(k, &statT); err != nil {
return err
}
- v.Major = (int64(unix.Major(statT.Rdev)))
- v.Minor = (int64(unix.Minor(statT.Rdev)))
+ v.Major = (int64(unix.Major(uint64(statT.Rdev))))
+ v.Minor = (int64(unix.Minor(uint64(statT.Rdev))))
s.ResourceLimits.BlockIO.ThrottleReadIOPSDevice = append(s.ResourceLimits.BlockIO.ThrottleReadIOPSDevice, v)
}
}
@@ -315,8 +315,8 @@ func finishThrottleDevices(s *specgen.SpecGenerator) error {
if err := unix.Stat(k, &statT); err != nil {
return err
}
- v.Major = (int64(unix.Major(statT.Rdev)))
- v.Minor = (int64(unix.Minor(statT.Rdev)))
+ v.Major = (int64(unix.Major(uint64(statT.Rdev))))
+ v.Minor = (int64(unix.Minor(uint64(statT.Rdev))))
s.ResourceLimits.BlockIO.ThrottleWriteIOPSDevice = append(s.ResourceLimits.BlockIO.ThrottleWriteIOPSDevice, v)
}
}
diff --git a/pkg/specgen/generate/namespaces.go b/pkg/specgen/generate/namespaces.go
index 036c7b7a1..3cd5a3c9c 100644
--- a/pkg/specgen/generate/namespaces.go
+++ b/pkg/specgen/generate/namespaces.go
@@ -364,7 +364,9 @@ func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt
// namespaces?
g.SetHostname(hostname)
}
- g.AddProcessEnv("HOSTNAME", hostname)
+ if _, ok := s.Env["HOSTNAME"]; !ok && s.Hostname != "" {
+ g.AddProcessEnv("HOSTNAME", hostname)
+ }
// User
switch s.UserNS.NSMode {
diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go
index ba68de6fd..7dc32a314 100644
--- a/pkg/specgen/generate/oci.go
+++ b/pkg/specgen/generate/oci.go
@@ -110,7 +110,7 @@ func makeCommand(ctx context.Context, s *specgen.SpecGenerator, img *image.Image
// Only use image command if the user did not manually set an
// entrypoint.
command := s.Command
- if (command == nil || len(command) == 0) && img != nil && (s.Entrypoint == nil || len(s.Entrypoint) == 0) {
+ if len(command) == 0 && img != nil && len(s.Entrypoint) == 0 {
newCmd, err := img.Cmd(ctx)
if err != nil {
return nil, err
diff --git a/pkg/specgen/generate/security.go b/pkg/specgen/generate/security.go
index d3cbac76e..390b19beb 100644
--- a/pkg/specgen/generate/security.go
+++ b/pkg/specgen/generate/security.go
@@ -133,13 +133,13 @@ func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator,
configSpec := g.Config
configSpec.Process.Capabilities.Ambient = []string{}
configSpec.Process.Capabilities.Bounding = caplist
- configSpec.Process.Capabilities.Inheritable = caplist
user := strings.Split(s.User, ":")[0]
if (user == "" && s.UserNS.NSMode != specgen.KeepID) || user == "root" || user == "0" {
configSpec.Process.Capabilities.Effective = caplist
configSpec.Process.Capabilities.Permitted = caplist
+ configSpec.Process.Capabilities.Inheritable = caplist
} else {
userCaps, err := capabilities.MergeCapabilities(nil, s.CapAdd, nil)
if err != nil {
@@ -147,6 +147,7 @@ func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator,
}
configSpec.Process.Capabilities.Effective = userCaps
configSpec.Process.Capabilities.Permitted = userCaps
+ configSpec.Process.Capabilities.Inheritable = userCaps
// Ambient capabilities were added to Linux 4.3. Set ambient
// capabilities only when the kernel supports them.
@@ -178,6 +179,10 @@ func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator,
g.SetRootReadonly(s.ReadOnlyFilesystem)
+ noUseIPC := s.IpcNS.NSMode == specgen.FromContainer || s.IpcNS.NSMode == specgen.FromPod || s.IpcNS.NSMode == specgen.Host
+ noUseNet := s.NetNS.NSMode == specgen.FromContainer || s.NetNS.NSMode == specgen.FromPod || s.NetNS.NSMode == specgen.Host
+ noUseUTS := s.UtsNS.NSMode == specgen.FromContainer || s.UtsNS.NSMode == specgen.FromPod || s.UtsNS.NSMode == specgen.Host
+
// Add default sysctls
defaultSysctls, err := util.ValidateSysctls(rtc.Sysctls())
if err != nil {
@@ -186,20 +191,20 @@ func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator,
for sysctlKey, sysctlVal := range defaultSysctls {
// Ignore mqueue sysctls if --ipc=host
- if s.IpcNS.IsHost() && strings.HasPrefix(sysctlKey, "fs.mqueue.") {
+ if noUseIPC && strings.HasPrefix(sysctlKey, "fs.mqueue.") {
logrus.Infof("Sysctl %s=%s ignored in containers.conf, since IPC Namespace set to host", sysctlKey, sysctlVal)
continue
}
// Ignore net sysctls if --net=host
- if s.NetNS.IsHost() && strings.HasPrefix(sysctlKey, "net.") {
+ if noUseNet && strings.HasPrefix(sysctlKey, "net.") {
logrus.Infof("Sysctl %s=%s ignored in containers.conf, since Network Namespace set to host", sysctlKey, sysctlVal)
continue
}
// Ignore uts sysctls if --uts=host
- if s.UtsNS.IsHost() && (strings.HasPrefix(sysctlKey, "kernel.domainname") || strings.HasPrefix(sysctlKey, "kernel.hostname")) {
+ if noUseUTS && (strings.HasPrefix(sysctlKey, "kernel.domainname") || strings.HasPrefix(sysctlKey, "kernel.hostname")) {
logrus.Infof("Sysctl %s=%s ignored in containers.conf, since UTS Namespace set to host", sysctlKey, sysctlVal)
continue
}
diff --git a/pkg/specgen/generate/storage.go b/pkg/specgen/generate/storage.go
index f523ac5bf..63713726e 100644
--- a/pkg/specgen/generate/storage.go
+++ b/pkg/specgen/generate/storage.go
@@ -124,14 +124,10 @@ func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Ru
// named volumes, and vice versa.
// We'll delete the conflicts here as we supersede.
for dest := range unifiedMounts {
- if _, ok := baseVolumes[dest]; ok {
- delete(baseVolumes, dest)
- }
+ delete(baseVolumes, dest)
}
for dest := range unifiedVolumes {
- if _, ok := baseMounts[dest]; ok {
- delete(baseMounts, dest)
- }
+ delete(baseMounts, dest)
}
// Supersede volumes-from/image volumes with unified volumes from above.
diff --git a/pkg/specgen/generate/validate.go b/pkg/specgen/generate/validate.go
index f0ab4b994..77cccad3e 100644
--- a/pkg/specgen/generate/validate.go
+++ b/pkg/specgen/generate/validate.go
@@ -48,7 +48,7 @@ func verifyContainerResourcesCgroupV1(s *specgen.SpecGenerator) ([]string, error
warnings = append(warnings, "Your kernel does not support memory swappiness capabilities, or the cgroup is not mounted. Memory swappiness discarded.")
memory.Swappiness = nil
} else {
- if *memory.Swappiness < 0 || *memory.Swappiness > 100 {
+ if *memory.Swappiness > 100 {
return warnings, errors.Errorf("invalid value: %v, valid memory swappiness range is 0-100", *memory.Swappiness)
}
}
diff --git a/pkg/systemd/generate/common.go b/pkg/systemd/generate/common.go
index 52a214883..8901298db 100644
--- a/pkg/systemd/generate/common.go
+++ b/pkg/systemd/generate/common.go
@@ -11,6 +11,11 @@ import (
// is set to the unit's (unique) name.
const EnvVariable = "PODMAN_SYSTEMD_UNIT"
+// minTimeoutStopSec is the minimal stop timeout for generated systemd units.
+// Once exceeded, processes of the services are killed and the cgroup(s) are
+// cleaned up.
+const minTimeoutStopSec = 60
+
// RestartPolicies includes all valid restart policies to be used in a unit
// file.
var RestartPolicies = []string{"no", "on-success", "on-failure", "on-abnormal", "on-watchdog", "on-abort", "always"}
@@ -66,3 +71,30 @@ func quoteArguments(command []string) []string {
}
return command
}
+
+func removeDetachArg(args []string, argCount int) []string {
+ // "--detach=false" could also be in the container entrypoint
+ // split them off so we do not remove it there
+ realArgs := args[len(args)-argCount:]
+ flagArgs := removeArg("-d=false", args[:len(args)-argCount])
+ flagArgs = removeArg("--detach=false", flagArgs)
+ return append(flagArgs, realArgs...)
+}
+
+func removeReplaceArg(args []string, argCount int) []string {
+ // "--replace=false" could also be in the container entrypoint
+ // split them off so we do not remove it there
+ realArgs := args[len(args)-argCount:]
+ flagArgs := removeArg("--replace=false", args[:len(args)-argCount])
+ return append(flagArgs, realArgs...)
+}
+
+func removeArg(arg string, args []string) []string {
+ newArgs := []string{}
+ for _, a := range args {
+ if a != arg {
+ newArgs = append(newArgs, a)
+ }
+ }
+ return newArgs
+}
diff --git a/pkg/systemd/generate/containers.go b/pkg/systemd/generate/containers.go
index d84125fc7..b64b2593c 100644
--- a/pkg/systemd/generate/containers.go
+++ b/pkg/systemd/generate/containers.go
@@ -14,6 +14,7 @@ import (
"github.com/containers/podman/v2/version"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
+ "github.com/spf13/pflag"
)
// containerInfo contains data required for generating a container's systemd
@@ -44,6 +45,9 @@ type containerInfo struct {
// Executable is the path to the podman executable. Will be auto-filled if
// left empty.
Executable string
+ // RootFlags contains the root flags which were used to create the container
+ // Only used with --new
+ RootFlags string
// TimeStamp at the time of creating the unit file. Will be set internally.
TimeStamp string
// CreateCommand is the full command plus arguments of the process the
@@ -55,6 +59,8 @@ type containerInfo struct {
ExecStartPre string
// ExecStart of the unit.
ExecStart string
+ // TimeoutStopSec of the unit.
+ TimeoutStopSec uint
// ExecStop of the unit.
ExecStop string
// ExecStopPost of the unit.
@@ -74,6 +80,7 @@ After={{- range $index, $value := .BoundToServices -}}{{if $index}} {{end}}{{ $v
[Service]
Environment={{.EnvVariable}}=%n
Restart={{.RestartPolicy}}
+TimeoutStopSec={{.TimeoutStopSec}}
{{- if .ExecStartPre}}
ExecStartPre={{.ExecStartPre}}
{{- end}}
@@ -81,7 +88,6 @@ ExecStart={{.ExecStart}}
ExecStop={{.ExecStop}}
ExecStopPost={{.ExecStopPost}}
PIDFile={{.PIDFile}}
-KillMode=none
Type=forking
[Install]
@@ -183,22 +189,30 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
info.ContainerIDFile = "%t/" + info.ServiceName + ".ctr-id"
// The create command must at least have three arguments:
// /usr/bin/podman run $IMAGE
- index := 2
- if info.CreateCommand[1] == "container" {
- index = 3
+ index := 0
+ for i, arg := range info.CreateCommand {
+ if arg == "run" || arg == "create" {
+ index = i + 1
+ break
+ }
}
- if len(info.CreateCommand) < index+1 {
+ if index == 0 {
return "", errors.Errorf("container's create command is too short or invalid: %v", info.CreateCommand)
}
// We're hard-coding the first five arguments and append the
// CreateCommand with a stripped command and subcommand.
- startCommand := []string{
- info.Executable,
+ startCommand := []string{info.Executable}
+ if index > 2 {
+ // include root flags
+ info.RootFlags = strings.Join(quoteArguments(info.CreateCommand[1:index-1]), " ")
+ startCommand = append(startCommand, info.CreateCommand[1:index-1]...)
+ }
+ startCommand = append(startCommand,
"run",
"--conmon-pidfile", "{{.PIDFile}}",
"--cidfile", "{{.ContainerIDFile}}",
"--cgroups=no-conmon",
- }
+ )
// If the container is in a pod, make sure that the
// --pod-id-file is set correctly.
if info.pod != nil {
@@ -208,22 +222,26 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
}
// Presence check for certain flags/options.
- hasDetachParam := false
- hasNameParam := false
- hasReplaceParam := false
- for _, p := range info.CreateCommand[index:] {
- switch p {
- case "--detach", "-d":
- hasDetachParam = true
- case "--name":
- hasNameParam = true
- case "--replace":
- hasReplaceParam = true
- }
- if strings.HasPrefix(p, "--name=") {
- hasNameParam = true
- }
+ fs := pflag.NewFlagSet("args", pflag.ContinueOnError)
+ fs.ParseErrorsWhitelist.UnknownFlags = true
+ fs.Usage = func() {}
+ fs.SetInterspersed(false)
+ fs.BoolP("detach", "d", false, "")
+ fs.String("name", "", "")
+ fs.Bool("replace", false, "")
+ fs.Parse(info.CreateCommand[index:])
+
+ hasDetachParam, err := fs.GetBool("detach")
+ if err != nil {
+ return "", err
}
+ hasNameParam := fs.Lookup("name").Changed
+ hasReplaceParam, err := fs.GetBool("replace")
+ if err != nil {
+ return "", err
+ }
+
+ remainingCmd := info.CreateCommand[index:]
if !hasDetachParam {
// Enforce detaching
@@ -238,6 +256,13 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
// will wait the `podman run` command exit until failed
// with timeout error.
startCommand = append(startCommand, "-d")
+
+ if fs.Changed("detach") {
+ // this can only happen if --detach=false is set
+ // in that case we need to remove it otherwise we
+ // would overwrite the previous detach arg to false
+ remainingCmd = removeDetachArg(remainingCmd, fs.NArg())
+ }
}
if hasNameParam && !hasReplaceParam {
// Enforce --replace for named containers. This will
@@ -245,16 +270,25 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
// start after system crashes (see
// github.com/containers/podman/issues/5485).
startCommand = append(startCommand, "--replace")
+
+ if fs.Changed("replace") {
+ // this can only happen if --replace=false is set
+ // in that case we need to remove it otherwise we
+ // would overwrite the previous replace arg to false
+ remainingCmd = removeReplaceArg(remainingCmd, fs.NArg())
+ }
}
- startCommand = append(startCommand, info.CreateCommand[index:]...)
+ startCommand = append(startCommand, remainingCmd...)
startCommand = quoteArguments(startCommand)
info.ExecStartPre = "/bin/rm -f {{.PIDFile}} {{.ContainerIDFile}}"
info.ExecStart = strings.Join(startCommand, " ")
- info.ExecStop = "{{.Executable}} stop --ignore --cidfile {{.ContainerIDFile}} {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}}"
- info.ExecStopPost = "{{.Executable}} rm --ignore -f --cidfile {{.ContainerIDFile}}"
+ info.ExecStop = "{{.Executable}} {{if .RootFlags}}{{ .RootFlags}} {{end}}stop --ignore --cidfile {{.ContainerIDFile}} {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}}"
+ info.ExecStopPost = "{{.Executable}} {{if .RootFlags}}{{ .RootFlags}} {{end}}rm --ignore -f --cidfile {{.ContainerIDFile}}"
}
+ info.TimeoutStopSec = minTimeoutStopSec + info.StopTimeout
+
if info.PodmanVersion == "" {
info.PodmanVersion = version.Version.String()
}
diff --git a/pkg/systemd/generate/containers_test.go b/pkg/systemd/generate/containers_test.go
index d27062ef3..c8e65bfe3 100644
--- a/pkg/systemd/generate/containers_test.go
+++ b/pkg/systemd/generate/containers_test.go
@@ -4,6 +4,7 @@ import (
"testing"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/stretchr/testify/assert"
)
func TestValidateRestartPolicyContainer(t *testing.T) {
@@ -48,11 +49,11 @@ After=network-online.target
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=82
ExecStart=/usr/bin/podman start 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
-ExecStop=/usr/bin/podman stop -t 10 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
-ExecStopPost=/usr/bin/podman stop -t 10 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
-PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
-KillMode=none
+ExecStop=/usr/bin/podman stop -t 22 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
+ExecStopPost=/usr/bin/podman stop -t 22 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
+PIDFile=/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
Type=forking
[Install]
@@ -71,11 +72,11 @@ After=network-online.target
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=70
ExecStart=/usr/bin/podman start foobar
ExecStop=/usr/bin/podman stop -t 10 foobar
ExecStopPost=/usr/bin/podman stop -t 10 foobar
-PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
-KillMode=none
+PIDFile=/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
Type=forking
[Install]
@@ -96,11 +97,11 @@ After=a.service b.service c.service pod.service
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=70
ExecStart=/usr/bin/podman start foobar
ExecStop=/usr/bin/podman stop -t 10 foobar
ExecStopPost=/usr/bin/podman stop -t 10 foobar
-PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
-KillMode=none
+PIDFile=/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
Type=forking
[Install]
@@ -119,12 +120,12 @@ After=network-online.target
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id
-ExecStart=/usr/bin/podman run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon -d --replace --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN "foo=arg \"with \" space"
-ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 42
-ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id
+ExecStart=/usr/bin/podman container run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon -d --replace --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN "foo=arg \"with \" space"
+ExecStop=/usr/bin/podman container stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 10
+ExecStopPost=/usr/bin/podman container rm --ignore -f --cidfile %t/jadda-jadda.ctr-id
PIDFile=%t/jadda-jadda.pid
-KillMode=none
Type=forking
[Install]
@@ -143,12 +144,12 @@ After=network-online.target
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id
ExecStart=/usr/bin/podman run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon --replace -d --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN
-ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 42
+ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 10
ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id
PIDFile=%t/jadda-jadda.pid
-KillMode=none
Type=forking
[Install]
@@ -167,12 +168,12 @@ After=network-online.target
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id
ExecStart=/usr/bin/podman run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon --pod-id-file /tmp/pod-foobar.pod-id-file --replace -d --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN
-ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 42
+ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 10
ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id
PIDFile=%t/jadda-jadda.pid
-KillMode=none
Type=forking
[Install]
@@ -191,12 +192,12 @@ After=network-online.target
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id
ExecStart=/usr/bin/podman run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon --replace --detach --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN
-ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 42
+ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 10
ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id
PIDFile=%t/jadda-jadda.pid
-KillMode=none
Type=forking
[Install]
@@ -215,12 +216,113 @@ After=network-online.target
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.pid %t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.ctr-id
ExecStart=/usr/bin/podman run --conmon-pidfile %t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.pid --cidfile %t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.ctr-id --cgroups=no-conmon -d awesome-image:latest
ExecStop=/usr/bin/podman stop --ignore --cidfile %t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.ctr-id -t 10
ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.ctr-id
PIDFile=%t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.pid
-KillMode=none
+Type=forking
+
+[Install]
+WantedBy=multi-user.target default.target
+`
+
+ genGoodNewDetach := func(detachparam string) string {
+ goodNewDetach := `# jadda-jadda.service
+# autogenerated by Podman CI
+
+[Unit]
+Description=Podman jadda-jadda.service
+Documentation=man:podman-generate-systemd(1)
+Wants=network.target
+After=network-online.target
+
+[Service]
+Environment=PODMAN_SYSTEMD_UNIT=%n
+Restart=always
+TimeoutStopSec=102
+ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id
+ExecStart=/usr/bin/podman run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon ` +
+ detachparam +
+ ` awesome-image:latest
+ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 42
+ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id
+PIDFile=%t/jadda-jadda.pid
+Type=forking
+
+[Install]
+WantedBy=multi-user.target default.target
+`
+ return goodNewDetach
+ }
+
+ goodNameNewDetachFalseWithCmd := `# jadda-jadda.service
+# autogenerated by Podman CI
+
+[Unit]
+Description=Podman jadda-jadda.service
+Documentation=man:podman-generate-systemd(1)
+Wants=network.target
+After=network-online.target
+
+[Service]
+Environment=PODMAN_SYSTEMD_UNIT=%n
+Restart=always
+TimeoutStopSec=102
+ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id
+ExecStart=/usr/bin/podman run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon -d --replace --name test -p 80:80 awesome-image:latest somecmd --detach=false
+ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 42
+ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id
+PIDFile=%t/jadda-jadda.pid
+Type=forking
+
+[Install]
+WantedBy=multi-user.target default.target
+`
+
+ goodNewRootFlags := `# jadda-jadda.service
+# autogenerated by Podman CI
+
+[Unit]
+Description=Podman jadda-jadda.service
+Documentation=man:podman-generate-systemd(1)
+Wants=network.target
+After=network-online.target
+
+[Service]
+Environment=PODMAN_SYSTEMD_UNIT=%n
+Restart=always
+TimeoutStopSec=102
+ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id
+ExecStart=/usr/bin/podman --events-backend none --runroot /root run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon -d awesome-image:latest
+ExecStop=/usr/bin/podman --events-backend none --runroot /root stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 42
+ExecStopPost=/usr/bin/podman --events-backend none --runroot /root rm --ignore -f --cidfile %t/jadda-jadda.ctr-id
+PIDFile=%t/jadda-jadda.pid
+Type=forking
+
+[Install]
+WantedBy=multi-user.target default.target
+`
+
+ goodContainerCreate := `# jadda-jadda.service
+# autogenerated by Podman CI
+
+[Unit]
+Description=Podman jadda-jadda.service
+Documentation=man:podman-generate-systemd(1)
+Wants=network.target
+After=network-online.target
+
+[Service]
+Environment=PODMAN_SYSTEMD_UNIT=%n
+Restart=always
+TimeoutStopSec=70
+ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id
+ExecStart=/usr/bin/podman container run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon -d awesome-image:latest
+ExecStop=/usr/bin/podman container stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 10
+ExecStopPost=/usr/bin/podman container rm --ignore -f --cidfile %t/jadda-jadda.ctr-id
+PIDFile=%t/jadda-jadda.pid
Type=forking
[Install]
@@ -241,8 +343,8 @@ WantedBy=multi-user.target default.target
ServiceName: "container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
ContainerNameOrID: "639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
RestartPolicy: "always",
- PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 10,
+ PIDFile: "/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 22,
PodmanVersion: "CI",
EnvVariable: EnvVariable,
},
@@ -256,7 +358,7 @@ WantedBy=multi-user.target default.target
ServiceName: "container-foobar",
ContainerNameOrID: "foobar",
RestartPolicy: "always",
- PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ PIDFile: "/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
StopTimeout: 10,
PodmanVersion: "CI",
EnvVariable: EnvVariable,
@@ -271,7 +373,7 @@ WantedBy=multi-user.target default.target
ServiceName: "container-foobar",
ContainerNameOrID: "foobar",
RestartPolicy: "always",
- PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ PIDFile: "/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
StopTimeout: 10,
PodmanVersion: "CI",
BoundToServices: []string{"pod", "a", "b", "c"},
@@ -286,7 +388,7 @@ WantedBy=multi-user.target default.target
Executable: "/usr/bin/podman",
ServiceName: "639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
RestartPolicy: "never",
- PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ PIDFile: "/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
StopTimeout: 10,
PodmanVersion: "CI",
EnvVariable: EnvVariable,
@@ -301,8 +403,8 @@ WantedBy=multi-user.target default.target
ServiceName: "jadda-jadda",
ContainerNameOrID: "jadda-jadda",
RestartPolicy: "always",
- PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 42,
+ PIDFile: "/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 10,
PodmanVersion: "CI",
CreateCommand: []string{"I'll get stripped", "container", "run", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN", "foo=arg \"with \" space"},
EnvVariable: EnvVariable,
@@ -317,10 +419,10 @@ WantedBy=multi-user.target default.target
ServiceName: "jadda-jadda",
ContainerNameOrID: "jadda-jadda",
RestartPolicy: "always",
- PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 42,
+ PIDFile: "/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 10,
PodmanVersion: "CI",
- CreateCommand: []string{"I'll get stripped", "container", "run", "-d", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN"},
+ CreateCommand: []string{"I'll get stripped", "run", "-d", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN"},
EnvVariable: EnvVariable,
},
goodWithExplicitShortDetachParam,
@@ -333,10 +435,10 @@ WantedBy=multi-user.target default.target
ServiceName: "jadda-jadda",
ContainerNameOrID: "jadda-jadda",
RestartPolicy: "always",
- PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 42,
+ PIDFile: "/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 10,
PodmanVersion: "CI",
- CreateCommand: []string{"I'll get stripped", "container", "run", "-d", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN"},
+ CreateCommand: []string{"I'll get stripped", "run", "-d", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN"},
EnvVariable: EnvVariable,
pod: &podInfo{
PodIDFile: "/tmp/pod-foobar.pod-id-file",
@@ -352,10 +454,10 @@ WantedBy=multi-user.target default.target
ServiceName: "jadda-jadda",
ContainerNameOrID: "jadda-jadda",
RestartPolicy: "always",
- PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 42,
+ PIDFile: "/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 10,
PodmanVersion: "CI",
- CreateCommand: []string{"I'll get stripped", "container", "run", "--detach", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN"},
+ CreateCommand: []string{"I'll get stripped", "run", "--detach", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN"},
EnvVariable: EnvVariable,
},
goodNameNewDetach,
@@ -368,16 +470,144 @@ WantedBy=multi-user.target default.target
ServiceName: "container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
ContainerNameOrID: "639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
RestartPolicy: "always",
- PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ PIDFile: "/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
StopTimeout: 10,
PodmanVersion: "CI",
- CreateCommand: []string{"I'll get stripped", "container", "run", "awesome-image:latest"},
+ CreateCommand: []string{"I'll get stripped", "run", "awesome-image:latest"},
EnvVariable: EnvVariable,
},
goodIDNew,
true,
false,
},
+ {"good with explicit detach=true param",
+ containerInfo{
+ Executable: "/usr/bin/podman",
+ ServiceName: "jadda-jadda",
+ ContainerNameOrID: "jadda-jadda",
+ RestartPolicy: "always",
+ PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 42,
+ PodmanVersion: "CI",
+ CreateCommand: []string{"I'll get stripped", "run", "--detach=true", "awesome-image:latest"},
+ EnvVariable: EnvVariable,
+ },
+ genGoodNewDetach("--detach=true"),
+ true,
+ false,
+ },
+ {"good with explicit detach=false param",
+ containerInfo{
+ Executable: "/usr/bin/podman",
+ ServiceName: "jadda-jadda",
+ ContainerNameOrID: "jadda-jadda",
+ RestartPolicy: "always",
+ PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 42,
+ PodmanVersion: "CI",
+ CreateCommand: []string{"I'll get stripped", "run", "--detach=false", "awesome-image:latest"},
+ EnvVariable: EnvVariable,
+ },
+ genGoodNewDetach("-d"),
+ true,
+ false,
+ },
+ {"good with explicit detach=false param",
+ containerInfo{
+ Executable: "/usr/bin/podman",
+ ServiceName: "jadda-jadda",
+ ContainerNameOrID: "jadda-jadda",
+ RestartPolicy: "always",
+ PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 42,
+ PodmanVersion: "CI",
+ CreateCommand: []string{"I'll get stripped", "run", "--name", "test", "-p", "80:80", "--detach=false", "awesome-image:latest", "somecmd", "--detach=false"},
+ EnvVariable: EnvVariable,
+ },
+ goodNameNewDetachFalseWithCmd,
+ true,
+ false,
+ },
+ {"good with multiple detach=false params",
+ containerInfo{
+ Executable: "/usr/bin/podman",
+ ServiceName: "jadda-jadda",
+ ContainerNameOrID: "jadda-jadda",
+ RestartPolicy: "always",
+ PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 42,
+ PodmanVersion: "CI",
+ CreateCommand: []string{"I'll get stripped", "run", "--name", "test", "-p", "80:80", "--detach=false", "--detach=false", "awesome-image:latest", "somecmd", "--detach=false"},
+ EnvVariable: EnvVariable,
+ },
+ goodNameNewDetachFalseWithCmd,
+ true,
+ false,
+ },
+ {"good with multiple shorthand params detach first",
+ containerInfo{
+ Executable: "/usr/bin/podman",
+ ServiceName: "jadda-jadda",
+ ContainerNameOrID: "jadda-jadda",
+ RestartPolicy: "always",
+ PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 42,
+ PodmanVersion: "CI",
+ CreateCommand: []string{"I'll get stripped", "run", "-dti", "awesome-image:latest"},
+ EnvVariable: EnvVariable,
+ },
+ genGoodNewDetach("-dti"),
+ true,
+ false,
+ },
+ {"good with multiple shorthand params detach last",
+ containerInfo{
+ Executable: "/usr/bin/podman",
+ ServiceName: "jadda-jadda",
+ ContainerNameOrID: "jadda-jadda",
+ RestartPolicy: "always",
+ PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 42,
+ PodmanVersion: "CI",
+ CreateCommand: []string{"I'll get stripped", "run", "-tid", "awesome-image:latest"},
+ EnvVariable: EnvVariable,
+ },
+ genGoodNewDetach("-tid"),
+ true,
+ false,
+ },
+ {"good with root flags",
+ containerInfo{
+ Executable: "/usr/bin/podman",
+ ServiceName: "jadda-jadda",
+ ContainerNameOrID: "jadda-jadda",
+ RestartPolicy: "always",
+ PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 42,
+ PodmanVersion: "CI",
+ CreateCommand: []string{"I'll get stripped", "--events-backend", "none", "--runroot", "/root", "run", "awesome-image:latest"},
+ EnvVariable: EnvVariable,
+ },
+ goodNewRootFlags,
+ true,
+ false,
+ },
+ {"good with container create",
+ containerInfo{
+ Executable: "/usr/bin/podman",
+ ServiceName: "jadda-jadda",
+ ContainerNameOrID: "jadda-jadda",
+ RestartPolicy: "always",
+ PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 10,
+ PodmanVersion: "CI",
+ CreateCommand: []string{"I'll get stripped", "container", "create", "awesome-image:latest"},
+ EnvVariable: EnvVariable,
+ },
+ goodContainerCreate,
+ true,
+ false,
+ },
}
for _, tt := range tests {
test := tt
@@ -390,9 +620,7 @@ WantedBy=multi-user.target default.target
t.Errorf("CreateContainerSystemdUnit() error = \n%v, wantErr \n%v", err, test.wantErr)
return
}
- if got != test.want {
- t.Errorf("CreateContainerSystemdUnit() = \n%v\n---------> want\n%v", got, test.want)
- }
+ assert.Equal(t, test.want, got)
})
}
}
diff --git a/pkg/systemd/generate/pods.go b/pkg/systemd/generate/pods.go
index 3c57b03fb..7678a240f 100644
--- a/pkg/systemd/generate/pods.go
+++ b/pkg/systemd/generate/pods.go
@@ -14,6 +14,7 @@ import (
"github.com/containers/podman/v2/version"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
+ "github.com/spf13/pflag"
)
// podInfo contains data required for generating a pod's systemd
@@ -44,6 +45,9 @@ type podInfo struct {
// Executable is the path to the podman executable. Will be auto-filled if
// left empty.
Executable string
+ // RootFlags contains the root flags which were used to create the container
+ // Only used with --new
+ RootFlags string
// TimeStamp at the time of creating the unit file. Will be set internally.
TimeStamp string
// CreateCommand is the full command plus arguments of the process the
@@ -60,6 +64,8 @@ type podInfo struct {
ExecStartPre2 string
// ExecStart of the unit.
ExecStart string
+ // TimeoutStopSec of the unit.
+ TimeoutStopSec uint
// ExecStop of the unit.
ExecStop string
// ExecStopPost of the unit.
@@ -72,6 +78,7 @@ Before={{- range $index, $value := .RequiredServices -}}{{if $index}} {{end}}{{
[Service]
Environment={{.EnvVariable}}=%n
Restart={{.RestartPolicy}}
+TimeoutStopSec={{.TimeoutStopSec}}
{{- if .ExecStartPre1}}
ExecStartPre={{.ExecStartPre1}}
{{- end}}
@@ -82,7 +89,6 @@ ExecStart={{.ExecStart}}
ExecStop={{.ExecStop}}
ExecStopPost={{.ExecStopPost}}
PIDFile={{.PIDFile}}
-KillMode=none
Type=forking
[Install]
@@ -262,7 +268,8 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions)
if podCreateIndex == 0 {
return "", errors.Errorf("pod does not appear to be created via `podman pod create`: %v", info.CreateCommand)
}
- podRootArgs = info.CreateCommand[0 : podCreateIndex-2]
+ podRootArgs = info.CreateCommand[1 : podCreateIndex-1]
+ info.RootFlags = strings.Join(quoteArguments(podRootArgs), " ")
podCreateArgs = filterPodFlags(info.CreateCommand[podCreateIndex+1:])
}
// We're hard-coding the first five arguments and append the
@@ -275,17 +282,26 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions)
"--pod-id-file", "{{.PodIDFile}}"}...)
// Presence check for certain flags/options.
- hasNameParam := false
- hasReplaceParam := false
- for _, p := range podCreateArgs {
- switch p {
- case "--name":
- hasNameParam = true
- case "--replace":
- hasReplaceParam = true
- }
+ fs := pflag.NewFlagSet("args", pflag.ContinueOnError)
+ fs.ParseErrorsWhitelist.UnknownFlags = true
+ fs.Usage = func() {}
+ fs.SetInterspersed(false)
+ fs.String("name", "", "")
+ fs.Bool("replace", false, "")
+ fs.Parse(podCreateArgs)
+
+ hasNameParam := fs.Lookup("name").Changed
+ hasReplaceParam, err := fs.GetBool("replace")
+ if err != nil {
+ return "", err
}
if hasNameParam && !hasReplaceParam {
+ if fs.Changed("replace") {
+ // this can only happen if --replace=false is set
+ // in that case we need to remove it otherwise we
+ // would overwrite the previous replace arg to false
+ podCreateArgs = removeReplaceArg(podCreateArgs, fs.NArg())
+ }
podCreateArgs = append(podCreateArgs, "--replace")
}
@@ -294,10 +310,12 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions)
info.ExecStartPre1 = "/bin/rm -f {{.PIDFile}} {{.PodIDFile}}"
info.ExecStartPre2 = strings.Join(startCommand, " ")
- info.ExecStart = "{{.Executable}} pod start --pod-id-file {{.PodIDFile}}"
- info.ExecStop = "{{.Executable}} pod stop --ignore --pod-id-file {{.PodIDFile}} {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}}"
- info.ExecStopPost = "{{.Executable}} pod rm --ignore -f --pod-id-file {{.PodIDFile}}"
+ info.ExecStart = "{{.Executable}} {{if .RootFlags}}{{ .RootFlags}} {{end}}pod start --pod-id-file {{.PodIDFile}}"
+ info.ExecStop = "{{.Executable}} {{if .RootFlags}}{{ .RootFlags}} {{end}}pod stop --ignore --pod-id-file {{.PodIDFile}} {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}}"
+ info.ExecStopPost = "{{.Executable}} {{if .RootFlags}}{{ .RootFlags}} {{end}}pod rm --ignore -f --pod-id-file {{.PodIDFile}}"
}
+ info.TimeoutStopSec = minTimeoutStopSec + info.StopTimeout
+
if info.PodmanVersion == "" {
info.PodmanVersion = version.Version.String()
}
diff --git a/pkg/systemd/generate/pods_test.go b/pkg/systemd/generate/pods_test.go
index 7f1f63b7e..c0d98df45 100644
--- a/pkg/systemd/generate/pods_test.go
+++ b/pkg/systemd/generate/pods_test.go
@@ -4,6 +4,7 @@ import (
"testing"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/stretchr/testify/assert"
)
func TestValidateRestartPolicyPod(t *testing.T) {
@@ -50,11 +51,11 @@ Before=container-1.service container-2.service
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
+TimeoutStopSec=102
ExecStart=/usr/bin/podman start jadda-jadda-infra
-ExecStop=/usr/bin/podman stop -t 10 jadda-jadda-infra
-ExecStopPost=/usr/bin/podman stop -t 10 jadda-jadda-infra
-PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
-KillMode=none
+ExecStop=/usr/bin/podman stop -t 42 jadda-jadda-infra
+ExecStopPost=/usr/bin/podman stop -t 42 jadda-jadda-infra
+PIDFile=/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
Type=forking
[Install]
@@ -75,13 +76,67 @@ Before=container-1.service container-2.service
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
+TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/pod-123abc.pid %t/pod-123abc.pod-id
ExecStartPre=/usr/bin/podman pod create --infra-conmon-pidfile %t/pod-123abc.pid --pod-id-file %t/pod-123abc.pod-id --name foo "bar=arg with space" --replace
ExecStart=/usr/bin/podman pod start --pod-id-file %t/pod-123abc.pod-id
ExecStop=/usr/bin/podman pod stop --ignore --pod-id-file %t/pod-123abc.pod-id -t 10
ExecStopPost=/usr/bin/podman pod rm --ignore -f --pod-id-file %t/pod-123abc.pod-id
PIDFile=%t/pod-123abc.pid
-KillMode=none
+Type=forking
+
+[Install]
+WantedBy=multi-user.target default.target
+`
+
+ podGoodNamedNewWithRootArgs := `# pod-123abc.service
+# autogenerated by Podman CI
+
+[Unit]
+Description=Podman pod-123abc.service
+Documentation=man:podman-generate-systemd(1)
+Wants=network.target
+After=network-online.target
+Requires=container-1.service container-2.service
+Before=container-1.service container-2.service
+
+[Service]
+Environment=PODMAN_SYSTEMD_UNIT=%n
+Restart=on-failure
+TimeoutStopSec=70
+ExecStartPre=/bin/rm -f %t/pod-123abc.pid %t/pod-123abc.pod-id
+ExecStartPre=/usr/bin/podman --events-backend none --runroot /root pod create --infra-conmon-pidfile %t/pod-123abc.pid --pod-id-file %t/pod-123abc.pod-id --name foo "bar=arg with space" --replace
+ExecStart=/usr/bin/podman --events-backend none --runroot /root pod start --pod-id-file %t/pod-123abc.pod-id
+ExecStop=/usr/bin/podman --events-backend none --runroot /root pod stop --ignore --pod-id-file %t/pod-123abc.pod-id -t 10
+ExecStopPost=/usr/bin/podman --events-backend none --runroot /root pod rm --ignore -f --pod-id-file %t/pod-123abc.pod-id
+PIDFile=%t/pod-123abc.pid
+Type=forking
+
+[Install]
+WantedBy=multi-user.target default.target
+`
+
+ podGoodNamedNewWithReplaceFalse := `# pod-123abc.service
+# autogenerated by Podman CI
+
+[Unit]
+Description=Podman pod-123abc.service
+Documentation=man:podman-generate-systemd(1)
+Wants=network.target
+After=network-online.target
+Requires=container-1.service container-2.service
+Before=container-1.service container-2.service
+
+[Service]
+Environment=PODMAN_SYSTEMD_UNIT=%n
+Restart=on-failure
+TimeoutStopSec=70
+ExecStartPre=/bin/rm -f %t/pod-123abc.pid %t/pod-123abc.pod-id
+ExecStartPre=/usr/bin/podman pod create --infra-conmon-pidfile %t/pod-123abc.pid --pod-id-file %t/pod-123abc.pod-id --name foo --replace
+ExecStart=/usr/bin/podman pod start --pod-id-file %t/pod-123abc.pod-id
+ExecStop=/usr/bin/podman pod stop --ignore --pod-id-file %t/pod-123abc.pod-id -t 10
+ExecStopPost=/usr/bin/podman pod rm --ignore -f --pod-id-file %t/pod-123abc.pod-id
+PIDFile=%t/pod-123abc.pid
Type=forking
[Install]
@@ -101,10 +156,27 @@ WantedBy=multi-user.target default.target
ServiceName: "pod-123abc",
InfraNameOrID: "jadda-jadda-infra",
RestartPolicy: "always",
+ PIDFile: "/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 42,
+ PodmanVersion: "CI",
+ RequiredServices: []string{"container-1", "container-2"},
+ CreateCommand: []string{"podman", "pod", "create", "--name", "foo", "bar=arg with space"},
+ },
+ podGood,
+ false,
+ false,
+ },
+ {"pod with root args",
+ podInfo{
+ Executable: "/usr/bin/podman",
+ ServiceName: "pod-123abc",
+ InfraNameOrID: "jadda-jadda-infra",
+ RestartPolicy: "always",
PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 10,
+ StopTimeout: 42,
PodmanVersion: "CI",
RequiredServices: []string{"container-1", "container-2"},
+ CreateCommand: []string{"podman", "--events-backend", "none", "--runroot", "/root", "pod", "create", "--name", "foo", "bar=arg with space"},
},
podGood,
false,
@@ -116,7 +188,7 @@ WantedBy=multi-user.target default.target
ServiceName: "pod-123abc",
InfraNameOrID: "jadda-jadda-infra",
RestartPolicy: "on-failure",
- PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ PIDFile: "/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
StopTimeout: 10,
PodmanVersion: "CI",
RequiredServices: []string{"container-1", "container-2"},
@@ -126,6 +198,38 @@ WantedBy=multi-user.target default.target
true,
false,
},
+ {"pod --new with root args",
+ podInfo{
+ Executable: "/usr/bin/podman",
+ ServiceName: "pod-123abc",
+ InfraNameOrID: "jadda-jadda-infra",
+ RestartPolicy: "on-failure",
+ PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 10,
+ PodmanVersion: "CI",
+ RequiredServices: []string{"container-1", "container-2"},
+ CreateCommand: []string{"podman", "--events-backend", "none", "--runroot", "/root", "pod", "create", "--name", "foo", "bar=arg with space"},
+ },
+ podGoodNamedNewWithRootArgs,
+ true,
+ false,
+ },
+ {"pod --new with --replace=false",
+ podInfo{
+ Executable: "/usr/bin/podman",
+ ServiceName: "pod-123abc",
+ InfraNameOrID: "jadda-jadda-infra",
+ RestartPolicy: "on-failure",
+ PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 10,
+ PodmanVersion: "CI",
+ RequiredServices: []string{"container-1", "container-2"},
+ CreateCommand: []string{"podman", "pod", "create", "--name", "foo", "--replace=false"},
+ },
+ podGoodNamedNewWithReplaceFalse,
+ true,
+ false,
+ },
}
for _, tt := range tests {
@@ -139,9 +243,7 @@ WantedBy=multi-user.target default.target
t.Errorf("CreatePodSystemdUnit() error = \n%v, wantErr \n%v", err, test.wantErr)
return
}
- if got != test.want {
- t.Errorf("CreatePodSystemdUnit() = \n%v\n---------> want\n%v", got, test.want)
- }
+ assert.Equal(t, test.want, got)
})
}
}