summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/compat/containers_prune.go44
-rw-r--r--pkg/api/handlers/compat/images.go47
-rw-r--r--pkg/api/handlers/compat/images_prune.go75
-rw-r--r--pkg/api/handlers/compat/volumes.go28
-rw-r--r--pkg/api/handlers/libpod/containers.go1
-rw-r--r--pkg/api/handlers/libpod/images.go3
-rw-r--r--pkg/api/handlers/libpod/pods.go11
-rw-r--r--pkg/api/handlers/libpod/system.go4
-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/checkpoint/checkpoint_restore.go29
-rw-r--r--pkg/domain/entities/container_ps.go2
-rw-r--r--pkg/domain/entities/containers.go5
-rw-r--r--pkg/domain/entities/play.go3
-rw-r--r--pkg/domain/entities/pods.go6
-rw-r--r--pkg/domain/filters/containers.go21
-rw-r--r--pkg/domain/filters/pods.go26
-rw-r--r--pkg/domain/filters/volumes.go4
-rw-r--r--pkg/domain/infra/abi/containers.go27
-rw-r--r--pkg/domain/infra/abi/images.go3
-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.go5
-rw-r--r--pkg/netns/netns_linux.go4
-rw-r--r--pkg/ps/ps.go6
-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/oci.go2
-rw-r--r--pkg/specgen/generate/storage.go8
-rw-r--r--pkg/specgen/generate/validate.go2
-rw-r--r--pkg/systemd/generate/common.go27
-rw-r--r--pkg/systemd/generate/containers.go80
-rw-r--r--pkg/systemd/generate/containers_test.go267
-rw-r--r--pkg/systemd/generate/pods.go40
-rw-r--r--pkg/systemd/generate/pods_test.go107
39 files changed, 756 insertions, 305 deletions
diff --git a/pkg/api/handlers/compat/containers_prune.go b/pkg/api/handlers/compat/containers_prune.go
index b3d26b8f4..7bba38475 100644
--- a/pkg/api/handlers/compat/containers_prune.go
+++ b/pkg/api/handlers/compat/containers_prune.go
@@ -1,9 +1,11 @@
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/reports"
"github.com/containers/podman/v2/pkg/domain/filters"
@@ -32,33 +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
}
- report, err := runtime.PruneContainers(filterFuncs)
- if err != nil {
- utils.InternalServerError(w, err)
+ 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
+ }
+ 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) (
- []*reports.PruneReport, error) {
+func PruneContainersHelper(r *http.Request, filterFuncs []libpod.ContainerFilter) ([]*reports.PruneReport, error) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
- reports, err := runtime.PruneContainers(filterFuncs)
+
+ report, err := runtime.PruneContainers(filterFuncs)
if err != nil {
- utils.InternalServerError(w, err)
return nil, err
}
- return reports, nil
+ return report, nil
}
diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go
index 9d7503aba..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,52 +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))
- }
- }
- imagePruneReports, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, filters)
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
- reclaimedSpace := uint64(0)
- for _, p := range imagePruneReports {
- idr = append(idr, types.ImageDeleteResponseItem{
- Deleted: p.Id,
- })
- reclaimedSpace = reclaimedSpace + p.Size
- }
-
- // 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: reclaimedSpace,
- }
- 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 1188d8f84..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 _, v := range pruned {
- // XXX: This drops any pruning per-volume error messages on the floor
+ 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 979a8adc4..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"
@@ -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 130e563ae..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,7 +38,7 @@ func SystemPrune(w http.ResponseWriter, r *http.Request) {
systemPruneReport.PodPruneReport = podPruneReport
// We could parallelize this, should we?
- containerPruneReports, err := compat.PruneContainersHelper(w, r, nil)
+ containerPruneReports, err := compat.PruneContainersHelper(r, nil)
if err != nil {
utils.InternalServerError(w, err)
return
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/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 05b9b774e..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 {
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/filters/containers.go b/pkg/domain/filters/containers.go
index ce6c12b71..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,6 +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 9d7c2daea..b5f5a0e91 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -113,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
}
@@ -134,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
}
@@ -487,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 {
@@ -525,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{
@@ -538,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 19f081abb..3487dc3f4 100644
--- a/pkg/domain/infra/abi/images.go
+++ b/pkg/domain/infra/abi/images.go
@@ -22,7 +22,6 @@ 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"
@@ -206,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 67c018122..97fa9d374 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -162,11 +162,6 @@ 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)
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/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/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/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 fb921cd72..8901298db 100644
--- a/pkg/systemd/generate/common.go
+++ b/pkg/systemd/generate/common.go
@@ -71,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 cfa02dc9d..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
@@ -185,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 {
@@ -210,23 +222,27 @@ 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
//
@@ -240,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
@@ -247,14 +270,21 @@ 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
diff --git a/pkg/systemd/generate/containers_test.go b/pkg/systemd/generate/containers_test.go
index b9fb8fee6..c8e65bfe3 100644
--- a/pkg/systemd/generate/containers_test.go
+++ b/pkg/systemd/generate/containers_test.go
@@ -53,7 +53,7 @@ TimeoutStopSec=82
ExecStart=/usr/bin/podman start 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
ExecStop=/usr/bin/podman stop -t 22 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
ExecStopPost=/usr/bin/podman stop -t 22 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
-PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
+PIDFile=/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
Type=forking
[Install]
@@ -76,7 +76,7 @@ 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
+PIDFile=/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
Type=forking
[Install]
@@ -101,7 +101,7 @@ 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
+PIDFile=/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
Type=forking
[Install]
@@ -122,9 +122,9 @@ 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 10
-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
Type=forking
@@ -228,6 +228,107 @@ Type=forking
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]
+WantedBy=multi-user.target default.target
+`
+
tests := []struct {
name string
info containerInfo
@@ -242,7 +343,7 @@ 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: 22,
PodmanVersion: "CI",
EnvVariable: EnvVariable,
@@ -257,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,
@@ -272,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"},
@@ -287,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,
@@ -302,7 +403,7 @@ 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",
+ 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"},
@@ -318,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",
+ 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,
@@ -334,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",
+ 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",
@@ -353,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",
+ 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,
@@ -369,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
diff --git a/pkg/systemd/generate/pods.go b/pkg/systemd/generate/pods.go
index fc582e42a..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
@@ -264,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
@@ -277,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")
}
@@ -296,9 +310,9 @@ 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
diff --git a/pkg/systemd/generate/pods_test.go b/pkg/systemd/generate/pods_test.go
index 6d925ecd2..c0d98df45 100644
--- a/pkg/systemd/generate/pods_test.go
+++ b/pkg/systemd/generate/pods_test.go
@@ -55,7 +55,7 @@ TimeoutStopSec=102
ExecStart=/usr/bin/podman start jadda-jadda-infra
ExecStop=/usr/bin/podman stop -t 42 jadda-jadda-infra
ExecStopPost=/usr/bin/podman stop -t 42 jadda-jadda-infra
-PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
+PIDFile=/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
Type=forking
[Install]
@@ -89,6 +89,60 @@ Type=forking
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]
+WantedBy=multi-user.target default.target
+`
+
tests := []struct {
name string
info podInfo
@@ -102,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: 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,
@@ -117,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"},
@@ -127,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 {