summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/compat/containers.go7
-rw-r--r--pkg/api/handlers/compat/containers_create.go8
-rw-r--r--pkg/api/handlers/compat/images_history.go2
-rw-r--r--pkg/api/handlers/compat/info.go2
-rw-r--r--pkg/api/handlers/compat/networks.go6
-rw-r--r--pkg/api/handlers/libpod/pods.go22
-rw-r--r--pkg/api/handlers/libpod/system.go2
-rw-r--r--pkg/api/handlers/libpod/volumes.go12
-rw-r--r--pkg/api/handlers/utils/images.go7
-rw-r--r--pkg/api/handlers/utils/pods.go6
-rw-r--r--pkg/api/server/docs.go25
-rw-r--r--pkg/bindings/connection.go15
-rw-r--r--pkg/bindings/containers/checkpoint.go2
-rw-r--r--pkg/bindings/containers/types.go2
-rw-r--r--pkg/bindings/images/images.go2
-rw-r--r--pkg/cgroups/cgroups.go4
-rw-r--r--pkg/cgroups/cpu.go3
-rw-r--r--pkg/domain/entities/generate.go2
-rw-r--r--pkg/domain/entities/pods.go22
-rw-r--r--pkg/domain/infra/abi/containers.go91
-rw-r--r--pkg/domain/infra/abi/containers_runlabel.go12
-rw-r--r--pkg/domain/infra/abi/cp.go6
-rw-r--r--pkg/domain/infra/abi/generate.go161
-rw-r--r--pkg/domain/infra/abi/images.go7
-rw-r--r--pkg/domain/infra/abi/images_list.go9
-rw-r--r--pkg/domain/infra/abi/manifest.go4
-rw-r--r--pkg/domain/infra/abi/network.go7
-rw-r--r--pkg/domain/infra/abi/play.go13
-rw-r--r--pkg/domain/infra/abi/pods.go39
-rw-r--r--pkg/domain/infra/abi/system.go12
-rw-r--r--pkg/domain/infra/abi/volumes.go17
-rw-r--r--pkg/domain/infra/tunnel/containers.go50
-rw-r--r--pkg/domain/infra/tunnel/images.go2
-rw-r--r--pkg/domain/infra/tunnel/network.go4
-rw-r--r--pkg/domain/infra/tunnel/pods.go25
-rw-r--r--pkg/domain/infra/tunnel/volumes.go9
-rw-r--r--pkg/hooks/exec/runtimeconfigfilter_test.go54
-rw-r--r--pkg/lookup/lookup.go2
-rw-r--r--pkg/network/files.go11
-rw-r--r--pkg/network/network.go4
-rw-r--r--pkg/ps/ps.go2
-rw-r--r--pkg/signal/signal_linux.go2
-rw-r--r--pkg/specgen/generate/pod_create.go4
-rw-r--r--pkg/specgen/podspecgen.go3
-rw-r--r--pkg/systemd/generate/common.go50
-rw-r--r--pkg/systemd/generate/common_test.go25
-rw-r--r--pkg/systemd/generate/containers.go289
-rw-r--r--pkg/systemd/generate/containers_test.go366
-rw-r--r--pkg/systemd/generate/pods.go341
-rw-r--r--pkg/systemd/generate/pods_test.go100
-rw-r--r--pkg/systemd/generate/systemdgen.go237
-rw-r--r--pkg/systemd/generate/systemdgen_test.go347
-rw-r--r--pkg/util/mountOpts.go3
53 files changed, 1431 insertions, 1028 deletions
diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go
index b90f3d625..8ce2180ab 100644
--- a/pkg/api/handlers/compat/containers.go
+++ b/pkg/api/handlers/compat/containers.go
@@ -465,8 +465,11 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON,
ports := make(nat.PortSet)
for p := range inspect.HostConfig.PortBindings {
- splitp := strings.Split(p, "/")
- port, err := nat.NewPort(splitp[0], splitp[1])
+ splitp := strings.SplitN(p, "/", 2)
+ if len(splitp) != 2 {
+ return nil, errors.Errorf("PORT/PROTOCOL Format required for %q", p)
+ }
+ port, err := nat.NewPort(splitp[1], splitp[0])
if err != nil {
return nil, err
}
diff --git a/pkg/api/handlers/compat/containers_create.go b/pkg/api/handlers/compat/containers_create.go
index 3d4bd4fb5..3ae9d9ab3 100644
--- a/pkg/api/handlers/compat/containers_create.go
+++ b/pkg/api/handlers/compat/containers_create.go
@@ -62,10 +62,8 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
func makeCreateConfig(containerConfig *config.Config, input handlers.CreateContainerConfig, newImage *image2.Image) (createconfig.CreateConfig, error) {
var (
- err error
- init bool
- tmpfs []string
- volumes []string
+ err error
+ init bool
)
env := make(map[string]string)
stopSignal := unix.SIGTERM
@@ -137,6 +135,7 @@ func makeCreateConfig(containerConfig *config.Config, input handlers.CreateConta
User: input.User,
}
pidConfig := createconfig.PidConfig{PidMode: namespaces.PidMode(input.HostConfig.PidMode)}
+ volumes := make([]string, 0, len(input.Volumes))
for k := range input.Volumes {
volumes = append(volumes, k)
}
@@ -158,6 +157,7 @@ func makeCreateConfig(containerConfig *config.Config, input handlers.CreateConta
}
// format the tmpfs mounts into a []string from map
+ tmpfs := make([]string, 0, len(input.HostConfig.Tmpfs))
for k, v := range input.HostConfig.Tmpfs {
tmpfs = append(tmpfs, fmt.Sprintf("%s:%s", k, v))
}
diff --git a/pkg/api/handlers/compat/images_history.go b/pkg/api/handlers/compat/images_history.go
index afadf4c48..7c0bbf828 100644
--- a/pkg/api/handlers/compat/images_history.go
+++ b/pkg/api/handlers/compat/images_history.go
@@ -12,7 +12,6 @@ import (
func HistoryImage(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
name := utils.GetName(r)
- var allHistory []handlers.HistoryResponse
newImage, err := runtime.ImageRuntime().NewFromLocal(name)
if err != nil {
@@ -25,6 +24,7 @@ func HistoryImage(w http.ResponseWriter, r *http.Request) {
utils.InternalServerError(w, err)
return
}
+ allHistory := make([]handlers.HistoryResponse, 0, len(history))
for _, h := range history {
l := handlers.HistoryResponse{
ID: h.ID,
diff --git a/pkg/api/handlers/compat/info.go b/pkg/api/handlers/compat/info.go
index d4a933c54..5c3f610a4 100644
--- a/pkg/api/handlers/compat/info.go
+++ b/pkg/api/handlers/compat/info.go
@@ -129,7 +129,7 @@ func GetInfo(w http.ResponseWriter, r *http.Request) {
}
func getGraphStatus(storeInfo map[string]string) [][2]string {
- var graphStatus [][2]string
+ graphStatus := make([][2]string, 0, len(storeInfo))
for k, v := range storeInfo {
graphStatus = append(graphStatus, [2]string{k, v})
}
diff --git a/pkg/api/handlers/compat/networks.go b/pkg/api/handlers/compat/networks.go
index 8734ba405..0f1eca5e5 100644
--- a/pkg/api/handlers/compat/networks.go
+++ b/pkg/api/handlers/compat/networks.go
@@ -162,9 +162,6 @@ func findPluginByName(plugins []*libcni.NetworkConfig, pluginType string) ([]byt
}
func ListNetworks(w http.ResponseWriter, r *http.Request) {
- var (
- reports []*types.NetworkResource
- )
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
@@ -191,6 +188,7 @@ func ListNetworks(w http.ResponseWriter, r *http.Request) {
utils.InternalServerError(w, err)
return
}
+ reports := make([]*types.NetworkResource, 0, len(netNames))
for _, name := range netNames {
report, err := getNetworkResourceByName(name, runtime)
if err != nil {
@@ -215,7 +213,7 @@ func CreateNetwork(w http.ResponseWriter, r *http.Request) {
if len(networkCreate.Name) > 0 {
name = networkCreate.Name
}
- // At present I think we should just suport the bridge driver
+ // At present I think we should just support the bridge driver
// and allow demand to make us consider more
if networkCreate.Driver != network.DefaultNetworkDriver {
utils.InternalServerError(w, errors.New("network create only supports the bridge driver"))
diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go
index 7d4d03144..4b57ef26a 100644
--- a/pkg/api/handlers/libpod/pods.go
+++ b/pkg/api/handlers/libpod/pods.go
@@ -89,7 +89,6 @@ func PodStop(w http.ResponseWriter, r *http.Request) {
runtime = r.Context().Value("runtime").(*libpod.Runtime)
decoder = r.Context().Value("decoder").(*schema.Decoder)
responses map[string]error
- errs []error
)
query := struct {
Timeout int `schema:"t"`
@@ -128,6 +127,7 @@ func PodStop(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
return
}
+ var errs []error //nolint
for _, err := range responses {
errs = append(errs, err)
}
@@ -139,9 +139,7 @@ func PodStop(w http.ResponseWriter, r *http.Request) {
}
func PodStart(w http.ResponseWriter, r *http.Request) {
- var (
- errs []error
- )
+ var errs []error //nolint
runtime := r.Context().Value("runtime").(*libpod.Runtime)
name := utils.GetName(r)
pod, err := runtime.LookupPod(name)
@@ -206,9 +204,7 @@ func PodDelete(w http.ResponseWriter, r *http.Request) {
}
func PodRestart(w http.ResponseWriter, r *http.Request) {
- var (
- errs []error
- )
+ var errs []error //nolint
runtime := r.Context().Value("runtime").(*libpod.Runtime)
name := utils.GetName(r)
pod, err := runtime.LookupPod(name)
@@ -243,12 +239,12 @@ func PodPrune(w http.ResponseWriter, r *http.Request) {
func PodPruneHelper(w http.ResponseWriter, r *http.Request) ([]*entities.PodPruneReport, error) {
var (
runtime = r.Context().Value("runtime").(*libpod.Runtime)
- reports []*entities.PodPruneReport
)
responses, err := runtime.PrunePods(r.Context())
if err != nil {
return nil, err
}
+ reports := make([]*entities.PodPruneReport, 0, len(responses))
for k, v := range responses {
reports = append(reports, &entities.PodPruneReport{
Err: v,
@@ -259,9 +255,7 @@ func PodPruneHelper(w http.ResponseWriter, r *http.Request) ([]*entities.PodPrun
}
func PodPause(w http.ResponseWriter, r *http.Request) {
- var (
- errs []error
- )
+ var errs []error //nolint
runtime := r.Context().Value("runtime").(*libpod.Runtime)
name := utils.GetName(r)
pod, err := runtime.LookupPod(name)
@@ -285,9 +279,7 @@ func PodPause(w http.ResponseWriter, r *http.Request) {
}
func PodUnpause(w http.ResponseWriter, r *http.Request) {
- var (
- errs []error
- )
+ var errs []error //nolint
runtime := r.Context().Value("runtime").(*libpod.Runtime)
name := utils.GetName(r)
pod, err := runtime.LookupPod(name)
@@ -357,7 +349,7 @@ func PodKill(w http.ResponseWriter, r *http.Request) {
runtime = r.Context().Value("runtime").(*libpod.Runtime)
decoder = r.Context().Value("decoder").(*schema.Decoder)
signal = "SIGKILL"
- errs []error
+ errs []error //nolint
)
query := struct {
Signal string `schema:"signal"`
diff --git a/pkg/api/handlers/libpod/system.go b/pkg/api/handlers/libpod/system.go
index f575546c9..52d3b91ab 100644
--- a/pkg/api/handlers/libpod/system.go
+++ b/pkg/api/handlers/libpod/system.go
@@ -61,7 +61,7 @@ func SystemPrune(w http.ResponseWriter, r *http.Request) {
systemPruneReport.ImagePruneReport = &report
if query.Volumes {
- volumePruneReport, err := pruneVolumesHelper(w, r)
+ volumePruneReport, err := pruneVolumesHelper(r)
if err != nil {
utils.InternalServerError(w, err)
return
diff --git a/pkg/api/handlers/libpod/volumes.go b/pkg/api/handlers/libpod/volumes.go
index b5574b87b..ea035fc4d 100644
--- a/pkg/api/handlers/libpod/volumes.go
+++ b/pkg/api/handlers/libpod/volumes.go
@@ -102,9 +102,8 @@ func InspectVolume(w http.ResponseWriter, r *http.Request) {
func ListVolumes(w http.ResponseWriter, r *http.Request) {
var (
- decoder = r.Context().Value("decoder").(*schema.Decoder)
- runtime = r.Context().Value("runtime").(*libpod.Runtime)
- volumeConfigs []*entities.VolumeListReport
+ decoder = r.Context().Value("decoder").(*schema.Decoder)
+ runtime = r.Context().Value("runtime").(*libpod.Runtime)
)
query := struct {
Filters map[string][]string `schema:"filters"`
@@ -129,6 +128,7 @@ func ListVolumes(w http.ResponseWriter, r *http.Request) {
utils.InternalServerError(w, err)
return
}
+ volumeConfigs := make([]*entities.VolumeListReport, 0, len(vols))
for _, v := range vols {
config := entities.VolumeConfigResponse{
Name: v.Name(),
@@ -147,7 +147,7 @@ func ListVolumes(w http.ResponseWriter, r *http.Request) {
}
func PruneVolumes(w http.ResponseWriter, r *http.Request) {
- reports, err := pruneVolumesHelper(w, r)
+ reports, err := pruneVolumesHelper(r)
if err != nil {
utils.InternalServerError(w, err)
return
@@ -155,15 +155,15 @@ func PruneVolumes(w http.ResponseWriter, r *http.Request) {
utils.WriteResponse(w, http.StatusOK, reports)
}
-func pruneVolumesHelper(w http.ResponseWriter, r *http.Request) ([]*entities.VolumePruneReport, error) {
+func pruneVolumesHelper(r *http.Request) ([]*entities.VolumePruneReport, error) {
var (
runtime = r.Context().Value("runtime").(*libpod.Runtime)
- reports []*entities.VolumePruneReport
)
pruned, err := runtime.PruneVolumes(r.Context())
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,
diff --git a/pkg/api/handlers/utils/images.go b/pkg/api/handlers/utils/images.go
index 7fb31a177..521f727be 100644
--- a/pkg/api/handlers/utils/images.go
+++ b/pkg/api/handlers/utils/images.go
@@ -3,6 +3,7 @@ package utils
import (
"fmt"
"net/http"
+ "strings"
"github.com/containers/image/v5/docker"
"github.com/containers/image/v5/storage"
@@ -77,9 +78,7 @@ func GetImages(w http.ResponseWriter, r *http.Request) ([]*image.Image, error) {
if len(query.Filters) > 0 {
for k, v := range query.Filters {
- for _, val := range v {
- filters = append(filters, fmt.Sprintf("%s=%s", k, val))
- }
+ filters = append(filters, fmt.Sprintf("%s=%s", k, strings.Join(v, "=")))
}
images, err = runtime.ImageRuntime().GetImagesWithFilters(filters)
if err != nil {
@@ -94,7 +93,7 @@ func GetImages(w http.ResponseWriter, r *http.Request) ([]*image.Image, error) {
if query.All {
return images, nil
}
- var returnImages []*image.Image
+ returnImages := []*image.Image{}
for _, img := range images {
if len(img.Names()) == 0 {
parent, err := img.IsParent(r.Context())
diff --git a/pkg/api/handlers/utils/pods.go b/pkg/api/handlers/utils/pods.go
index 4a5cbd05c..0bb818c1c 100644
--- a/pkg/api/handlers/utils/pods.go
+++ b/pkg/api/handlers/utils/pods.go
@@ -11,7 +11,6 @@ import (
func GetPods(w http.ResponseWriter, r *http.Request) ([]*entities.ListPodsReport, error) {
var (
- lps []*entities.ListPodsReport
pods []*libpod.Pod
filters []libpod.PodFilter
)
@@ -45,6 +44,11 @@ func GetPods(w http.ResponseWriter, r *http.Request) ([]*entities.ListPodsReport
return nil, err
}
+ if len(pods) == 0 {
+ return nil, nil
+ }
+
+ lps := make([]*entities.ListPodsReport, 0, len(pods))
for _, pod := range pods {
status, err := pod.GetPodStatus()
if err != nil {
diff --git a/pkg/api/server/docs.go b/pkg/api/server/docs.go
index c989c7927..124c16092 100644
--- a/pkg/api/server/docs.go
+++ b/pkg/api/server/docs.go
@@ -4,6 +4,31 @@
// only as experimental as this point. The endpoints, parameters, inputs, and
// return values can all change.
//
+// To start the service and keep it running for 5,000 seconds (-t 0 runs forever):
+//
+// podman system service -t 5000 &
+//
+// 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
+//
+// See podman-service(1) for more information.
+//
+// Quick Examples:
+//
+// 'podman info'
+//
+// curl --unix-socket /run/podman/podman.sock http://d/v1.0.0/libpod/info
+//
+// 'podman pull quay.io/containers/podman'
+//
+// curl -XPOST --unix-socket /run/podman/podman.sock -v 'http://d/v1.0.0/images/create?fromImage=quay.io%2Fcontainers%2Fpodman'
+//
+// 'podman list images'
+//
+// curl --unix-socket /run/podman/podman.sock -v 'http://d/v1.0.0/libpod/images/json' | jq
+//
// Terms Of Service:
//
// Schemes: http, https
diff --git a/pkg/bindings/connection.go b/pkg/bindings/connection.go
index aa7f3707c..a9c61e5ae 100644
--- a/pkg/bindings/connection.go
+++ b/pkg/bindings/connection.go
@@ -115,12 +115,12 @@ func NewConnectionWithIdentity(ctx context.Context, uri string, passPhrase strin
_url.Path = JoinURL(_url.Host, _url.Path)
_url.Host = ""
}
- connection, err = unixClient(_url)
+ connection = unixClient(_url)
case "tcp":
if !strings.HasPrefix(uri, "tcp://") {
return nil, errors.New("tcp URIs should begin with tcp://")
}
- connection, err = tcpClient(_url)
+ connection = tcpClient(_url)
default:
return nil, errors.Errorf("'%s' is not a supported schema", _url.Scheme)
}
@@ -135,7 +135,7 @@ func NewConnectionWithIdentity(ctx context.Context, uri string, passPhrase strin
return ctx, nil
}
-func tcpClient(_url *url.URL) (Connection, error) {
+func tcpClient(_url *url.URL) Connection {
connection := Connection{
URI: _url,
}
@@ -147,7 +147,7 @@ func tcpClient(_url *url.URL) (Connection, error) {
DisableCompression: true,
},
}
- return connection, nil
+ return connection
}
// pingNewConnection pings to make sure the RESTFUL service is up
@@ -186,8 +186,7 @@ func pingNewConnection(ctx context.Context) error {
}
func sshClient(_url *url.URL, secure bool, passPhrase string, identities ...string) (Connection, error) {
- var authMethods []ssh.AuthMethod
-
+ authMethods := []ssh.AuthMethod{}
for _, i := range identities {
auth, err := publicKey(i, []byte(passPhrase))
if err != nil {
@@ -256,7 +255,7 @@ func sshClient(_url *url.URL, secure bool, passPhrase string, identities ...stri
return connection, nil
}
-func unixClient(_url *url.URL) (Connection, error) {
+func unixClient(_url *url.URL) Connection {
connection := Connection{URI: _url}
connection.Client = &http.Client{
Transport: &http.Transport{
@@ -266,7 +265,7 @@ func unixClient(_url *url.URL) (Connection, error) {
DisableCompression: true,
},
}
- return connection, nil
+ return connection
}
// DoRequest assembles the http request and returns the response
diff --git a/pkg/bindings/containers/checkpoint.go b/pkg/bindings/containers/checkpoint.go
index 916ec8071..8a3932e80 100644
--- a/pkg/bindings/containers/checkpoint.go
+++ b/pkg/bindings/containers/checkpoint.go
@@ -42,7 +42,7 @@ func Checkpoint(ctx context.Context, nameOrID string, keep, leaveRunning, tcpEst
}
// Restore restores a checkpointed container to running. The container is identified by the nameOrID option. All
-// additional options are optional and allow finer control of the restore processs.
+// additional options are optional and allow finer control of the restore process.
func Restore(ctx context.Context, nameOrID string, keep, tcpEstablished, ignoreRootFS, ignoreStaticIP, ignoreStaticMAC *bool, name, importArchive *string) (*entities.RestoreReport, error) {
var report entities.RestoreReport
conn, err := bindings.GetClient(ctx)
diff --git a/pkg/bindings/containers/types.go b/pkg/bindings/containers/types.go
index 31daaf565..f288c2944 100644
--- a/pkg/bindings/containers/types.go
+++ b/pkg/bindings/containers/types.go
@@ -12,7 +12,7 @@ type LogOptions struct {
Until *string
}
-// CommitOptions describe details about the resulting commited
+// CommitOptions describe details about the resulting committed
// image as defined by repo and tag. None of these options
// are required.
type CommitOptions struct {
diff --git a/pkg/bindings/images/images.go b/pkg/bindings/images/images.go
index a82a9080b..9cb6a0ac5 100644
--- a/pkg/bindings/images/images.go
+++ b/pkg/bindings/images/images.go
@@ -394,7 +394,7 @@ func Pull(ctx context.Context, rawImage string, options entities.ImagePullOption
}
// Push is the binding for libpod's v2 endpoints for push images. Note that
-// `source` must be a refering to an image in the remote's container storage.
+// `source` must be a referring to an image in the remote's container storage.
// The destination must be a reference to a registry (i.e., of docker transport
// or be normalized to one). Other transports are rejected as they do not make
// sense in a remote context.
diff --git a/pkg/cgroups/cgroups.go b/pkg/cgroups/cgroups.go
index 3b56f944f..399072108 100644
--- a/pkg/cgroups/cgroups.go
+++ b/pkg/cgroups/cgroups.go
@@ -133,7 +133,7 @@ func getAvailableControllers(exclude map[string]controllerHandler, cgroup2 bool)
if err != nil {
return nil, errors.Wrapf(err, "read directory %s", cgroupRoot)
}
- var controllers []controller
+ controllers := []controller{}
for _, i := range infos {
name := i.Name()
if _, found := exclude[name]; found {
@@ -505,7 +505,7 @@ func (c *CgroupControl) AddPid(pid int) error {
return nil
}
- var names []string
+ names := make([]string, 0, len(handlers))
for n := range handlers {
names = append(names, n)
}
diff --git a/pkg/cgroups/cpu.go b/pkg/cgroups/cpu.go
index 5f0a18031..3745c6e50 100644
--- a/pkg/cgroups/cpu.go
+++ b/pkg/cgroups/cpu.go
@@ -29,13 +29,12 @@ func readAcct(ctr *CgroupControl, name string) (uint64, error) {
}
func readAcctList(ctr *CgroupControl, name string) ([]uint64, error) {
- var r []uint64
-
p := filepath.Join(ctr.getCgroupv1Path(CPUAcct), name)
data, err := ioutil.ReadFile(p)
if err != nil {
return nil, errors.Wrapf(err, "reading %s", p)
}
+ r := []uint64{}
for _, s := range strings.Split(string(data), " ") {
s = cleanString(s)
if s == "" {
diff --git a/pkg/domain/entities/generate.go b/pkg/domain/entities/generate.go
index 68a42d897..a8ad13705 100644
--- a/pkg/domain/entities/generate.go
+++ b/pkg/domain/entities/generate.go
@@ -18,7 +18,7 @@ type GenerateSystemdOptions struct {
ContainerPrefix string
// PodPrefix - systemd unit name prefix for pods
PodPrefix string
- // Separator - systemd unit name seperator between name/id and prefix
+ // Separator - systemd unit name separator between name/id and prefix
Separator string
}
diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go
index a85333c75..fc76ddd41 100644
--- a/pkg/domain/entities/pods.go
+++ b/pkg/domain/entities/pods.go
@@ -103,15 +103,16 @@ type PodRmReport struct {
}
type PodCreateOptions struct {
- CGroupParent string
- Hostname string
- Infra bool
- InfraImage string
- InfraCommand string
- Labels map[string]string
- Name string
- Net *NetOptions
- Share []string
+ CGroupParent string
+ Hostname string
+ Infra bool
+ InfraImage string
+ InfraCommand string
+ InfraConmonPidFile string
+ Labels map[string]string
+ Name string
+ Net *NetOptions
+ Share []string
}
type PodCreateReport struct {
@@ -127,6 +128,9 @@ func (p PodCreateOptions) ToPodSpecGen(s *specgen.PodSpecGenerator) {
if len(p.InfraCommand) > 0 {
s.InfraCommand = strings.Split(p.InfraCommand, " ")
}
+ if len(p.InfraConmonPidFile) > 0 {
+ s.InfraConmonPidFile = p.InfraConmonPidFile
+ }
s.InfraImage = p.InfraImage
s.SharedNamespaces = p.Share
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 4d6d0d59a..d2c8aefdc 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -84,13 +84,11 @@ func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrID string)
}
func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []string, options entities.WaitOptions) ([]entities.WaitReport, error) {
- var (
- responses []entities.WaitReport
- )
ctrs, err := getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
if err != nil {
return nil, err
}
+ responses := make([]entities.WaitReport, 0, len(ctrs))
for _, c := range ctrs {
response := entities.WaitReport{Id: c.ID()}
exitCode, err := c.WaitForConditionWithInterval(options.Interval, options.Condition)
@@ -106,10 +104,9 @@ 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 (
- ctrs []*libpod.Container
- err error
- report []*entities.PauseUnpauseReport
+ err error
)
+ ctrs := []*libpod.Container{} //nolint
if options.All {
ctrs, err = ic.Libpod.GetAllContainers()
} else {
@@ -118,6 +115,7 @@ func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []stri
if err != nil {
return nil, err
}
+ report := make([]*entities.PauseUnpauseReport, 0, len(ctrs))
for _, c := range ctrs {
err := c.Pause()
report = append(report, &entities.PauseUnpauseReport{Id: c.ID(), Err: err})
@@ -127,10 +125,9 @@ 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 (
- ctrs []*libpod.Container
- err error
- report []*entities.PauseUnpauseReport
+ err error
)
+ ctrs := []*libpod.Container{} //nolint
if options.All {
ctrs, err = ic.Libpod.GetAllContainers()
} else {
@@ -139,6 +136,7 @@ func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []st
if err != nil {
return nil, err
}
+ report := make([]*entities.PauseUnpauseReport, 0, len(ctrs))
for _, c := range ctrs {
err := c.Unpause()
report = append(report, &entities.PauseUnpauseReport{Id: c.ID(), Err: err})
@@ -146,9 +144,6 @@ func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []st
return report, nil
}
func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []string, options entities.StopOptions) ([]*entities.StopReport, error) {
- var (
- reports []*entities.StopReport
- )
names := namesOrIds
for _, cidFile := range options.CIDFiles {
content, err := ioutil.ReadFile(cidFile)
@@ -184,6 +179,7 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
if err != nil {
return nil, err
}
+ reports := make([]*entities.StopReport, 0, len(errMap))
for ctr, err := range errMap {
report := new(entities.StopReport)
report.Id = ctr.ID()
@@ -204,10 +200,10 @@ func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.
filterFuncs = append(filterFuncs, generatedFunc)
}
}
- return ic.pruneContainersHelper(ctx, filterFuncs)
+ return ic.pruneContainersHelper(filterFuncs)
}
-func (ic *ContainerEngine) pruneContainersHelper(ctx context.Context, filterFuncs []libpod.ContainerFilter) (*entities.ContainerPruneReport, error) {
+func (ic *ContainerEngine) pruneContainersHelper(filterFuncs []libpod.ContainerFilter) (*entities.ContainerPruneReport, error) {
prunedContainers, pruneErrors, err := ic.Libpod.PruneContainers(filterFuncs)
if err != nil {
return nil, err
@@ -220,9 +216,6 @@ func (ic *ContainerEngine) pruneContainersHelper(ctx context.Context, filterFunc
}
func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) {
- var (
- reports []*entities.KillReport
- )
sig, err := signal.ParseSignalNameOrNumber(options.Signal)
if err != nil {
return nil, err
@@ -231,6 +224,7 @@ func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []strin
if err != nil {
return nil, err
}
+ reports := make([]*entities.KillReport, 0, len(ctrs))
for _, con := range ctrs {
reports = append(reports, &entities.KillReport{
Id: con.ID(),
@@ -241,9 +235,8 @@ func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []strin
}
func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []string, options entities.RestartOptions) ([]*entities.RestartReport, error) {
var (
- ctrs []*libpod.Container
- err error
- reports []*entities.RestartReport
+ ctrs []*libpod.Container
+ err error
)
if options.Running {
@@ -258,6 +251,7 @@ func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []st
}
}
+ reports := make([]*entities.RestartReport, 0, len(ctrs))
for _, con := range ctrs {
timeout := con.StopTimeout()
if options.Timeout != nil {
@@ -272,9 +266,7 @@ func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []st
}
func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, options entities.RmOptions) ([]*entities.RmReport, error) {
- var (
- reports []*entities.RmReport
- )
+ reports := []*entities.RmReport{}
if options.Storage {
for _, ctr := range namesOrIds {
report := entities.RmReport{Id: ctr}
@@ -347,11 +339,11 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string,
}
func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]*entities.ContainerInspectReport, error) {
- var reports []*entities.ContainerInspectReport
ctrs, err := getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
if err != nil {
return nil, err
}
+ reports := make([]*entities.ContainerInspectReport, 0, len(ctrs))
for _, c := range ctrs {
data, err := c.Inspect(options.Size)
if err != nil {
@@ -439,9 +431,8 @@ func (ic *ContainerEngine) ContainerExport(ctx context.Context, nameOrID string,
func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds []string, options entities.CheckpointOptions) ([]*entities.CheckpointReport, error) {
var (
- err error
- cons []*libpod.Container
- reports []*entities.CheckpointReport
+ err error
+ cons []*libpod.Container
)
checkOpts := libpod.ContainerCheckpointOptions{
Keep: options.Keep,
@@ -463,6 +454,7 @@ func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds [
if err != nil {
return nil, err
}
+ reports := make([]*entities.CheckpointReport, 0, len(cons))
for _, con := range cons {
err = con.Checkpoint(ctx, checkOpts)
reports = append(reports, &entities.CheckpointReport{
@@ -475,10 +467,8 @@ func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds [
func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []string, options entities.RestoreOptions) ([]*entities.RestoreReport, error) {
var (
- cons []*libpod.Container
- err error
- filterFuncs []libpod.ContainerFilter
- reports []*entities.RestoreReport
+ cons []*libpod.Container
+ err error
)
restoreOptions := libpod.ContainerCheckpointOptions{
@@ -491,10 +481,12 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st
IgnoreStaticMAC: options.IgnoreStaticMAC,
}
- filterFuncs = append(filterFuncs, func(c *libpod.Container) bool {
- state, _ := c.State()
- return state == define.ContainerStateExited
- })
+ filterFuncs := []libpod.ContainerFilter{
+ func(c *libpod.Container) bool {
+ state, _ := c.State()
+ return state == define.ContainerStateExited
+ },
+ }
switch {
case options.Import != "":
@@ -507,6 +499,7 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st
if err != nil {
return nil, err
}
+ reports := make([]*entities.RestoreReport, 0, len(cons))
for _, con := range cons {
err := con.Restore(ctx, restoreOptions)
reports = append(reports, &entities.RestoreReport{
@@ -565,34 +558,34 @@ func makeExecConfig(options entities.ExecOptions) *libpod.ExecConfig {
return execConfig
}
-func checkExecPreserveFDs(options entities.ExecOptions) (int, error) {
- ec := define.ExecErrorCodeGeneric
+func checkExecPreserveFDs(options entities.ExecOptions) error {
if options.PreserveFDs > 0 {
entries, err := ioutil.ReadDir("/proc/self/fd")
if err != nil {
- return ec, errors.Wrapf(err, "unable to read /proc/self/fd")
+ return errors.Wrapf(err, "unable to read /proc/self/fd")
}
m := make(map[int]bool)
for _, e := range entries {
i, err := strconv.Atoi(e.Name())
if err != nil {
- return ec, errors.Wrapf(err, "cannot parse %s in /proc/self/fd", e.Name())
+ return errors.Wrapf(err, "cannot parse %s in /proc/self/fd", e.Name())
}
m[i] = true
}
for i := 3; i < 3+int(options.PreserveFDs); i++ {
if _, found := m[i]; !found {
- return ec, errors.New("invalid --preserve-fds=N specified. Not enough FDs available")
+ return errors.New("invalid --preserve-fds=N specified. Not enough FDs available")
}
}
}
- return ec, nil
+ return nil
}
func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrID string, options entities.ExecOptions, streams define.AttachStreams) (int, error) {
- ec, err := checkExecPreserveFDs(options)
+ ec := define.ExecErrorCodeGeneric
+ err := checkExecPreserveFDs(options)
if err != nil {
return ec, err
}
@@ -609,7 +602,7 @@ func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrID string, o
}
func (ic *ContainerEngine) ContainerExecDetached(ctx context.Context, nameOrID string, options entities.ExecOptions) (string, error) {
- _, err := checkExecPreserveFDs(options)
+ err := checkExecPreserveFDs(options)
if err != nil {
return "", err
}
@@ -648,7 +641,7 @@ func (ic *ContainerEngine) ContainerExecDetached(ctx context.Context, nameOrID s
}
func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []string, options entities.ContainerStartOptions) ([]*entities.ContainerStartReport, error) {
- var reports []*entities.ContainerStartReport
+ reports := []*entities.ContainerStartReport{}
var exitCode = define.ExecErrorCodeGeneric
ctrs, rawInputs, err := getContainersAndInputByContext(false, options.Latest, namesOrIds, ic.Libpod)
if err != nil {
@@ -907,7 +900,7 @@ func (ic *ContainerEngine) ContainerLogs(ctx context.Context, containers []strin
}
func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []string, options entities.ContainerCleanupOptions) ([]*entities.ContainerCleanupReport, error) {
- var reports []*entities.ContainerCleanupReport
+ reports := []*entities.ContainerCleanupReport{}
ctrs, err := getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
if err != nil {
return nil, err
@@ -958,11 +951,11 @@ func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []st
}
func (ic *ContainerEngine) ContainerInit(ctx context.Context, namesOrIds []string, options entities.ContainerInitOptions) ([]*entities.ContainerInitReport, error) {
- var reports []*entities.ContainerInitReport
ctrs, err := getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
if err != nil {
return nil, err
}
+ reports := make([]*entities.ContainerInitReport, 0, len(ctrs))
for _, ctr := range ctrs {
report := entities.ContainerInitReport{Id: ctr.ID()}
err := ctr.Init(ctx)
@@ -993,11 +986,11 @@ func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIDs []strin
os.Exit(ret)
}
}
- var reports []*entities.ContainerMountReport
ctrs, err := getContainersByContext(options.All, options.Latest, nameOrIDs, ic.Libpod)
if err != nil {
return nil, err
}
+ reports := make([]*entities.ContainerMountReport, 0, len(ctrs))
for _, ctr := range ctrs {
report := entities.ContainerMountReport{Id: ctr.ID()}
report.Path, report.Err = ctr.Mount()
@@ -1030,11 +1023,11 @@ func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIDs []strin
}
func (ic *ContainerEngine) ContainerUnmount(ctx context.Context, nameOrIDs []string, options entities.ContainerUnmountOptions) ([]*entities.ContainerUnmountReport, error) {
- var reports []*entities.ContainerUnmountReport
ctrs, err := getContainersByContext(options.All, options.Latest, nameOrIDs, ic.Libpod)
if err != nil {
return nil, err
}
+ reports := []*entities.ContainerUnmountReport{}
for _, ctr := range ctrs {
state, err := ctr.State()
if err != nil {
@@ -1065,11 +1058,11 @@ func (ic *ContainerEngine) Config(_ context.Context) (*config.Config, error) {
}
func (ic *ContainerEngine) ContainerPort(ctx context.Context, nameOrID string, options entities.ContainerPortOptions) ([]*entities.ContainerPortReport, error) {
- var reports []*entities.ContainerPortReport
ctrs, err := getContainersByContext(options.All, options.Latest, []string{nameOrID}, ic.Libpod)
if err != nil {
return nil, err
}
+ reports := []*entities.ContainerPortReport{}
for _, con := range ctrs {
state, err := con.State()
if err != nil {
diff --git a/pkg/domain/infra/abi/containers_runlabel.go b/pkg/domain/infra/abi/containers_runlabel.go
index 41f4444d5..37422aac5 100644
--- a/pkg/domain/infra/abi/containers_runlabel.go
+++ b/pkg/domain/infra/abi/containers_runlabel.go
@@ -116,7 +116,7 @@ func generateRunlabelCommand(runlabel string, img *image.Image, args []string, o
err error
name, imageName string
globalOpts string
- cmd, env []string
+ cmd []string
)
// TODO: How do we get global opts as done in v1?
@@ -149,7 +149,7 @@ func generateRunlabelCommand(runlabel string, img *image.Image, args []string, o
return nil, nil, err
}
- env = generateRunEnvironment(name, imageName, options)
+ env := generateRunEnvironment(options)
env = append(env, "PODMAN_RUNLABEL_NESTED=1")
envmap, err := envLib.ParseSlice(env)
if err != nil {
@@ -185,9 +185,6 @@ func generateRunlabelCommand(runlabel string, img *image.Image, args []string, o
// generateCommand takes a label (string) and converts it to an executable command
func generateCommand(command, imageName, name, globalOpts string) ([]string, error) {
- var (
- newCommand []string
- )
if name == "" {
name = imageName
}
@@ -201,8 +198,7 @@ func generateCommand(command, imageName, name, globalOpts string) ([]string, err
if err != nil {
return nil, err
}
- newCommand = append(newCommand, prog)
-
+ newCommand := []string{prog}
for _, arg := range cmd[1:] {
var newArg string
switch arg {
@@ -234,7 +230,7 @@ func generateCommand(command, imageName, name, globalOpts string) ([]string, err
// GenerateRunEnvironment merges the current environment variables with optional
// environment variables provided by the user
-func generateRunEnvironment(name, imageName string, options entities.ContainerRunlabelOptions) []string {
+func generateRunEnvironment(options entities.ContainerRunlabelOptions) []string {
newEnv := os.Environ()
if options.Optional1 != "" {
newEnv = append(newEnv, fmt.Sprintf("OPT1=%s", options.Optional1))
diff --git a/pkg/domain/infra/abi/cp.go b/pkg/domain/infra/abi/cp.go
index 9fc1e3bee..7567d5a70 100644
--- a/pkg/domain/infra/abi/cp.go
+++ b/pkg/domain/infra/abi/cp.go
@@ -92,7 +92,7 @@ func (ic *ContainerEngine) ContainerCp(ctx context.Context, source, dest string,
if isFromHostToCtr {
if isVol, volDestName, volName := isVolumeDestName(destPath, ctr); isVol { //nolint(gocritic)
- path, err := pathWithVolumeMount(ctr, ic.Libpod, volDestName, volName, destPath)
+ path, err := pathWithVolumeMount(ic.Libpod, volDestName, volName, destPath)
if err != nil {
return nil, errors.Wrapf(err, "error getting destination path from volume %s", volDestName)
}
@@ -126,7 +126,7 @@ func (ic *ContainerEngine) ContainerCp(ctx context.Context, source, dest string,
} else {
destOwner = idtools.IDPair{UID: os.Getuid(), GID: os.Getgid()}
if isVol, volDestName, volName := isVolumeDestName(srcPath, ctr); isVol { //nolint(gocritic)
- path, err := pathWithVolumeMount(ctr, ic.Libpod, volDestName, volName, srcPath)
+ path, err := pathWithVolumeMount(ic.Libpod, volDestName, volName, srcPath)
if err != nil {
return nil, errors.Wrapf(err, "error getting source path from volume %s", volDestName)
}
@@ -384,7 +384,7 @@ func isVolumeDestName(path string, ctr *libpod.Container) (bool, string, string)
}
// if SRCPATH or DESTPATH is from volume mount's destination -v or --mount type=volume, generates the path with volume mount point
-func pathWithVolumeMount(ctr *libpod.Container, runtime *libpod.Runtime, volDestName, volName, path string) (string, error) {
+func pathWithVolumeMount(runtime *libpod.Runtime, volDestName, volName, path string) (string, error) {
destVolume, err := runtime.GetVolume(volName)
if err != nil {
return "", errors.Wrapf(err, "error getting volume destination %s", volName)
diff --git a/pkg/domain/infra/abi/generate.go b/pkg/domain/infra/abi/generate.go
index abb5e2911..8853303d5 100644
--- a/pkg/domain/infra/abi/generate.go
+++ b/pkg/domain/infra/abi/generate.go
@@ -4,7 +4,6 @@ import (
"bytes"
"context"
"fmt"
- "strings"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
@@ -16,165 +15,29 @@ import (
)
func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string, options entities.GenerateSystemdOptions) (*entities.GenerateSystemdReport, error) {
- opts := generate.Options{
- Files: options.Files,
- New: options.New,
- }
-
// First assume it's a container.
- if info, found, err := ic.generateSystemdgenContainerInfo(nameOrID, nil, options); found && err != nil {
- return nil, err
- } else if found && err == nil {
- output, err := generate.CreateContainerSystemdUnit(info, opts)
- if err != nil {
- return nil, err
+ ctr, ctrErr := ic.Libpod.LookupContainer(nameOrID)
+ if ctrErr == nil {
+ // Generate the unit for the container.
+ s, err := generate.ContainerUnit(ctr, options)
+ if err == nil {
+ return &entities.GenerateSystemdReport{Output: s}, nil
}
- return &entities.GenerateSystemdReport{Output: output}, nil
- }
-
- // --new does not support pods.
- if options.New {
- return nil, errors.Errorf("error generating systemd unit files: cannot generate generic files for a pod")
}
- // We're either having a pod or garbage.
+ // If it's not a container, we either have a pod or garbage.
pod, err := ic.Libpod.LookupPod(nameOrID)
if err != nil {
- return nil, err
- }
-
- // Error out if the pod has no infra container, which we require to be the
- // main service.
- if !pod.HasInfraContainer() {
- return nil, fmt.Errorf("error generating systemd unit files: Pod %q has no infra container", pod.Name())
+ err = errors.Wrap(ctrErr, err.Error())
+ return nil, errors.Wrapf(err, "%s does not refer to a container or pod", nameOrID)
}
- // Generate a systemdgen.ContainerInfo for the infra container. This
- // ContainerInfo acts as the main service of the pod.
- infraID, err := pod.InfraContainerID()
- if err != nil {
- return nil, nil
- }
- podInfo, _, err := ic.generateSystemdgenContainerInfo(infraID, pod, options)
+ // Generate the units for the pod and all its containers.
+ s, err := generate.PodUnits(pod, options)
if err != nil {
return nil, err
}
-
- // Compute the container-dependency graph for the Pod.
- containers, err := pod.AllContainers()
- if err != nil {
- return nil, err
- }
- if len(containers) == 0 {
- return nil, fmt.Errorf("error generating systemd unit files: Pod %q has no containers", pod.Name())
- }
- graph, err := libpod.BuildContainerGraph(containers)
- if err != nil {
- return nil, err
- }
-
- // Traverse the dependency graph and create systemdgen.ContainerInfo's for
- // each container.
- containerInfos := []*generate.ContainerInfo{podInfo}
- for ctr, dependencies := range graph.DependencyMap() {
- // Skip the infra container as we already generated it.
- if ctr.ID() == infraID {
- continue
- }
- ctrInfo, _, err := ic.generateSystemdgenContainerInfo(ctr.ID(), nil, options)
- if err != nil {
- return nil, err
- }
- // Now add the container's dependencies and at the container as a
- // required service of the infra container.
- for _, dep := range dependencies {
- if dep.ID() == infraID {
- ctrInfo.BoundToServices = append(ctrInfo.BoundToServices, podInfo.ServiceName)
- } else {
- _, serviceName := generateServiceName(dep, nil, options)
- ctrInfo.BoundToServices = append(ctrInfo.BoundToServices, serviceName)
- }
- }
- podInfo.RequiredServices = append(podInfo.RequiredServices, ctrInfo.ServiceName)
- containerInfos = append(containerInfos, ctrInfo)
- }
-
- // Now generate the systemd service for all containers.
- builder := strings.Builder{}
- for i, info := range containerInfos {
- if i > 0 {
- builder.WriteByte('\n')
- }
- out, err := generate.CreateContainerSystemdUnit(info, opts)
- if err != nil {
- return nil, err
- }
- builder.WriteString(out)
- }
-
- return &entities.GenerateSystemdReport{Output: builder.String()}, nil
-}
-
-// generateSystemdgenContainerInfo is a helper to generate a
-// systemdgen.ContainerInfo for `GenerateSystemd`.
-func (ic *ContainerEngine) generateSystemdgenContainerInfo(nameOrID string, pod *libpod.Pod, options entities.GenerateSystemdOptions) (*generate.ContainerInfo, bool, error) {
- ctr, err := ic.Libpod.LookupContainer(nameOrID)
- if err != nil {
- return nil, false, err
- }
-
- timeout := ctr.StopTimeout()
- if options.StopTimeout != nil {
- timeout = *options.StopTimeout
- }
-
- config := ctr.Config()
- conmonPidFile := config.ConmonPidFile
- if conmonPidFile == "" {
- return nil, true, errors.Errorf("conmon PID file path is empty, try to recreate the container with --conmon-pidfile flag")
- }
-
- createCommand := []string{}
- if config.CreateCommand != nil {
- createCommand = config.CreateCommand
- } else if options.New {
- return nil, true, errors.Errorf("cannot use --new on container %q: no create command found", nameOrID)
- }
-
- name, serviceName := generateServiceName(ctr, pod, options)
- info := &generate.ContainerInfo{
- ServiceName: serviceName,
- ContainerName: name,
- RestartPolicy: options.RestartPolicy,
- PIDFile: conmonPidFile,
- StopTimeout: timeout,
- GenerateTimestamp: true,
- CreateCommand: createCommand,
- }
-
- return info, true, nil
-}
-
-// generateServiceName generates the container name and the service name for systemd service.
-func generateServiceName(ctr *libpod.Container, pod *libpod.Pod, options entities.GenerateSystemdOptions) (string, string) {
- var kind, name, ctrName string
- if pod == nil {
- kind = options.ContainerPrefix //defaults to container
- name = ctr.ID()
- if options.Name {
- name = ctr.Name()
- }
- ctrName = name
- } else {
- kind = options.PodPrefix //defaults to pod
- name = pod.ID()
- ctrName = ctr.ID()
- if options.Name {
- name = pod.Name()
- ctrName = ctr.Name()
- }
- }
- return ctrName, fmt.Sprintf("%s%s%s", kind, options.Separator, name)
+ return &entities.GenerateSystemdReport{Output: s}, nil
}
func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrID string, options entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) {
diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go
index 67f331aac..e630d9bc8 100644
--- a/pkg/domain/infra/abi/images.go
+++ b/pkg/domain/infra/abi/images.go
@@ -167,7 +167,7 @@ func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entiti
return nil, errors.Wrapf(err, "error getting repository tags")
}
- var foundIDs []string
+ foundIDs := []string{}
for _, tag := range tags {
name := rawImage + ":" + tag
newImage, err := ir.Libpod.ImageRuntime().New(ctx, name, options.SignaturePolicy, options.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, util.PullImageAlways)
@@ -443,7 +443,7 @@ func removeErrorsToExitCode(rmErrors []error) int {
// container.
inUseErrors bool
// otherErrors indicates that at least one error other than the two
- // above occured.
+ // above occurred.
otherErrors bool
)
@@ -549,8 +549,7 @@ func (ir *ImageEngine) Remove(ctx context.Context, images []string, opts entitie
rmErrors = append(rmErrors, err)
}
}
-
- return
+ return //nolint
}
// Shutdown Libpod engine
diff --git a/pkg/domain/infra/abi/images_list.go b/pkg/domain/infra/abi/images_list.go
index 3034e36ec..98c041c15 100644
--- a/pkg/domain/infra/abi/images_list.go
+++ b/pkg/domain/infra/abi/images_list.go
@@ -8,17 +8,12 @@ import (
)
func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions) ([]*entities.ImageSummary, error) {
- var (
- images []*libpodImage.Image
- err error
- )
-
- images, err = ir.Libpod.ImageRuntime().GetImagesWithFilters(opts.Filter)
+ images, err := ir.Libpod.ImageRuntime().GetImagesWithFilters(opts.Filter)
if err != nil {
return nil, err
}
- var summaries []*entities.ImageSummary
+ summaries := []*entities.ImageSummary{}
for _, img := range images {
var repoTags []string
if opts.All {
diff --git a/pkg/domain/infra/abi/manifest.go b/pkg/domain/infra/abi/manifest.go
index a2b5fc0fc..a6f5bab6b 100644
--- a/pkg/domain/infra/abi/manifest.go
+++ b/pkg/domain/infra/abi/manifest.go
@@ -153,7 +153,7 @@ func (ir *ImageEngine) ManifestRemove(ctx context.Context, names []string) (stri
}
listImage, err := ir.Libpod.ImageRuntime().NewFromLocal(names[0])
if err != nil {
- return "", errors.Wrapf(err, "error retriving local image from image name %s", names[0])
+ return "", errors.Wrapf(err, "error retrieving local image from image name %s", names[0])
}
updatedListID, err := listImage.RemoveManifest(instanceDigest)
if err == nil {
@@ -166,7 +166,7 @@ func (ir *ImageEngine) ManifestRemove(ctx context.Context, names []string) (stri
func (ir *ImageEngine) ManifestPush(ctx context.Context, names []string, opts entities.ManifestPushOptions) error {
listImage, err := ir.Libpod.ImageRuntime().NewFromLocal(names[0])
if err != nil {
- return errors.Wrapf(err, "error retriving local image from image name %s", names[0])
+ return errors.Wrapf(err, "error retrieving local image from image name %s", names[0])
}
dest, err := alltransports.ParseImageName(names[1])
if err != nil {
diff --git a/pkg/domain/infra/abi/network.go b/pkg/domain/infra/abi/network.go
index 8e3515824..eba1af362 100644
--- a/pkg/domain/infra/abi/network.go
+++ b/pkg/domain/infra/abi/network.go
@@ -48,15 +48,12 @@ func (ic *ContainerEngine) NetworkList(ctx context.Context, options entities.Net
}
func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []string, options entities.NetworkInspectOptions) ([]entities.NetworkInspectReport, error) {
- var (
- rawCNINetworks []entities.NetworkInspectReport
- )
-
config, err := ic.Libpod.GetConfig()
if err != nil {
return nil, err
}
+ rawCNINetworks := make([]entities.NetworkInspectReport, 0, len(namesOrIds))
for _, name := range namesOrIds {
rawList, err := network.InspectNetwork(config, name)
if err != nil {
@@ -68,7 +65,7 @@ func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []stri
}
func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, options entities.NetworkRmOptions) ([]*entities.NetworkRmReport, error) {
- var reports []*entities.NetworkRmReport
+ reports := []*entities.NetworkRmReport{}
config, err := ic.Libpod.GetConfig()
if err != nil {
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
index f5b93c51b..7053cec9e 100644
--- a/pkg/domain/infra/abi/play.go
+++ b/pkg/domain/infra/abi/play.go
@@ -109,9 +109,7 @@ func (ic *ContainerEngine) playKubeDeployment(ctx context.Context, deploymentYAM
func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
var (
- containers []*libpod.Container
pod *libpod.Pod
- podOptions []libpod.PodCreateOption
registryCreds *types.DockerAuthConfig
writer io.Writer
playKubePod entities.PlayKubePod
@@ -130,8 +128,10 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
}
}
- podOptions = append(podOptions, libpod.WithInfraContainer())
- podOptions = append(podOptions, libpod.WithPodName(podName))
+ podOptions := []libpod.PodCreateOption{
+ libpod.WithInfraContainer(),
+ libpod.WithPodName(podName),
+ }
// TODO for now we just used the default kernel namespaces; we need to add/subtract this from yaml
hostname := podYAML.Spec.Hostname
@@ -271,6 +271,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
return nil, err
}
+ containers := make([]*libpod.Container, 0, len(podYAML.Spec.Containers))
for _, container := range podYAML.Spec.Containers {
pullPolicy := util.PullImageMissing
if len(container.ImagePullPolicy) > 0 {
@@ -293,7 +294,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
if err != nil {
return nil, err
}
- conf, err := kubeContainerToCreateConfig(ctx, container, ic.Libpod, newImage, namespaces, volumes, pod.ID(), podName, podInfraID, seccompPaths)
+ conf, err := kubeContainerToCreateConfig(ctx, container, newImage, namespaces, volumes, pod.ID(), podName, podInfraID, seccompPaths)
if err != nil {
return nil, err
}
@@ -407,7 +408,7 @@ func setupSecurityContext(securityConfig *createconfig.SecurityConfig, userConfi
}
// kubeContainerToCreateConfig takes a v1.Container and returns a createconfig describing a container
-func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container, runtime *libpod.Runtime, newImage *image.Image, namespaces map[string]string, volumes map[string]string, podID, podName, infraID string, seccompPaths *kubeSeccompPaths) (*createconfig.CreateConfig, error) {
+func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container, newImage *image.Image, namespaces map[string]string, volumes map[string]string, podID, podName, infraID string, seccompPaths *kubeSeccompPaths) (*createconfig.CreateConfig, error) {
var (
containerConfig createconfig.CreateConfig
pidConfig createconfig.PidConfig
diff --git a/pkg/domain/infra/abi/pods.go b/pkg/domain/infra/abi/pods.go
index eb6f1e191..4a122f54d 100644
--- a/pkg/domain/infra/abi/pods.go
+++ b/pkg/domain/infra/abi/pods.go
@@ -54,9 +54,7 @@ func (ic *ContainerEngine) PodExists(ctx context.Context, nameOrID string) (*ent
}
func (ic *ContainerEngine) PodKill(ctx context.Context, namesOrIds []string, options entities.PodKillOptions) ([]*entities.PodKillReport, error) {
- var (
- reports []*entities.PodKillReport
- )
+ reports := []*entities.PodKillReport{}
sig, err := signal.ParseSignalNameOrNumber(options.Signal)
if err != nil {
return nil, err
@@ -87,9 +85,7 @@ func (ic *ContainerEngine) PodKill(ctx context.Context, namesOrIds []string, opt
}
func (ic *ContainerEngine) PodPause(ctx context.Context, namesOrIds []string, options entities.PodPauseOptions) ([]*entities.PodPauseReport, error) {
- var (
- reports []*entities.PodPauseReport
- )
+ reports := []*entities.PodPauseReport{}
pods, err := getPodsByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
if err != nil {
return nil, err
@@ -114,9 +110,7 @@ func (ic *ContainerEngine) PodPause(ctx context.Context, namesOrIds []string, op
}
func (ic *ContainerEngine) PodUnpause(ctx context.Context, namesOrIds []string, options entities.PodunpauseOptions) ([]*entities.PodUnpauseReport, error) {
- var (
- reports []*entities.PodUnpauseReport
- )
+ reports := []*entities.PodUnpauseReport{}
pods, err := getPodsByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
if err != nil {
return nil, err
@@ -141,9 +135,7 @@ func (ic *ContainerEngine) PodUnpause(ctx context.Context, namesOrIds []string,
}
func (ic *ContainerEngine) PodStop(ctx context.Context, namesOrIds []string, options entities.PodStopOptions) ([]*entities.PodStopReport, error) {
- var (
- reports []*entities.PodStopReport
- )
+ reports := []*entities.PodStopReport{}
pods, err := getPodsByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchPod) {
return nil, err
@@ -168,9 +160,7 @@ func (ic *ContainerEngine) PodStop(ctx context.Context, namesOrIds []string, opt
}
func (ic *ContainerEngine) PodRestart(ctx context.Context, namesOrIds []string, options entities.PodRestartOptions) ([]*entities.PodRestartReport, error) {
- var (
- reports []*entities.PodRestartReport
- )
+ reports := []*entities.PodRestartReport{}
pods, err := getPodsByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
if err != nil {
return nil, err
@@ -196,13 +186,12 @@ func (ic *ContainerEngine) PodRestart(ctx context.Context, namesOrIds []string,
}
func (ic *ContainerEngine) PodStart(ctx context.Context, namesOrIds []string, options entities.PodStartOptions) ([]*entities.PodStartReport, error) {
- var (
- reports []*entities.PodStartReport
- )
+ reports := []*entities.PodStartReport{}
pods, err := getPodsByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
if err != nil {
return nil, err
}
+
for _, p := range pods {
report := entities.PodStartReport{Id: p.ID()}
errs, err := p.Start(ctx)
@@ -224,13 +213,11 @@ func (ic *ContainerEngine) PodStart(ctx context.Context, namesOrIds []string, op
}
func (ic *ContainerEngine) PodRm(ctx context.Context, namesOrIds []string, options entities.PodRmOptions) ([]*entities.PodRmReport, error) {
- var (
- reports []*entities.PodRmReport
- )
pods, err := getPodsByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchPod) {
return nil, err
}
+ reports := make([]*entities.PodRmReport, 0, len(pods))
for _, p := range pods {
report := entities.PodRmReport{Id: p.ID()}
err := ic.Libpod.RemovePod(ctx, p, true, options.Force)
@@ -247,13 +234,11 @@ func (ic *ContainerEngine) PodPrune(ctx context.Context, options entities.PodPru
}
func (ic *ContainerEngine) prunePodHelper(ctx context.Context) ([]*entities.PodPruneReport, error) {
- var (
- reports []*entities.PodPruneReport
- )
response, err := ic.Libpod.PrunePods(ctx)
if err != nil {
return nil, err
}
+ reports := make([]*entities.PodPruneReport, 0, len(response))
for k, v := range response {
reports = append(reports, &entities.PodPruneReport{
Err: v,
@@ -298,9 +283,8 @@ func (ic *ContainerEngine) PodTop(ctx context.Context, options entities.PodTopOp
func (ic *ContainerEngine) PodPs(ctx context.Context, options entities.PodPSOptions) ([]*entities.ListPodsReport, error) {
var (
err error
- filters []libpod.PodFilter
- pds []*libpod.Pod
- reports []*entities.ListPodsReport
+ filters = []libpod.PodFilter{}
+ pds = []*libpod.Pod{}
)
for k, v := range options.Filters {
@@ -326,6 +310,7 @@ func (ic *ContainerEngine) PodPs(ctx context.Context, options entities.PodPSOpti
}
}
+ reports := make([]*entities.ListPodsReport, 0, len(pds))
for _, p := range pds {
var lpcs []*entities.ListPodContainer
status, err := p.GetPodStatus()
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index 33ba58558..90002326e 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -172,7 +172,7 @@ func checkInput() error { // nolint:deadcode,unused
return nil
}
-// SystemPrune removes unsed data from the system. Pruning pods, containers, volumes and images.
+// 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)
podPruneReport, err := ic.prunePodHelper(ctx)
@@ -181,7 +181,7 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys
}
systemPruneReport.PodPruneReport = podPruneReport
- containerPruneReport, err := ic.pruneContainersHelper(ctx, nil)
+ containerPruneReport, err := ic.pruneContainersHelper(nil)
if err != nil {
return nil, err
}
@@ -212,10 +212,7 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys
func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.SystemDfOptions) (*entities.SystemDfReport, error) {
var (
- dfImages []*entities.SystemDfImageReport
- dfContainers []*entities.SystemDfContainerReport
- dfVolumes []*entities.SystemDfVolumeReport
- runningContainers []string
+ dfImages = []*entities.SystemDfImageReport{}
)
// Get Images and iterate them
@@ -282,6 +279,7 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System
if err != nil {
return nil, err
}
+ dfContainers := make([]*entities.SystemDfContainerReport, 0, len(cons))
for _, c := range cons {
iid, _ := c.Image()
conSize, err := c.RootFsSize()
@@ -320,10 +318,12 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System
if err != nil {
return nil, err
}
+ runningContainers := make([]string, 0, len(running))
for _, c := range running {
runningContainers = append(runningContainers, c.ID())
}
+ dfVolumes := make([]*entities.SystemDfVolumeReport, 0, len(vols))
for _, v := range vols {
var consInUse int
volSize, err := sizeOfPath(v.MountPoint())
diff --git a/pkg/domain/infra/abi/volumes.go b/pkg/domain/infra/abi/volumes.go
index a311e0c4e..702e11003 100644
--- a/pkg/domain/infra/abi/volumes.go
+++ b/pkg/domain/infra/abi/volumes.go
@@ -40,9 +40,10 @@ func (ic *ContainerEngine) VolumeCreate(ctx context.Context, opts entities.Volum
func (ic *ContainerEngine) VolumeRm(ctx context.Context, namesOrIds []string, opts entities.VolumeRmOptions) ([]*entities.VolumeRmReport, error) {
var (
err error
- reports []*entities.VolumeRmReport
vols []*libpod.Volume
+ reports = []*entities.VolumeRmReport{}
)
+
if opts.All {
vols, err = ic.Libpod.Volumes()
if err != nil {
@@ -72,9 +73,8 @@ func (ic *ContainerEngine) VolumeRm(ctx context.Context, namesOrIds []string, op
func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []string, opts entities.VolumeInspectOptions) ([]*entities.VolumeInspectReport, error) {
var (
- err error
- reports []*entities.VolumeInspectReport
- vols []*libpod.Volume
+ err error
+ vols []*libpod.Volume
)
// Note: as with previous implementation, a single failure here
@@ -93,6 +93,7 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
vols = append(vols, vol)
}
}
+ reports := make([]*entities.VolumeInspectReport, 0, len(vols))
for _, v := range vols {
config := entities.VolumeConfigResponse{
Name: v.Name(),
@@ -115,13 +116,11 @@ func (ic *ContainerEngine) VolumePrune(ctx context.Context, opts entities.Volume
}
func (ic *ContainerEngine) pruneVolumesHelper(ctx context.Context) ([]*entities.VolumePruneReport, error) {
- var (
- reports []*entities.VolumePruneReport
- )
pruned, err := ic.Libpod.PruneVolumes(ctx)
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,
@@ -132,9 +131,6 @@ func (ic *ContainerEngine) pruneVolumesHelper(ctx context.Context) ([]*entities.
}
func (ic *ContainerEngine) VolumeList(ctx context.Context, opts entities.VolumeListOptions) ([]*entities.VolumeListReport, error) {
- var (
- reports []*entities.VolumeListReport
- )
volumeFilters, err := filters.GenerateVolumeFilters(opts.Filter)
if err != nil {
return nil, err
@@ -143,6 +139,7 @@ func (ic *ContainerEngine) VolumeList(ctx context.Context, opts entities.VolumeL
if err != nil {
return nil, err
}
+ reports := make([]*entities.VolumeListReport, 0, len(vols))
for _, v := range vols {
config := entities.VolumeConfigResponse{
Name: v.Name(),
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index 68a8b0329..4bd813847 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -32,13 +32,11 @@ func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrID string)
}
func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []string, options entities.WaitOptions) ([]entities.WaitReport, error) {
- var (
- responses []entities.WaitReport
- )
cons, err := getContainersByContext(ic.ClientCxt, false, namesOrIds)
if err != nil {
return nil, err
}
+ responses := make([]entities.WaitReport, 0, len(cons))
for _, c := range cons {
response := entities.WaitReport{Id: c.ID}
exitCode, err := containers.Wait(ic.ClientCxt, c.ID, &options.Condition)
@@ -53,13 +51,11 @@ 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 (
- reports []*entities.PauseUnpauseReport
- )
ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds)
if err != nil {
return nil, err
}
+ reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs))
for _, c := range ctrs {
err := containers.Pause(ic.ClientCxt, c.ID)
reports = append(reports, &entities.PauseUnpauseReport{Id: c.ID, Err: err})
@@ -68,13 +64,11 @@ 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 (
- reports []*entities.PauseUnpauseReport
- )
ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds)
if err != nil {
return nil, err
}
+ reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs))
for _, c := range ctrs {
err := containers.Unpause(ic.ClientCxt, c.ID)
reports = append(reports, &entities.PauseUnpauseReport{Id: c.ID, Err: err})
@@ -83,9 +77,7 @@ func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []st
}
func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []string, options entities.StopOptions) ([]*entities.StopReport, error) {
- var (
- reports []*entities.StopReport
- )
+ reports := []*entities.StopReport{}
for _, cidFile := range options.CIDFiles {
content, err := ioutil.ReadFile(cidFile)
if err != nil {
@@ -125,13 +117,11 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
}
func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) {
- var (
- reports []*entities.KillReport
- )
ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds)
if err != nil {
return nil, err
}
+ reports := make([]*entities.KillReport, 0, len(ctrs))
for _, c := range ctrs {
reports = append(reports, &entities.KillReport{
Id: c.ID,
@@ -143,7 +133,7 @@ func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []strin
func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []string, options entities.RestartOptions) ([]*entities.RestartReport, error) {
var (
- reports []*entities.RestartReport
+ reports = []*entities.RestartReport{}
timeout *int
)
if options.Timeout != nil {
@@ -168,9 +158,6 @@ func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []st
}
func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, options entities.RmOptions) ([]*entities.RmReport, error) {
- var (
- reports []*entities.RmReport
- )
for _, cidFile := range options.CIDFiles {
content, err := ioutil.ReadFile(cidFile)
if err != nil {
@@ -184,6 +171,7 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string,
return nil, err
}
// TODO there is no endpoint for container eviction. Need to discuss
+ reports := make([]*entities.RmReport, 0, len(ctrs))
for _, c := range ctrs {
reports = append(reports, &entities.RmReport{
Id: c.ID,
@@ -198,13 +186,11 @@ func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.
}
func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]*entities.ContainerInspectReport, error) {
- var (
- reports []*entities.ContainerInspectReport
- )
ctrs, err := getContainersByContext(ic.ClientCxt, false, namesOrIds)
if err != nil {
return nil, err
}
+ reports := make([]*entities.ContainerInspectReport, 0, len(ctrs))
for _, con := range ctrs {
data, err := containers.Inspect(ic.ClientCxt, con.ID, &options.Size)
if err != nil {
@@ -282,9 +268,8 @@ func (ic *ContainerEngine) ContainerExport(ctx context.Context, nameOrID string,
func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds []string, options entities.CheckpointOptions) ([]*entities.CheckpointReport, error) {
var (
- reports []*entities.CheckpointReport
- err error
- ctrs []entities.ListContainer
+ err error
+ ctrs = []entities.ListContainer{}
)
if options.All {
@@ -305,6 +290,7 @@ func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds [
return nil, err
}
}
+ reports := make([]*entities.CheckpointReport, 0, len(ctrs))
for _, c := range ctrs {
report, err := containers.Checkpoint(ic.ClientCxt, c.ID, &options.Keep, &options.LeaveRunning, &options.TCPEstablished, &options.IgnoreRootFS, &options.Export)
if err != nil {
@@ -317,9 +303,8 @@ func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds [
func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []string, options entities.RestoreOptions) ([]*entities.RestoreReport, error) {
var (
- reports []*entities.RestoreReport
- err error
- ctrs []entities.ListContainer
+ err error
+ ctrs = []entities.ListContainer{}
)
if options.All {
allCtrs, err := getContainersByContext(ic.ClientCxt, true, []string{})
@@ -339,6 +324,7 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st
return nil, err
}
}
+ reports := make([]*entities.RestoreReport, 0, len(ctrs))
for _, c := range ctrs {
report, err := containers.Restore(ic.ClientCxt, c.ID, &options.Keep, &options.TCPEstablished, &options.IgnoreRootFS, &options.IgnoreStaticIP, &options.IgnoreStaticMAC, &options.Name, &options.Import)
if err != nil {
@@ -467,7 +453,7 @@ func startAndAttach(ic *ContainerEngine, name string, detachKeys *string, input,
}
func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []string, options entities.ContainerStartOptions) ([]*entities.ContainerStartReport, error) {
- var reports []*entities.ContainerStartReport
+ reports := []*entities.ContainerStartReport{}
for _, name := range namesOrIds {
report := entities.ContainerStartReport{
Id: name,
@@ -535,11 +521,11 @@ func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []st
}
func (ic *ContainerEngine) ContainerInit(ctx context.Context, namesOrIds []string, options entities.ContainerInitOptions) ([]*entities.ContainerInitReport, error) {
- var reports []*entities.ContainerInitReport
ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds)
if err != nil {
return nil, err
}
+ reports := make([]*entities.ContainerInitReport, 0, len(ctrs))
for _, ctr := range ctrs {
err := containers.ContainerInit(ic.ClientCxt, ctr.ID)
// When using all, it is NOT considered an error if a container
@@ -569,8 +555,8 @@ func (ic *ContainerEngine) Config(_ context.Context) (*config.Config, error) {
func (ic *ContainerEngine) ContainerPort(ctx context.Context, nameOrID string, options entities.ContainerPortOptions) ([]*entities.ContainerPortReport, error) {
var (
- reports []*entities.ContainerPortReport
- namesOrIds []string
+ reports = []*entities.ContainerPortReport{}
+ namesOrIds = []string{}
)
if len(nameOrID) > 0 {
namesOrIds = append(namesOrIds, nameOrID)
diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go
index fc7ac0aa8..ec2c53c4f 100644
--- a/pkg/domain/infra/tunnel/images.go
+++ b/pkg/domain/infra/tunnel/images.go
@@ -39,7 +39,7 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions)
return nil, err
}
- is := make([]*entities.ImageSummary, len(images))
+ is := make([]*entities.ImageSummary, 0, len(images))
for i, img := range images {
hold := entities.ImageSummary{}
if err := utils.DeepCopy(&hold, img); err != nil {
diff --git a/pkg/domain/infra/tunnel/network.go b/pkg/domain/infra/tunnel/network.go
index 7725d8257..e7cc5fb26 100644
--- a/pkg/domain/infra/tunnel/network.go
+++ b/pkg/domain/infra/tunnel/network.go
@@ -12,7 +12,7 @@ func (ic *ContainerEngine) NetworkList(ctx context.Context, options entities.Net
}
func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []string, options entities.NetworkInspectOptions) ([]entities.NetworkInspectReport, error) {
- var reports []entities.NetworkInspectReport
+ reports := make([]entities.NetworkInspectReport, 0, len(namesOrIds))
for _, name := range namesOrIds {
report, err := network.Inspect(ic.ClientCxt, name)
if err != nil {
@@ -24,7 +24,7 @@ func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []stri
}
func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, options entities.NetworkRmOptions) ([]*entities.NetworkRmReport, error) {
- var reports []*entities.NetworkRmReport
+ reports := make([]*entities.NetworkRmReport, 0, len(namesOrIds))
for _, name := range namesOrIds {
report, err := network.Remove(ic.ClientCxt, name, &options.Force)
if err != nil {
diff --git a/pkg/domain/infra/tunnel/pods.go b/pkg/domain/infra/tunnel/pods.go
index 5ca4a6a80..d18e9937c 100644
--- a/pkg/domain/infra/tunnel/pods.go
+++ b/pkg/domain/infra/tunnel/pods.go
@@ -17,10 +17,6 @@ func (ic *ContainerEngine) PodExists(ctx context.Context, nameOrID string) (*ent
}
func (ic *ContainerEngine) PodKill(ctx context.Context, namesOrIds []string, options entities.PodKillOptions) ([]*entities.PodKillReport, error) {
- var (
- reports []*entities.PodKillReport
- )
-
_, err := util.ParseSignal(options.Signal)
if err != nil {
return nil, err
@@ -30,6 +26,7 @@ func (ic *ContainerEngine) PodKill(ctx context.Context, namesOrIds []string, opt
if err != nil {
return nil, err
}
+ reports := make([]*entities.PodKillReport, 0, len(foundPods))
for _, p := range foundPods {
response, err := pods.Kill(ic.ClientCxt, p.Id, &options.Signal)
if err != nil {
@@ -46,13 +43,11 @@ func (ic *ContainerEngine) PodKill(ctx context.Context, namesOrIds []string, opt
}
func (ic *ContainerEngine) PodPause(ctx context.Context, namesOrIds []string, options entities.PodPauseOptions) ([]*entities.PodPauseReport, error) {
- var (
- reports []*entities.PodPauseReport
- )
foundPods, err := getPodsByContext(ic.ClientCxt, options.All, namesOrIds)
if err != nil {
return nil, err
}
+ reports := make([]*entities.PodPauseReport, 0, len(foundPods))
for _, p := range foundPods {
response, err := pods.Pause(ic.ClientCxt, p.Id)
if err != nil {
@@ -69,13 +64,11 @@ func (ic *ContainerEngine) PodPause(ctx context.Context, namesOrIds []string, op
}
func (ic *ContainerEngine) PodUnpause(ctx context.Context, namesOrIds []string, options entities.PodunpauseOptions) ([]*entities.PodUnpauseReport, error) {
- var (
- reports []*entities.PodUnpauseReport
- )
foundPods, err := getPodsByContext(ic.ClientCxt, options.All, namesOrIds)
if err != nil {
return nil, err
}
+ reports := make([]*entities.PodUnpauseReport, 0, len(foundPods))
for _, p := range foundPods {
response, err := pods.Unpause(ic.ClientCxt, p.Id)
if err != nil {
@@ -92,10 +85,7 @@ func (ic *ContainerEngine) PodUnpause(ctx context.Context, namesOrIds []string,
}
func (ic *ContainerEngine) PodStop(ctx context.Context, namesOrIds []string, options entities.PodStopOptions) ([]*entities.PodStopReport, error) {
- var (
- reports []*entities.PodStopReport
- timeout = -1
- )
+ timeout := -1
foundPods, err := getPodsByContext(ic.ClientCxt, options.All, namesOrIds)
if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchPod) {
return nil, err
@@ -103,6 +93,7 @@ func (ic *ContainerEngine) PodStop(ctx context.Context, namesOrIds []string, opt
if options.Timeout != -1 {
timeout = options.Timeout
}
+ reports := make([]*entities.PodStopReport, 0, len(foundPods))
for _, p := range foundPods {
response, err := pods.Stop(ic.ClientCxt, p.Id, &timeout)
if err != nil {
@@ -119,11 +110,11 @@ func (ic *ContainerEngine) PodStop(ctx context.Context, namesOrIds []string, opt
}
func (ic *ContainerEngine) PodRestart(ctx context.Context, namesOrIds []string, options entities.PodRestartOptions) ([]*entities.PodRestartReport, error) {
- var reports []*entities.PodRestartReport
foundPods, err := getPodsByContext(ic.ClientCxt, options.All, namesOrIds)
if err != nil {
return nil, err
}
+ reports := make([]*entities.PodRestartReport, 0, len(foundPods))
for _, p := range foundPods {
response, err := pods.Restart(ic.ClientCxt, p.Id)
if err != nil {
@@ -140,11 +131,11 @@ func (ic *ContainerEngine) PodRestart(ctx context.Context, namesOrIds []string,
}
func (ic *ContainerEngine) PodStart(ctx context.Context, namesOrIds []string, options entities.PodStartOptions) ([]*entities.PodStartReport, error) {
- var reports []*entities.PodStartReport
foundPods, err := getPodsByContext(ic.ClientCxt, options.All, namesOrIds)
if err != nil {
return nil, err
}
+ reports := make([]*entities.PodStartReport, 0, len(foundPods))
for _, p := range foundPods {
response, err := pods.Start(ic.ClientCxt, p.Id)
if err != nil {
@@ -161,11 +152,11 @@ func (ic *ContainerEngine) PodStart(ctx context.Context, namesOrIds []string, op
}
func (ic *ContainerEngine) PodRm(ctx context.Context, namesOrIds []string, options entities.PodRmOptions) ([]*entities.PodRmReport, error) {
- var reports []*entities.PodRmReport
foundPods, err := getPodsByContext(ic.ClientCxt, options.All, namesOrIds)
if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchPod) {
return nil, err
}
+ reports := make([]*entities.PodRmReport, 0, len(foundPods))
for _, p := range foundPods {
response, err := pods.Remove(ic.ClientCxt, p.Id, &options.Force)
if err != nil {
diff --git a/pkg/domain/infra/tunnel/volumes.go b/pkg/domain/infra/tunnel/volumes.go
index 5b65c66ea..af7273ac4 100644
--- a/pkg/domain/infra/tunnel/volumes.go
+++ b/pkg/domain/infra/tunnel/volumes.go
@@ -16,10 +16,6 @@ func (ic *ContainerEngine) VolumeCreate(ctx context.Context, opts entities.Volum
}
func (ic *ContainerEngine) VolumeRm(ctx context.Context, namesOrIds []string, opts entities.VolumeRmOptions) ([]*entities.VolumeRmReport, error) {
- var (
- reports []*entities.VolumeRmReport
- )
-
if opts.All {
vols, err := volumes.List(ic.ClientCxt, nil)
if err != nil {
@@ -29,6 +25,7 @@ func (ic *ContainerEngine) VolumeRm(ctx context.Context, namesOrIds []string, op
namesOrIds = append(namesOrIds, v.Name)
}
}
+ reports := make([]*entities.VolumeRmReport, 0, len(namesOrIds))
for _, id := range namesOrIds {
reports = append(reports, &entities.VolumeRmReport{
Err: volumes.Remove(ic.ClientCxt, id, &opts.Force),
@@ -39,9 +36,6 @@ func (ic *ContainerEngine) VolumeRm(ctx context.Context, namesOrIds []string, op
}
func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []string, opts entities.VolumeInspectOptions) ([]*entities.VolumeInspectReport, error) {
- var (
- reports []*entities.VolumeInspectReport
- )
if opts.All {
vols, err := volumes.List(ic.ClientCxt, nil)
if err != nil {
@@ -51,6 +45,7 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
namesOrIds = append(namesOrIds, v.Name)
}
}
+ reports := make([]*entities.VolumeInspectReport, 0, len(namesOrIds))
for _, id := range namesOrIds {
data, err := volumes.Inspect(ic.ClientCxt, id)
if err != nil {
diff --git a/pkg/hooks/exec/runtimeconfigfilter_test.go b/pkg/hooks/exec/runtimeconfigfilter_test.go
index 48dd2f998..f4b6cf86a 100644
--- a/pkg/hooks/exec/runtimeconfigfilter_test.go
+++ b/pkg/hooks/exec/runtimeconfigfilter_test.go
@@ -12,21 +12,11 @@ import (
"github.com/stretchr/testify/assert"
)
-func pointerInt(value int) *int {
- return &value
-}
-
-func pointerUInt32(value uint32) *uint32 {
- return &value
-}
-
-func pointerFileMode(value os.FileMode) *os.FileMode {
- return &value
-}
-
func TestRuntimeConfigFilter(t *testing.T) {
unexpectedEndOfJSONInput := json.Unmarshal([]byte("{\n"), nil) //nolint
-
+ fileMode := os.FileMode(0600)
+ rootUint32 := uint32(0)
+ binUser := int(1)
for _, tt := range []struct {
name string
contextTimeout time.Duration
@@ -77,9 +67,9 @@ func TestRuntimeConfigFilter(t *testing.T) {
Type: "c",
Major: 10,
Minor: 229,
- FileMode: pointerFileMode(0600),
- UID: pointerUInt32(0),
- GID: pointerUInt32(0),
+ FileMode: &fileMode,
+ UID: &rootUint32,
+ GID: &rootUint32,
},
},
},
@@ -96,18 +86,18 @@ func TestRuntimeConfigFilter(t *testing.T) {
Type: "c",
Major: 10,
Minor: 229,
- FileMode: pointerFileMode(0600),
- UID: pointerUInt32(0),
- GID: pointerUInt32(0),
+ FileMode: &fileMode,
+ UID: &rootUint32,
+ GID: &rootUint32,
},
{
Path: "/dev/sda",
Type: "b",
Major: 8,
Minor: 0,
- FileMode: pointerFileMode(0600),
- UID: pointerUInt32(0),
- GID: pointerUInt32(0),
+ FileMode: &fileMode,
+ UID: &rootUint32,
+ GID: &rootUint32,
},
},
},
@@ -137,9 +127,9 @@ func TestRuntimeConfigFilter(t *testing.T) {
Type: "c",
Major: 10,
Minor: 229,
- FileMode: pointerFileMode(0600),
- UID: pointerUInt32(0),
- GID: pointerUInt32(0),
+ FileMode: &fileMode,
+ UID: &rootUint32,
+ GID: &rootUint32,
},
},
},
@@ -156,18 +146,18 @@ func TestRuntimeConfigFilter(t *testing.T) {
Type: "c",
Major: 10,
Minor: 229,
- FileMode: pointerFileMode(0600),
- UID: pointerUInt32(0),
- GID: pointerUInt32(0),
+ FileMode: &fileMode,
+ UID: &rootUint32,
+ GID: &rootUint32,
},
{
Path: "/dev/sdb",
Type: "b",
Major: 8,
Minor: 0,
- FileMode: pointerFileMode(0600),
- UID: pointerUInt32(0),
- GID: pointerUInt32(0),
+ FileMode: &fileMode,
+ UID: &rootUint32,
+ GID: &rootUint32,
},
},
},
@@ -203,7 +193,7 @@ func TestRuntimeConfigFilter(t *testing.T) {
{
Path: path,
Args: []string{"sh", "-c", "sleep 2"},
- Timeout: pointerInt(1),
+ Timeout: &binUser,
},
},
input: &spec.Spec{
diff --git a/pkg/lookup/lookup.go b/pkg/lookup/lookup.go
index dff25f74f..8f241edf2 100644
--- a/pkg/lookup/lookup.go
+++ b/pkg/lookup/lookup.go
@@ -79,7 +79,6 @@ func GetContainerGroups(groups []string, containerMount string, override *Overri
var (
groupDest string
err error
- uintgids []uint32
)
groupPath := etcgroup
@@ -96,6 +95,7 @@ func GetContainerGroups(groups []string, containerMount string, override *Overri
if err != nil {
return nil, err
}
+ uintgids := make([]uint32, 0, len(gids))
// For libpod, we want []uint32s
for _, gid := range gids {
uintgids = append(uintgids, uint32(gid))
diff --git a/pkg/network/files.go b/pkg/network/files.go
index 81c0e1a28..beb3289f3 100644
--- a/pkg/network/files.go
+++ b/pkg/network/files.go
@@ -22,13 +22,13 @@ func GetCNIConfDir(config *config.Config) string {
// LoadCNIConfsFromDir loads all the CNI configurations from a dir
func LoadCNIConfsFromDir(dir string) ([]*libcni.NetworkConfigList, error) {
- var configs []*libcni.NetworkConfigList
files, err := libcni.ConfFiles(dir, []string{".conflist"})
if err != nil {
return nil, err
}
sort.Strings(files)
+ configs := make([]*libcni.NetworkConfigList, 0, len(files))
for _, confFile := range files {
conf, err := libcni.ConfListFromFile(confFile)
if err != nil {
@@ -72,7 +72,7 @@ func ReadRawCNIConfByName(config *config.Config, name string) ([]byte, error) {
// GetCNIPlugins returns a list of plugins that a given network
// has in the form of a string
func GetCNIPlugins(list *libcni.NetworkConfigList) string {
- var plugins []string
+ plugins := make([]string, 0, len(list.Plugins))
for _, plug := range list.Plugins {
plugins = append(plugins, plug.Network.Type)
}
@@ -106,12 +106,11 @@ func GetNetworksFromFilesystem(config *config.Config) ([]*allocator.Net, error)
// GetNetworkNamesFromFileSystem gets all the names from the cni network
// configuration files
func GetNetworkNamesFromFileSystem(config *config.Config) ([]string, error) {
- var networkNames []string
-
networks, err := LoadCNIConfsFromDir(GetCNIConfDir(config))
if err != nil {
return nil, err
}
+ networkNames := []string{}
for _, n := range networks {
networkNames = append(networkNames, n.Name)
}
@@ -144,12 +143,12 @@ func GetInterfaceNameFromConfig(path string) (string, error) {
// GetBridgeNamesFromFileSystem is a convenience function to get all the bridge
// names from the configured networks
func GetBridgeNamesFromFileSystem(config *config.Config) ([]string, error) {
- var bridgeNames []string
-
networks, err := LoadCNIConfsFromDir(GetCNIConfDir(config))
if err != nil {
return nil, err
}
+
+ bridgeNames := []string{}
for _, n := range networks {
var name string
// iterate network conflists
diff --git a/pkg/network/network.go b/pkg/network/network.go
index 3ff664316..997aaf8a2 100644
--- a/pkg/network/network.go
+++ b/pkg/network/network.go
@@ -30,11 +30,11 @@ func IsSupportedDriver(driver string) error {
// GetLiveNetworks returns a slice of networks representing what the system
// has defined as network interfaces
func GetLiveNetworks() ([]*net.IPNet, error) {
- var nets []*net.IPNet
addrs, err := net.InterfaceAddrs()
if err != nil {
return nil, err
}
+ nets := make([]*net.IPNet, 0, len(addrs))
for _, address := range addrs {
_, n, err := net.ParseCIDR(address.String())
if err != nil {
@@ -47,11 +47,11 @@ func GetLiveNetworks() ([]*net.IPNet, error) {
// GetLiveNetworkNames returns a list of network interfaces on the system
func GetLiveNetworkNames() ([]string, error) {
- var interfaceNames []string
liveInterfaces, err := net.Interfaces()
if err != nil {
return nil, err
}
+ interfaceNames := make([]string, 0, len(liveInterfaces))
for _, i := range liveInterfaces {
interfaceNames = append(interfaceNames, i.Name)
}
diff --git a/pkg/ps/ps.go b/pkg/ps/ps.go
index ec96367cb..b07eb7f9a 100644
--- a/pkg/ps/ps.go
+++ b/pkg/ps/ps.go
@@ -21,7 +21,7 @@ import (
func GetContainerLists(runtime *libpod.Runtime, options entities.ContainerListOptions) ([]entities.ListContainer, error) {
var (
filterFuncs []libpod.ContainerFilter
- pss []entities.ListContainer
+ pss = []entities.ListContainer{}
)
all := options.All || options.Last > 0
if len(options.Filters) > 0 {
diff --git a/pkg/signal/signal_linux.go b/pkg/signal/signal_linux.go
index 6eebf7e5a..72ab1b97b 100644
--- a/pkg/signal/signal_linux.go
+++ b/pkg/signal/signal_linux.go
@@ -93,7 +93,7 @@ var signalMap = map[string]syscall.Signal{
// CatchAll catches all signals and relays them to the specified channel.
func CatchAll(sigc chan os.Signal) {
- var handledSigs []os.Signal
+ handledSigs := make([]os.Signal, 0, len(signalMap))
for _, s := range signalMap {
handledSigs = append(handledSigs, s)
}
diff --git a/pkg/specgen/generate/pod_create.go b/pkg/specgen/generate/pod_create.go
index cd2d69cfb..5ccb1ba80 100644
--- a/pkg/specgen/generate/pod_create.go
+++ b/pkg/specgen/generate/pod_create.go
@@ -93,5 +93,9 @@ func createPodOptions(p *specgen.PodSpecGenerator) ([]libpod.PodCreateOption, er
options = append(options, libpod.WithInfraContainerPorts(ports))
}
options = append(options, libpod.WithPodCgroups())
+ options = append(options, libpod.WithPodCreateCommand())
+ if len(p.InfraConmonPidFile) > 0 {
+ options = append(options, libpod.WithInfraConmonPidFile(p.InfraConmonPidFile))
+ }
return options, nil
}
diff --git a/pkg/specgen/podspecgen.go b/pkg/specgen/podspecgen.go
index 11976233a..600d27004 100644
--- a/pkg/specgen/podspecgen.go
+++ b/pkg/specgen/podspecgen.go
@@ -25,6 +25,9 @@ type PodBasicConfig struct {
// InfraCommand and InfraImages in this struct.
// Optional.
NoInfra bool `json:"no_infra,omitempty"`
+ // InfraConmonPidFile is a custom path to store the infra container's
+ // conmon PID.
+ InfraConmonPidFile string `json:"infra_conmon_pid_file,omitempty"`
// InfraCommand sets the command that will be used to start the infra
// container.
// If not set, the default set in the Libpod configuration file will be
diff --git a/pkg/systemd/generate/common.go b/pkg/systemd/generate/common.go
new file mode 100644
index 000000000..fe56dc874
--- /dev/null
+++ b/pkg/systemd/generate/common.go
@@ -0,0 +1,50 @@
+package generate
+
+import (
+ "github.com/pkg/errors"
+)
+
+// EnvVariable "PODMAN_SYSTEMD_UNIT" is set in all generated systemd units and
+// is set to the unit's (unique) name.
+const EnvVariable = "PODMAN_SYSTEMD_UNIT"
+
+// 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"}
+
+// validateRestartPolicy checks that the user-provided policy is valid.
+func validateRestartPolicy(restart string) error {
+ for _, i := range restartPolicies {
+ if i == restart {
+ return nil
+ }
+ }
+ return errors.Errorf("%s is not a valid restart policy", restart)
+}
+
+const headerTemplate = `# {{.ServiceName}}.service
+# autogenerated by Podman {{.PodmanVersion}}
+{{- if .TimeStamp}}
+# {{.TimeStamp}}
+{{- end}}
+
+[Unit]
+Description=Podman {{.ServiceName}}.service
+Documentation=man:podman-generate-systemd(1)
+Wants=network.target
+After=network-online.target
+`
+
+// filterPodFlags removes --pod and --pod-id-file from the specified command.
+func filterPodFlags(command []string) []string {
+ processed := []string{}
+ for i := 0; i < len(command); i++ {
+ s := command[i]
+ if s == "--pod" || s == "--pod-id-file" {
+ i++
+ continue
+ }
+ processed = append(processed, s)
+ }
+ return processed
+}
diff --git a/pkg/systemd/generate/common_test.go b/pkg/systemd/generate/common_test.go
new file mode 100644
index 000000000..f53bb7828
--- /dev/null
+++ b/pkg/systemd/generate/common_test.go
@@ -0,0 +1,25 @@
+package generate
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestFilterPodFlags(t *testing.T) {
+
+ tests := []struct {
+ input []string
+ }{
+ {[]string{"podman", "pod", "create"}},
+ {[]string{"podman", "pod", "create", "--name", "foo"}},
+ {[]string{"podman", "pod", "create", "--pod-id-file", "foo"}},
+ {[]string{"podman", "run", "--pod", "foo"}},
+ }
+
+ for _, test := range tests {
+ processed := filterPodFlags(test.input)
+ assert.NotContains(t, processed, "--pod-id-file")
+ assert.NotContains(t, processed, "--pod")
+ }
+}
diff --git a/pkg/systemd/generate/containers.go b/pkg/systemd/generate/containers.go
new file mode 100644
index 000000000..dced1a3da
--- /dev/null
+++ b/pkg/systemd/generate/containers.go
@@ -0,0 +1,289 @@
+package generate
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+ "text/template"
+ "time"
+
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/version"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+// containerInfo contains data required for generating a container's systemd
+// unit file.
+type containerInfo struct {
+ // ServiceName of the systemd service.
+ ServiceName string
+ // Name or ID of the container.
+ ContainerNameOrID string
+ // StopTimeout sets the timeout Podman waits before killing the container
+ // during service stop.
+ StopTimeout uint
+ // RestartPolicy of the systemd unit (e.g., no, on-failure, always).
+ RestartPolicy string
+ // PIDFile of the service. Required for forking services. Must point to the
+ // PID of the associated conmon process.
+ PIDFile string
+ // ContainerIDFile to be used in the unit.
+ ContainerIDFile string
+ // GenerateTimestamp, if set the generated unit file has a time stamp.
+ GenerateTimestamp bool
+ // BoundToServices are the services this service binds to. Note that this
+ // service runs after them.
+ BoundToServices []string
+ // PodmanVersion for the header. Will be set internally. Will be auto-filled
+ // if left empty.
+ PodmanVersion string
+ // Executable is the path to the podman executable. Will be auto-filled if
+ // left empty.
+ Executable 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
+ // container has been created with.
+ CreateCommand []string
+ // EnvVariable is generate.EnvVariable and must not be set.
+ EnvVariable string
+ // ExecStartPre of the unit.
+ ExecStartPre string
+ // ExecStart of the unit.
+ ExecStart string
+ // ExecStop of the unit.
+ ExecStop string
+ // ExecStopPost of the unit.
+ ExecStopPost string
+
+ // If not nil, the container is part of the pod. We can use the
+ // podInfo to extract the relevant data.
+ pod *podInfo
+}
+
+const containerTemplate = headerTemplate + `
+{{- if .BoundToServices}}
+RefuseManualStart=yes
+RefuseManualStop=yes
+BindsTo={{- range $index, $value := .BoundToServices -}}{{if $index}} {{end}}{{ $value }}.service{{end}}
+After={{- range $index, $value := .BoundToServices -}}{{if $index}} {{end}}{{ $value }}.service{{end}}
+{{- end}}
+
+[Service]
+Environment={{.EnvVariable}}=%n
+Restart={{.RestartPolicy}}
+{{- if .ExecStartPre}}
+ExecStartPre={{.ExecStartPre}}
+{{- end}}
+ExecStart={{.ExecStart}}
+ExecStop={{.ExecStop}}
+{{- if .ExecStopPost}}
+ExecStopPost={{.ExecStopPost}}
+{{- end}}
+PIDFile={{.PIDFile}}
+KillMode=none
+Type=forking
+
+[Install]
+WantedBy=multi-user.target default.target`
+
+// ContainerUnit generates a systemd unit for the specified container. Based
+// on the options, the return value might be the entire unit or a file it has
+// been written to.
+func ContainerUnit(ctr *libpod.Container, options entities.GenerateSystemdOptions) (string, error) {
+ info, err := generateContainerInfo(ctr, options)
+ if err != nil {
+ return "", err
+ }
+ return executeContainerTemplate(info, options)
+}
+
+func generateContainerInfo(ctr *libpod.Container, options entities.GenerateSystemdOptions) (*containerInfo, error) {
+ timeout := ctr.StopTimeout()
+ if options.StopTimeout != nil {
+ timeout = *options.StopTimeout
+ }
+
+ config := ctr.Config()
+ conmonPidFile := config.ConmonPidFile
+ if conmonPidFile == "" {
+ return nil, errors.Errorf("conmon PID file path is empty, try to recreate the container with --conmon-pidfile flag")
+ }
+
+ createCommand := []string{}
+ if config.CreateCommand != nil {
+ createCommand = config.CreateCommand
+ } else if options.New {
+ return nil, errors.Errorf("cannot use --new on container %q: no create command found", ctr.ID())
+ }
+
+ nameOrID, serviceName := containerServiceName(ctr, options)
+
+ info := containerInfo{
+ ServiceName: serviceName,
+ ContainerNameOrID: nameOrID,
+ RestartPolicy: options.RestartPolicy,
+ PIDFile: conmonPidFile,
+ StopTimeout: timeout,
+ GenerateTimestamp: true,
+ CreateCommand: createCommand,
+ }
+
+ return &info, nil
+}
+
+// containerServiceName returns the nameOrID and the service name of the
+// container.
+func containerServiceName(ctr *libpod.Container, options entities.GenerateSystemdOptions) (string, string) {
+ nameOrID := ctr.ID()
+ if options.Name {
+ nameOrID = ctr.Name()
+ }
+ serviceName := fmt.Sprintf("%s%s%s", options.ContainerPrefix, options.Separator, nameOrID)
+ return nameOrID, serviceName
+}
+
+// executeContainerTemplate executes the container template on the specified
+// containerInfo. Note that the containerInfo is also post processed and
+// completed, which allows for an easier unit testing.
+func executeContainerTemplate(info *containerInfo, options entities.GenerateSystemdOptions) (string, error) {
+ if err := validateRestartPolicy(info.RestartPolicy); err != nil {
+ return "", err
+ }
+
+ // Make sure the executable is set.
+ if info.Executable == "" {
+ executable, err := os.Executable()
+ if err != nil {
+ executable = "/usr/bin/podman"
+ logrus.Warnf("Could not obtain podman executable location, using default %s", executable)
+ }
+ info.Executable = executable
+ }
+
+ info.EnvVariable = EnvVariable
+ info.ExecStart = "{{.Executable}} start {{.ContainerNameOrID}}"
+ info.ExecStop = "{{.Executable}} stop {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}} {{.ContainerNameOrID}}"
+
+ // Assemble the ExecStart command when creating a new container.
+ //
+ // Note that we cannot catch all corner cases here such that users
+ // *must* manually check the generated files. A container might have
+ // been created via a Python script, which would certainly yield an
+ // invalid `info.CreateCommand`. Hence, we're doing a best effort unit
+ // generation and don't try aiming at completeness.
+ if options.New {
+ info.PIDFile = "%t/" + info.ServiceName + ".pid"
+ 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
+ }
+ if len(info.CreateCommand) < index+1 {
+ 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 subcomand.
+ startCommand := []string{
+ info.Executable,
+ "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 {
+ podFlags := []string{"--pod-id-file", info.pod.PodIDFile}
+ startCommand = append(startCommand, podFlags...)
+ info.CreateCommand = filterPodFlags(info.CreateCommand)
+ }
+
+ // Enforce detaching
+ //
+ // since we use systemd `Type=forking` service
+ // @see https://www.freedesktop.org/software/systemd/man/systemd.service.html#Type=
+ // when we generated systemd service file with the --new param,
+ // `ExecStart` will have `/usr/bin/podman run ...`
+ // if `info.CreateCommand` has no `-d` or `--detach` param,
+ // podman will run the container in default attached mode,
+ // as a result, `systemd start` will wait the `podman run` command exit until failed with timeout error.
+ hasDetachParam := false
+ for _, p := range info.CreateCommand[index:] {
+ if p == "--detach" || p == "-d" {
+ hasDetachParam = true
+ }
+ }
+ if !hasDetachParam {
+ startCommand = append(startCommand, "-d")
+ }
+ startCommand = append(startCommand, info.CreateCommand[index:]...)
+
+ info.ExecStartPre = "/usr/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}}"
+ }
+
+ if info.PodmanVersion == "" {
+ info.PodmanVersion = version.Version
+ }
+ if info.GenerateTimestamp {
+ info.TimeStamp = fmt.Sprintf("%v", time.Now().Format(time.UnixDate))
+ }
+
+ // Sort the slices to assure a deterministic output.
+ sort.Strings(info.BoundToServices)
+
+ // Generate the template and compile it.
+ //
+ // Note that we need a two-step generation process to allow for fields
+ // embedding other fields. This way we can replace `A -> B -> C` and
+ // make the code easier to maintain at the cost of a slightly slower
+ // generation. That's especially needed for embedding the PID and ID
+ // files in other fields which will eventually get replaced in the 2nd
+ // template execution.
+ templ, err := template.New("container_template").Parse(containerTemplate)
+ if err != nil {
+ return "", errors.Wrap(err, "error parsing systemd service template")
+ }
+
+ var buf bytes.Buffer
+ if err := templ.Execute(&buf, info); err != nil {
+ return "", err
+ }
+
+ // Now parse the generated template (i.e., buf) and execute it.
+ templ, err = template.New("container_template").Parse(buf.String())
+ if err != nil {
+ return "", errors.Wrap(err, "error parsing systemd service template")
+ }
+
+ buf = bytes.Buffer{}
+ if err := templ.Execute(&buf, info); err != nil {
+ return "", err
+ }
+
+ if !options.Files {
+ return buf.String(), nil
+ }
+
+ buf.WriteByte('\n')
+ cwd, err := os.Getwd()
+ if err != nil {
+ return "", errors.Wrap(err, "error getting current working directory")
+ }
+ path := filepath.Join(cwd, fmt.Sprintf("%s.service", info.ServiceName))
+ if err := ioutil.WriteFile(path, buf.Bytes(), 0644); err != nil {
+ return "", errors.Wrap(err, "error generating systemd unit")
+ }
+ return path, nil
+}
diff --git a/pkg/systemd/generate/containers_test.go b/pkg/systemd/generate/containers_test.go
new file mode 100644
index 000000000..8365ecd7a
--- /dev/null
+++ b/pkg/systemd/generate/containers_test.go
@@ -0,0 +1,366 @@
+package generate
+
+import (
+ "testing"
+
+ "github.com/containers/libpod/pkg/domain/entities"
+)
+
+func TestValidateRestartPolicyContainer(t *testing.T) {
+ type containerInfo struct {
+ restart string
+ }
+ tests := []struct {
+ name string
+ containerInfo containerInfo
+ wantErr bool
+ }{
+ {"good-on", containerInfo{restart: "no"}, false},
+ {"good-on-success", containerInfo{restart: "on-success"}, false},
+ {"good-on-failure", containerInfo{restart: "on-failure"}, false},
+ {"good-on-abnormal", containerInfo{restart: "on-abnormal"}, false},
+ {"good-on-watchdog", containerInfo{restart: "on-watchdog"}, false},
+ {"good-on-abort", containerInfo{restart: "on-abort"}, false},
+ {"good-always", containerInfo{restart: "always"}, false},
+ {"fail", containerInfo{restart: "foobar"}, true},
+ {"failblank", containerInfo{restart: ""}, true},
+ }
+ for _, tt := range tests {
+ test := tt
+ t.Run(tt.name, func(t *testing.T) {
+ if err := validateRestartPolicy(test.containerInfo.restart); (err != nil) != test.wantErr {
+ t.Errorf("ValidateRestartPolicy() error = %v, wantErr %v", err, test.wantErr)
+ }
+ })
+ }
+}
+
+func TestCreateContainerSystemdUnit(t *testing.T) {
+ goodID := `# container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.service
+# autogenerated by Podman CI
+
+[Unit]
+Description=Podman container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.service
+Documentation=man:podman-generate-systemd(1)
+Wants=network.target
+After=network-online.target
+
+[Service]
+Environment=PODMAN_SYSTEMD_UNIT=%n
+Restart=always
+ExecStart=/usr/bin/podman start 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
+ExecStop=/usr/bin/podman stop -t 10 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
+PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
+KillMode=none
+Type=forking
+
+[Install]
+WantedBy=multi-user.target default.target`
+
+ goodName := `# container-foobar.service
+# autogenerated by Podman CI
+
+[Unit]
+Description=Podman container-foobar.service
+Documentation=man:podman-generate-systemd(1)
+Wants=network.target
+After=network-online.target
+
+[Service]
+Environment=PODMAN_SYSTEMD_UNIT=%n
+Restart=always
+ExecStart=/usr/bin/podman start foobar
+ExecStop=/usr/bin/podman stop -t 10 foobar
+PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
+KillMode=none
+Type=forking
+
+[Install]
+WantedBy=multi-user.target default.target`
+
+ goodNameBoundTo := `# container-foobar.service
+# autogenerated by Podman CI
+
+[Unit]
+Description=Podman container-foobar.service
+Documentation=man:podman-generate-systemd(1)
+Wants=network.target
+After=network-online.target
+RefuseManualStart=yes
+RefuseManualStop=yes
+BindsTo=a.service b.service c.service pod.service
+After=a.service b.service c.service pod.service
+
+[Service]
+Environment=PODMAN_SYSTEMD_UNIT=%n
+Restart=always
+ExecStart=/usr/bin/podman start foobar
+ExecStop=/usr/bin/podman stop -t 10 foobar
+PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
+KillMode=none
+Type=forking
+
+[Install]
+WantedBy=multi-user.target default.target`
+
+ goodNameNew := `# 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
+ExecStartPre=/usr/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 --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
+ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id
+PIDFile=%t/jadda-jadda.pid
+KillMode=none
+Type=forking
+
+[Install]
+WantedBy=multi-user.target default.target`
+
+ goodNameNewWithPodFile := `# 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
+ExecStartPre=/usr/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 -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
+ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id
+PIDFile=%t/jadda-jadda.pid
+KillMode=none
+Type=forking
+
+[Install]
+WantedBy=multi-user.target default.target`
+ goodNameNewDetach := `# 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
+ExecStartPre=/usr/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 --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
+ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id
+PIDFile=%t/jadda-jadda.pid
+KillMode=none
+Type=forking
+
+[Install]
+WantedBy=multi-user.target default.target`
+
+ goodIDNew := `# container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.service
+# autogenerated by Podman CI
+
+[Unit]
+Description=Podman container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.service
+Documentation=man:podman-generate-systemd(1)
+Wants=network.target
+After=network-online.target
+
+[Service]
+Environment=PODMAN_SYSTEMD_UNIT=%n
+Restart=always
+ExecStartPre=/usr/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`
+
+ tests := []struct {
+ name string
+ info containerInfo
+ want string
+ new bool
+ wantErr bool
+ }{
+
+ {"good with id",
+ containerInfo{
+ Executable: "/usr/bin/podman",
+ ServiceName: "container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
+ ContainerNameOrID: "639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
+ RestartPolicy: "always",
+ PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 10,
+ PodmanVersion: "CI",
+ EnvVariable: EnvVariable,
+ },
+ goodID,
+ false,
+ false,
+ },
+ {"good with name",
+ containerInfo{
+ Executable: "/usr/bin/podman",
+ ServiceName: "container-foobar",
+ ContainerNameOrID: "foobar",
+ RestartPolicy: "always",
+ PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 10,
+ PodmanVersion: "CI",
+ EnvVariable: EnvVariable,
+ },
+ goodName,
+ false,
+ false,
+ },
+ {"good with name and bound to",
+ containerInfo{
+ Executable: "/usr/bin/podman",
+ ServiceName: "container-foobar",
+ ContainerNameOrID: "foobar",
+ RestartPolicy: "always",
+ PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 10,
+ PodmanVersion: "CI",
+ BoundToServices: []string{"pod", "a", "b", "c"},
+ EnvVariable: EnvVariable,
+ },
+ goodNameBoundTo,
+ false,
+ false,
+ },
+ {"bad restart policy",
+ containerInfo{
+ Executable: "/usr/bin/podman",
+ ServiceName: "639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
+ RestartPolicy: "never",
+ PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 10,
+ PodmanVersion: "CI",
+ EnvVariable: EnvVariable,
+ },
+ "",
+ false,
+ true,
+ },
+ {"good with name and generic",
+ 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", "container", "run", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN"},
+ EnvVariable: EnvVariable,
+ },
+ goodNameNew,
+ true,
+ false,
+ },
+ {"good with explicit short detach 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", "container", "run", "-d", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN"},
+ EnvVariable: EnvVariable,
+ },
+ goodNameNew,
+ true,
+ false,
+ },
+ {"good with explicit short detach param and podInfo",
+ 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", "container", "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",
+ },
+ },
+ goodNameNewWithPodFile,
+ true,
+ false,
+ },
+ {"good with explicit full detach 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", "container", "run", "--detach", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN"},
+ EnvVariable: EnvVariable,
+ },
+ goodNameNewDetach,
+ true,
+ false,
+ },
+ {"good with id and no param",
+ containerInfo{
+ Executable: "/usr/bin/podman",
+ ServiceName: "container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
+ ContainerNameOrID: "639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
+ RestartPolicy: "always",
+ PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 10,
+ PodmanVersion: "CI",
+ CreateCommand: []string{"I'll get stripped", "container", "run", "awesome-image:latest"},
+ EnvVariable: EnvVariable,
+ },
+ goodIDNew,
+ true,
+ false,
+ },
+ }
+ for _, tt := range tests {
+ test := tt
+ t.Run(tt.name, func(t *testing.T) {
+ opts := entities.GenerateSystemdOptions{
+ Files: false,
+ New: test.new,
+ }
+ got, err := executeContainerTemplate(&test.info, opts)
+ if (err != nil) != test.wantErr {
+ 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)
+ }
+ })
+ }
+}
diff --git a/pkg/systemd/generate/pods.go b/pkg/systemd/generate/pods.go
new file mode 100644
index 000000000..5cfd5ab0a
--- /dev/null
+++ b/pkg/systemd/generate/pods.go
@@ -0,0 +1,341 @@
+package generate
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+ "text/template"
+ "time"
+
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/version"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+// podInfo contains data required for generating a pod's systemd
+// unit file.
+type podInfo struct {
+ // ServiceName of the systemd service.
+ ServiceName string
+ // Name or ID of the infra container.
+ InfraNameOrID string
+ // StopTimeout sets the timeout Podman waits before killing the container
+ // during service stop.
+ StopTimeout uint
+ // RestartPolicy of the systemd unit (e.g., no, on-failure, always).
+ RestartPolicy string
+ // PIDFile of the service. Required for forking services. Must point to the
+ // PID of the associated conmon process.
+ PIDFile string
+ // PodIDFile of the unit.
+ PodIDFile string
+ // GenerateTimestamp, if set the generated unit file has a time stamp.
+ GenerateTimestamp bool
+ // RequiredServices are services this service requires. Note that this
+ // service runs before them.
+ RequiredServices []string
+ // PodmanVersion for the header. Will be set internally. Will be auto-filled
+ // if left empty.
+ PodmanVersion string
+ // Executable is the path to the podman executable. Will be auto-filled if
+ // left empty.
+ Executable 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
+ // container has been created with.
+ CreateCommand []string
+ // PodCreateCommand - a post-processed variant of CreateCommand to use
+ // when creating the pod.
+ PodCreateCommand string
+ // EnvVariable is generate.EnvVariable and must not be set.
+ EnvVariable string
+ // ExecStartPre1 of the unit.
+ ExecStartPre1 string
+ // ExecStartPre2 of the unit.
+ ExecStartPre2 string
+ // ExecStart of the unit.
+ ExecStart string
+ // ExecStop of the unit.
+ ExecStop string
+ // ExecStopPost of the unit.
+ ExecStopPost string
+}
+
+const podTemplate = headerTemplate + `Requires={{- range $index, $value := .RequiredServices -}}{{if $index}} {{end}}{{ $value }}.service{{end}}
+Before={{- range $index, $value := .RequiredServices -}}{{if $index}} {{end}}{{ $value }}.service{{end}}
+
+[Service]
+Environment={{.EnvVariable}}=%n
+Restart={{.RestartPolicy}}
+{{- if .ExecStartPre1}}
+ExecStartPre={{.ExecStartPre1}}
+{{- end}}
+{{- if .ExecStartPre2}}
+ExecStartPre={{.ExecStartPre2}}
+{{- end}}
+ExecStart={{.ExecStart}}
+ExecStop={{.ExecStop}}
+{{- if .ExecStopPost}}
+ExecStopPost={{.ExecStopPost}}
+{{- end}}
+PIDFile={{.PIDFile}}
+KillMode=none
+Type=forking
+
+[Install]
+WantedBy=multi-user.target default.target`
+
+// PodUnits generates systemd units for the specified pod and its containers.
+// Based on the options, the return value might be the content of all units or
+// the files they been written to.
+func PodUnits(pod *libpod.Pod, options entities.GenerateSystemdOptions) (string, error) {
+ // Error out if the pod has no infra container, which we require to be the
+ // main service.
+ if !pod.HasInfraContainer() {
+ return "", errors.Errorf("error generating systemd unit files: Pod %q has no infra container", pod.Name())
+ }
+
+ podInfo, err := generatePodInfo(pod, options)
+ if err != nil {
+ return "", err
+ }
+
+ infraID, err := pod.InfraContainerID()
+ if err != nil {
+ return "", err
+ }
+
+ // Compute the container-dependency graph for the Pod.
+ containers, err := pod.AllContainers()
+ if err != nil {
+ return "", err
+ }
+ if len(containers) == 0 {
+ return "", errors.Errorf("error generating systemd unit files: Pod %q has no containers", pod.Name())
+ }
+ graph, err := libpod.BuildContainerGraph(containers)
+ if err != nil {
+ return "", err
+ }
+
+ // Traverse the dependency graph and create systemdgen.containerInfo's for
+ // each container.
+ containerInfos := []*containerInfo{}
+ for ctr, dependencies := range graph.DependencyMap() {
+ // Skip the infra container as we already generated it.
+ if ctr.ID() == infraID {
+ continue
+ }
+ ctrInfo, err := generateContainerInfo(ctr, options)
+ if err != nil {
+ return "", err
+ }
+ // Now add the container's dependencies and at the container as a
+ // required service of the infra container.
+ for _, dep := range dependencies {
+ if dep.ID() == infraID {
+ ctrInfo.BoundToServices = append(ctrInfo.BoundToServices, podInfo.ServiceName)
+ } else {
+ _, serviceName := containerServiceName(dep, options)
+ ctrInfo.BoundToServices = append(ctrInfo.BoundToServices, serviceName)
+ }
+ }
+ podInfo.RequiredServices = append(podInfo.RequiredServices, ctrInfo.ServiceName)
+ containerInfos = append(containerInfos, ctrInfo)
+ }
+
+ // Now generate the systemd service for all containers.
+ builder := strings.Builder{}
+ out, err := executePodTemplate(podInfo, options)
+ if err != nil {
+ return "", err
+ }
+ builder.WriteString(out)
+ for _, info := range containerInfos {
+ info.pod = podInfo
+ builder.WriteByte('\n')
+ out, err := executeContainerTemplate(info, options)
+ if err != nil {
+ return "", err
+ }
+ builder.WriteString(out)
+ }
+
+ return builder.String(), nil
+}
+
+func generatePodInfo(pod *libpod.Pod, options entities.GenerateSystemdOptions) (*podInfo, error) {
+ // Generate a systemdgen.containerInfo for the infra container. This
+ // containerInfo acts as the main service of the pod.
+ infraCtr, err := pod.InfraContainer()
+ if err != nil {
+ return nil, errors.Wrap(err, "could not find infra container")
+ }
+
+ timeout := infraCtr.StopTimeout()
+ if options.StopTimeout != nil {
+ timeout = *options.StopTimeout
+ }
+
+ config := infraCtr.Config()
+ conmonPidFile := config.ConmonPidFile
+ if conmonPidFile == "" {
+ return nil, errors.Errorf("conmon PID file path is empty, try to recreate the container with --conmon-pidfile flag")
+ }
+
+ createCommand := pod.CreateCommand()
+ if options.New && len(createCommand) == 0 {
+ return nil, errors.Errorf("cannot use --new on pod %q: no create command found", pod.ID())
+ }
+
+ nameOrID := pod.ID()
+ ctrNameOrID := infraCtr.ID()
+ if options.Name {
+ nameOrID = pod.Name()
+ ctrNameOrID = infraCtr.Name()
+ }
+ serviceName := fmt.Sprintf("%s%s%s", options.PodPrefix, options.Separator, nameOrID)
+
+ info := podInfo{
+ ServiceName: serviceName,
+ InfraNameOrID: ctrNameOrID,
+ RestartPolicy: options.RestartPolicy,
+ PIDFile: conmonPidFile,
+ StopTimeout: timeout,
+ GenerateTimestamp: true,
+ CreateCommand: createCommand,
+ }
+ return &info, nil
+}
+
+// executePodTemplate executes the pod template on the specified podInfo. Note
+// that the podInfo is also post processed and completed, which allows for an
+// easier unit testing.
+func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions) (string, error) {
+ if err := validateRestartPolicy(info.RestartPolicy); err != nil {
+ return "", err
+ }
+
+ // Make sure the executable is set.
+ if info.Executable == "" {
+ executable, err := os.Executable()
+ if err != nil {
+ executable = "/usr/bin/podman"
+ logrus.Warnf("Could not obtain podman executable location, using default %s", executable)
+ }
+ info.Executable = executable
+ }
+
+ info.EnvVariable = EnvVariable
+ info.ExecStart = "{{.Executable}} start {{.InfraNameOrID}}"
+ info.ExecStop = "{{.Executable}} stop {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}} {{.InfraNameOrID}}"
+
+ // Assemble the ExecStart command when creating a new pod.
+ //
+ // Note that we cannot catch all corner cases here such that users
+ // *must* manually check the generated files. A pod might have been
+ // created via a Python script, which would certainly yield an invalid
+ // `info.CreateCommand`. Hence, we're doing a best effort unit
+ // generation and don't try aiming at completeness.
+ if options.New {
+ info.PIDFile = "%t/" + info.ServiceName + ".pid"
+ info.PodIDFile = "%t/" + info.ServiceName + ".pod-id"
+
+ podCreateIndex := 0
+ var podRootArgs, podCreateArgs []string
+ switch len(info.CreateCommand) {
+ case 0, 1, 2:
+ return "", errors.Errorf("pod does not appear to be created via `podman pod create`: %v", info.CreateCommand)
+ default:
+ // Make sure that pod was created with `pod create` and
+ // not something else, such as `run --pod new`.
+ for i := 1; i < len(info.CreateCommand); i++ {
+ if info.CreateCommand[i-1] == "pod" && info.CreateCommand[i] == "create" {
+ podCreateIndex = i
+ break
+ }
+ }
+ if podCreateIndex == 0 {
+ return "", errors.Errorf("pod does not appear to be created via `podman pod create`: %v", info.CreateCommand)
+ }
+ podRootArgs = info.CreateCommand[1 : podCreateIndex-2]
+ podCreateArgs = filterPodFlags(info.CreateCommand[podCreateIndex+1:])
+ }
+ // We're hard-coding the first five arguments and append the
+ // CreateCommand with a stripped command and subcomand.
+ startCommand := []string{info.Executable}
+ startCommand = append(startCommand, podRootArgs...)
+ startCommand = append(startCommand,
+ []string{"pod", "create",
+ "--infra-conmon-pidfile", "{{.PIDFile}}",
+ "--pod-id-file", "{{.PodIDFile}}"}...)
+
+ startCommand = append(startCommand, podCreateArgs...)
+
+ info.ExecStartPre1 = "/usr/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}}"
+ }
+ if info.PodmanVersion == "" {
+ info.PodmanVersion = version.Version
+ }
+ if info.GenerateTimestamp {
+ info.TimeStamp = fmt.Sprintf("%v", time.Now().Format(time.UnixDate))
+ }
+
+ // Sort the slices to assure a deterministic output.
+ sort.Strings(info.RequiredServices)
+
+ // Generate the template and compile it.
+ //
+ // Note that we need a two-step generation process to allow for fields
+ // embedding other fields. This way we can replace `A -> B -> C` and
+ // make the code easier to maintain at the cost of a slightly slower
+ // generation. That's especially needed for embedding the PID and ID
+ // files in other fields which will eventually get replaced in the 2nd
+ // template execution.
+ templ, err := template.New("pod_template").Parse(podTemplate)
+ if err != nil {
+ return "", errors.Wrap(err, "error parsing systemd service template")
+ }
+
+ var buf bytes.Buffer
+ if err := templ.Execute(&buf, info); err != nil {
+ return "", err
+ }
+
+ // Now parse the generated template (i.e., buf) and execute it.
+ templ, err = template.New("pod_template").Parse(buf.String())
+ if err != nil {
+ return "", errors.Wrap(err, "error parsing systemd service template")
+ }
+
+ buf = bytes.Buffer{}
+ if err := templ.Execute(&buf, info); err != nil {
+ return "", err
+ }
+
+ if !options.Files {
+ return buf.String(), nil
+ }
+
+ buf.WriteByte('\n')
+ cwd, err := os.Getwd()
+ if err != nil {
+ return "", errors.Wrap(err, "error getting current working directory")
+ }
+ path := filepath.Join(cwd, fmt.Sprintf("%s.service", info.ServiceName))
+ if err := ioutil.WriteFile(path, buf.Bytes(), 0644); err != nil {
+ return "", errors.Wrap(err, "error generating systemd unit")
+ }
+ return path, nil
+}
diff --git a/pkg/systemd/generate/pods_test.go b/pkg/systemd/generate/pods_test.go
new file mode 100644
index 000000000..f6e225c35
--- /dev/null
+++ b/pkg/systemd/generate/pods_test.go
@@ -0,0 +1,100 @@
+package generate
+
+import (
+ "testing"
+
+ "github.com/containers/libpod/pkg/domain/entities"
+)
+
+func TestValidateRestartPolicyPod(t *testing.T) {
+ type podInfo struct {
+ restart string
+ }
+ tests := []struct {
+ name string
+ podInfo podInfo
+ wantErr bool
+ }{
+ {"good-on", podInfo{restart: "no"}, false},
+ {"good-on-success", podInfo{restart: "on-success"}, false},
+ {"good-on-failure", podInfo{restart: "on-failure"}, false},
+ {"good-on-abnormal", podInfo{restart: "on-abnormal"}, false},
+ {"good-on-watchdog", podInfo{restart: "on-watchdog"}, false},
+ {"good-on-abort", podInfo{restart: "on-abort"}, false},
+ {"good-always", podInfo{restart: "always"}, false},
+ {"fail", podInfo{restart: "foobar"}, true},
+ {"failblank", podInfo{restart: ""}, true},
+ }
+ for _, tt := range tests {
+ test := tt
+ t.Run(tt.name, func(t *testing.T) {
+ if err := validateRestartPolicy(test.podInfo.restart); (err != nil) != test.wantErr {
+ t.Errorf("ValidateRestartPolicy() error = %v, wantErr %v", err, test.wantErr)
+ }
+ })
+ }
+}
+
+func TestCreatePodSystemdUnit(t *testing.T) {
+ podGoodName := `# 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=always
+ExecStart=/usr/bin/podman start jadda-jadda-infra
+ExecStop=/usr/bin/podman stop -t 10 jadda-jadda-infra
+PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
+KillMode=none
+Type=forking
+
+[Install]
+WantedBy=multi-user.target default.target`
+
+ tests := []struct {
+ name string
+ info podInfo
+ want string
+ wantErr bool
+ }{
+ {"pod",
+ 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,
+ PodmanVersion: "CI",
+ RequiredServices: []string{"container-1", "container-2"},
+ },
+ podGoodName,
+ false,
+ },
+ }
+
+ for _, tt := range tests {
+ test := tt
+ t.Run(tt.name, func(t *testing.T) {
+ opts := entities.GenerateSystemdOptions{
+ Files: false,
+ }
+ got, err := executePodTemplate(&test.info, opts)
+ if (err != nil) != test.wantErr {
+ 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)
+ }
+ })
+ }
+}
diff --git a/pkg/systemd/generate/systemdgen.go b/pkg/systemd/generate/systemdgen.go
deleted file mode 100644
index 73fe52c0e..000000000
--- a/pkg/systemd/generate/systemdgen.go
+++ /dev/null
@@ -1,237 +0,0 @@
-package generate
-
-import (
- "bytes"
- "fmt"
- "io/ioutil"
- "os"
- "path/filepath"
- "sort"
- "strings"
- "text/template"
- "time"
-
- "github.com/containers/libpod/version"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-)
-
-// EnvVariable "PODMAN_SYSTEMD_UNIT" is set in all generated systemd units and
-// is set to the unit's (unique) name.
-const EnvVariable = "PODMAN_SYSTEMD_UNIT"
-
-// ContainerInfo contains data required for generating a container's systemd
-// unit file.
-type ContainerInfo struct {
- // ServiceName of the systemd service.
- ServiceName string
- // Name or ID of the container.
- ContainerName string
- // InfraContainer of the pod.
- InfraContainer string
- // StopTimeout sets the timeout Podman waits before killing the container
- // during service stop.
- StopTimeout uint
- // RestartPolicy of the systemd unit (e.g., no, on-failure, always).
- RestartPolicy string
- // PIDFile of the service. Required for forking services. Must point to the
- // PID of the associated conmon process.
- PIDFile string
- // GenerateTimestamp, if set the generated unit file has a time stamp.
- GenerateTimestamp bool
- // BoundToServices are the services this service binds to. Note that this
- // service runs after them.
- BoundToServices []string
- // RequiredServices are services this service requires. Note that this
- // service runs before them.
- RequiredServices []string
- // PodmanVersion for the header. Will be set internally. Will be auto-filled
- // if left empty.
- PodmanVersion string
- // Executable is the path to the podman executable. Will be auto-filled if
- // left empty.
- Executable string
- // TimeStamp at the time of creating the unit file. Will be set internally.
- TimeStamp string
- // New controls if a new container is created or if an existing one is started.
- New bool
- // CreateCommand is the full command plus arguments of the process the
- // container has been created with.
- CreateCommand []string
- // RunCommand is a post-processed variant of CreateCommand and used for
- // the ExecStart field in generic unit files.
- RunCommand string
- // EnvVariable is generate.EnvVariable and must not be set.
- EnvVariable string
-}
-
-var restartPolicies = []string{"no", "on-success", "on-failure", "on-abnormal", "on-watchdog", "on-abort", "always"}
-
-// validateRestartPolicy checks that the user-provided policy is valid.
-func validateRestartPolicy(restart string) error {
- for _, i := range restartPolicies {
- if i == restart {
- return nil
- }
- }
- return errors.Errorf("%s is not a valid restart policy", restart)
-}
-
-const containerTemplate = `# {{.ServiceName}}.service
-# autogenerated by Podman {{.PodmanVersion}}
-{{- if .TimeStamp}}
-# {{.TimeStamp}}
-{{- end}}
-
-[Unit]
-Description=Podman {{.ServiceName}}.service
-Documentation=man:podman-generate-systemd(1)
-Wants=network.target
-After=network-online.target
-{{- if .BoundToServices}}
-RefuseManualStart=yes
-RefuseManualStop=yes
-BindsTo={{- range $index, $value := .BoundToServices -}}{{if $index}} {{end}}{{ $value }}.service{{end}}
-After={{- range $index, $value := .BoundToServices -}}{{if $index}} {{end}}{{ $value }}.service{{end}}
-{{- end}}
-{{- if .RequiredServices}}
-Requires={{- range $index, $value := .RequiredServices -}}{{if $index}} {{end}}{{ $value }}.service{{end}}
-Before={{- range $index, $value := .RequiredServices -}}{{if $index}} {{end}}{{ $value }}.service{{end}}
-{{- end}}
-
-[Service]
-Environment={{.EnvVariable}}=%n
-Restart={{.RestartPolicy}}
-{{- if .New}}
-ExecStartPre=/usr/bin/rm -f %t/%n-pid %t/%n-cid
-ExecStart={{.RunCommand}}
-ExecStop={{.Executable}} stop --ignore --cidfile %t/%n-cid {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}}
-ExecStopPost={{.Executable}} rm --ignore -f --cidfile %t/%n-cid
-PIDFile=%t/%n-pid
-{{- else}}
-ExecStart={{.Executable}} start {{.ContainerName}}
-ExecStop={{.Executable}} stop {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}} {{.ContainerName}}
-PIDFile={{.PIDFile}}
-{{- end}}
-KillMode=none
-Type=forking
-
-[Install]
-WantedBy=multi-user.target default.target`
-
-// Options include different options to control the unit file generation.
-type Options struct {
- // When set, generate service files in the current working directory and
- // return the paths to these files instead of returning all contents in one
- // big string.
- Files bool
- // New controls if a new container is created or if an existing one is started.
- New bool
-}
-
-// CreateContainerSystemdUnit creates a systemd unit file for a container.
-func CreateContainerSystemdUnit(info *ContainerInfo, opts Options) (string, error) {
- if err := validateRestartPolicy(info.RestartPolicy); err != nil {
- return "", err
- }
-
- // Make sure the executable is set.
- if info.Executable == "" {
- executable, err := os.Executable()
- if err != nil {
- executable = "/usr/bin/podman"
- logrus.Warnf("Could not obtain podman executable location, using default %s", executable)
- }
- info.Executable = executable
- }
-
- info.EnvVariable = EnvVariable
-
- // Assemble the ExecStart command when creating a new container.
- //
- // Note that we cannot catch all corner cases here such that users
- // *must* manually check the generated files. A container might have
- // been created via a Python script, which would certainly yield an
- // invalid `info.CreateCommand`. Hence, we're doing a best effort unit
- // generation and don't try aiming at completeness.
- if opts.New {
- // The create command must at least have three arguments:
- // /usr/bin/podman run $IMAGE
- index := 2
- if info.CreateCommand[1] == "container" {
- index = 3
- }
- if len(info.CreateCommand) < index+1 {
- 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 subcomand.
- command := []string{
- info.Executable,
- "run",
- "--conmon-pidfile", "%t/%n-pid",
- "--cidfile", "%t/%n-cid",
- "--cgroups=no-conmon",
- }
-
- // Enforce detaching
- //
- // since we use systemd `Type=forking` service
- // @see https://www.freedesktop.org/software/systemd/man/systemd.service.html#Type=
- // when we generated systemd service file with the --new param,
- // `ExecStart` will have `/usr/bin/podman run ...`
- // if `info.CreateCommand` has no `-d` or `--detach` param,
- // podman will run the container in default attached mode,
- // as a result, `systemd start` will wait the `podman run` command exit until failed with timeout error.
- hasDetachParam := false
- for _, p := range info.CreateCommand[index:] {
- if p == "--detach" || p == "-d" {
- hasDetachParam = true
- }
- }
- if !hasDetachParam {
- command = append(command, "-d")
- }
-
- command = append(command, info.CreateCommand[index:]...)
- info.RunCommand = strings.Join(command, " ")
- info.New = true
- }
-
- if info.PodmanVersion == "" {
- info.PodmanVersion = version.Version
- }
- if info.GenerateTimestamp {
- info.TimeStamp = fmt.Sprintf("%v", time.Now().Format(time.UnixDate))
- }
-
- // Sort the slices to assure a deterministic output.
- sort.Strings(info.RequiredServices)
- sort.Strings(info.BoundToServices)
-
- // Generate the template and compile it.
- templ, err := template.New("systemd_service_file").Parse(containerTemplate)
- if err != nil {
- return "", errors.Wrap(err, "error parsing systemd service template")
- }
-
- var buf bytes.Buffer
- if err := templ.Execute(&buf, info); err != nil {
- return "", err
- }
-
- if !opts.Files {
- return buf.String(), nil
- }
-
- buf.WriteByte('\n')
- cwd, err := os.Getwd()
- if err != nil {
- return "", errors.Wrap(err, "error getting current working directory")
- }
- path := filepath.Join(cwd, fmt.Sprintf("%s.service", info.ServiceName))
- if err := ioutil.WriteFile(path, buf.Bytes(), 0644); err != nil {
- return "", errors.Wrap(err, "error generating systemd unit")
- }
- return path, nil
-}
diff --git a/pkg/systemd/generate/systemdgen_test.go b/pkg/systemd/generate/systemdgen_test.go
deleted file mode 100644
index cc5db5e24..000000000
--- a/pkg/systemd/generate/systemdgen_test.go
+++ /dev/null
@@ -1,347 +0,0 @@
-package generate
-
-import (
- "testing"
-)
-
-func TestValidateRestartPolicy(t *testing.T) {
- type ContainerInfo struct {
- restart string
- }
- tests := []struct {
- name string
- ContainerInfo ContainerInfo
- wantErr bool
- }{
- {"good-on", ContainerInfo{restart: "no"}, false},
- {"good-on-success", ContainerInfo{restart: "on-success"}, false},
- {"good-on-failure", ContainerInfo{restart: "on-failure"}, false},
- {"good-on-abnormal", ContainerInfo{restart: "on-abnormal"}, false},
- {"good-on-watchdog", ContainerInfo{restart: "on-watchdog"}, false},
- {"good-on-abort", ContainerInfo{restart: "on-abort"}, false},
- {"good-always", ContainerInfo{restart: "always"}, false},
- {"fail", ContainerInfo{restart: "foobar"}, true},
- {"failblank", ContainerInfo{restart: ""}, true},
- }
- for _, tt := range tests {
- test := tt
- t.Run(tt.name, func(t *testing.T) {
- if err := validateRestartPolicy(test.ContainerInfo.restart); (err != nil) != test.wantErr {
- t.Errorf("ValidateRestartPolicy() error = %v, wantErr %v", err, test.wantErr)
- }
- })
- }
-}
-
-func TestCreateContainerSystemdUnit(t *testing.T) {
- goodID := `# container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.service
-# autogenerated by Podman CI
-
-[Unit]
-Description=Podman container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.service
-Documentation=man:podman-generate-systemd(1)
-Wants=network.target
-After=network-online.target
-
-[Service]
-Environment=PODMAN_SYSTEMD_UNIT=%n
-Restart=always
-ExecStart=/usr/bin/podman start 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
-ExecStop=/usr/bin/podman stop -t 10 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
-PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
-KillMode=none
-Type=forking
-
-[Install]
-WantedBy=multi-user.target default.target`
-
- goodName := `# container-foobar.service
-# autogenerated by Podman CI
-
-[Unit]
-Description=Podman container-foobar.service
-Documentation=man:podman-generate-systemd(1)
-Wants=network.target
-After=network-online.target
-
-[Service]
-Environment=PODMAN_SYSTEMD_UNIT=%n
-Restart=always
-ExecStart=/usr/bin/podman start foobar
-ExecStop=/usr/bin/podman stop -t 10 foobar
-PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
-KillMode=none
-Type=forking
-
-[Install]
-WantedBy=multi-user.target default.target`
-
- goodNameBoundTo := `# container-foobar.service
-# autogenerated by Podman CI
-
-[Unit]
-Description=Podman container-foobar.service
-Documentation=man:podman-generate-systemd(1)
-Wants=network.target
-After=network-online.target
-RefuseManualStart=yes
-RefuseManualStop=yes
-BindsTo=a.service b.service c.service pod.service
-After=a.service b.service c.service pod.service
-
-[Service]
-Environment=PODMAN_SYSTEMD_UNIT=%n
-Restart=always
-ExecStart=/usr/bin/podman start foobar
-ExecStop=/usr/bin/podman stop -t 10 foobar
-PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
-KillMode=none
-Type=forking
-
-[Install]
-WantedBy=multi-user.target default.target`
-
- podGoodName := `# 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=always
-ExecStart=/usr/bin/podman start jadda-jadda-infra
-ExecStop=/usr/bin/podman stop -t 10 jadda-jadda-infra
-PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
-KillMode=none
-Type=forking
-
-[Install]
-WantedBy=multi-user.target default.target`
-
- goodNameNew := `# 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
-ExecStartPre=/usr/bin/rm -f %t/%n-pid %t/%n-cid
-ExecStart=/usr/bin/podman run --conmon-pidfile %t/%n-pid --cidfile %t/%n-cid --cgroups=no-conmon -d --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN
-ExecStop=/usr/bin/podman stop --ignore --cidfile %t/%n-cid -t 42
-ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/%n-cid
-PIDFile=%t/%n-pid
-KillMode=none
-Type=forking
-
-[Install]
-WantedBy=multi-user.target default.target`
-
- goodNameNewDetach := `# 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
-ExecStartPre=/usr/bin/rm -f %t/%n-pid %t/%n-cid
-ExecStart=/usr/bin/podman run --conmon-pidfile %t/%n-pid --cidfile %t/%n-cid --cgroups=no-conmon --detach --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN
-ExecStop=/usr/bin/podman stop --ignore --cidfile %t/%n-cid -t 42
-ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/%n-cid
-PIDFile=%t/%n-pid
-KillMode=none
-Type=forking
-
-[Install]
-WantedBy=multi-user.target default.target`
-
- goodIDNew := `# container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.service
-# autogenerated by Podman CI
-
-[Unit]
-Description=Podman container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.service
-Documentation=man:podman-generate-systemd(1)
-Wants=network.target
-After=network-online.target
-
-[Service]
-Environment=PODMAN_SYSTEMD_UNIT=%n
-Restart=always
-ExecStartPre=/usr/bin/rm -f %t/%n-pid %t/%n-cid
-ExecStart=/usr/bin/podman run --conmon-pidfile %t/%n-pid --cidfile %t/%n-cid --cgroups=no-conmon -d awesome-image:latest
-ExecStop=/usr/bin/podman stop --ignore --cidfile %t/%n-cid -t 10
-ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/%n-cid
-PIDFile=%t/%n-pid
-KillMode=none
-Type=forking
-
-[Install]
-WantedBy=multi-user.target default.target`
-
- tests := []struct {
- name string
- info ContainerInfo
- want string
- wantErr bool
- }{
-
- {"good with id",
- ContainerInfo{
- Executable: "/usr/bin/podman",
- ServiceName: "container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
- ContainerName: "639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
- RestartPolicy: "always",
- PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 10,
- PodmanVersion: "CI",
- },
- goodID,
- false,
- },
- {"good with name",
- ContainerInfo{
- Executable: "/usr/bin/podman",
- ServiceName: "container-foobar",
- ContainerName: "foobar",
- RestartPolicy: "always",
- PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 10,
- PodmanVersion: "CI",
- },
- goodName,
- false,
- },
- {"good with name and bound to",
- ContainerInfo{
- Executable: "/usr/bin/podman",
- ServiceName: "container-foobar",
- ContainerName: "foobar",
- RestartPolicy: "always",
- PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 10,
- PodmanVersion: "CI",
- BoundToServices: []string{"pod", "a", "b", "c"},
- },
- goodNameBoundTo,
- false,
- },
- {"pod",
- ContainerInfo{
- Executable: "/usr/bin/podman",
- ServiceName: "pod-123abc",
- ContainerName: "jadda-jadda-infra",
- RestartPolicy: "always",
- PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 10,
- PodmanVersion: "CI",
- RequiredServices: []string{"container-1", "container-2"},
- },
- podGoodName,
- false,
- },
- {"bad restart policy",
- ContainerInfo{
- Executable: "/usr/bin/podman",
- ServiceName: "639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
- RestartPolicy: "never",
- PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 10,
- PodmanVersion: "CI",
- },
- "",
- true,
- },
- {"good with name and generic",
- ContainerInfo{
- Executable: "/usr/bin/podman",
- ServiceName: "jadda-jadda",
- ContainerName: "jadda-jadda",
- RestartPolicy: "always",
- PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 42,
- PodmanVersion: "CI",
- New: true,
- CreateCommand: []string{"I'll get stripped", "container", "run", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN"},
- },
- goodNameNew,
- false,
- },
- {"good with explicit short detach param",
- ContainerInfo{
- Executable: "/usr/bin/podman",
- ServiceName: "jadda-jadda",
- ContainerName: "jadda-jadda",
- RestartPolicy: "always",
- PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 42,
- PodmanVersion: "CI",
- New: true,
- CreateCommand: []string{"I'll get stripped", "container", "run", "-d", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN"},
- },
- goodNameNew,
- false,
- },
- {"good with explicit full detach param",
- ContainerInfo{
- Executable: "/usr/bin/podman",
- ServiceName: "jadda-jadda",
- ContainerName: "jadda-jadda",
- RestartPolicy: "always",
- PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 42,
- PodmanVersion: "CI",
- New: true,
- CreateCommand: []string{"I'll get stripped", "container", "run", "--detach", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN"},
- },
- goodNameNewDetach,
- false,
- },
- {"good with id and no param",
- ContainerInfo{
- Executable: "/usr/bin/podman",
- ServiceName: "container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
- ContainerName: "639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
- RestartPolicy: "always",
- PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- StopTimeout: 10,
- PodmanVersion: "CI",
- New: true,
- CreateCommand: []string{"I'll get stripped", "container", "run", "awesome-image:latest"},
- },
- goodIDNew,
- false,
- },
- }
- for _, tt := range tests {
- test := tt
- t.Run(tt.name, func(t *testing.T) {
- opts := Options{
- Files: false,
- New: test.info.New,
- }
- got, err := CreateContainerSystemdUnit(&test.info, opts)
- if (err != nil) != test.wantErr {
- 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)
- }
- })
- }
-}
diff --git a/pkg/util/mountOpts.go b/pkg/util/mountOpts.go
index 929223244..416e60728 100644
--- a/pkg/util/mountOpts.go
+++ b/pkg/util/mountOpts.go
@@ -28,8 +28,7 @@ func ProcessOptions(options []string, isTmpfs bool, sourcePath string) ([]string
foundWrite, foundSize, foundProp, foundMode, foundExec, foundSuid, foundDev, foundCopyUp, foundBind, foundZ bool
)
- var newOptions []string
-
+ newOptions := make([]string, 0, len(options))
for _, opt := range options {
// Some options have parameters - size, mode
splitOpt := strings.SplitN(opt, "=", 2)