summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/adapter/containers.go145
-rw-r--r--pkg/adapter/containers_remote.go2
-rw-r--r--pkg/adapter/pods.go10
-rw-r--r--pkg/adapter/runtime.go18
-rw-r--r--pkg/adapter/runtime_remote.go7
-rw-r--r--pkg/adapter/volumes_remote.go2
-rw-r--r--pkg/cgroups/cgroups.go8
-rw-r--r--pkg/firewall/common.go55
-rw-r--r--pkg/firewall/firewall_linux.go47
-rw-r--r--pkg/firewall/firewall_none.go43
-rw-r--r--pkg/firewall/firewall_unsupported.go27
-rw-r--r--pkg/firewall/firewalld.go122
-rw-r--r--pkg/firewall/iptables.go195
-rw-r--r--pkg/systemdgen/systemdgen.go147
-rw-r--r--pkg/systemdgen/systemdgen_test.go180
-rw-r--r--pkg/util/utils_supported.go6
-rw-r--r--pkg/util/utils_windows.go8
-rw-r--r--pkg/varlinkapi/containers.go15
-rw-r--r--pkg/varlinkapi/generate.go23
-rw-r--r--pkg/varlinkapi/images.go26
-rw-r--r--pkg/varlinkapi/volumes.go1
21 files changed, 456 insertions, 631 deletions
diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go
index 45a9a54a3..41607145d 100644
--- a/pkg/adapter/containers.go
+++ b/pkg/adapter/containers.go
@@ -342,7 +342,8 @@ func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode
if err := ctr.Start(ctx, c.IsSet("pod")); err != nil {
// This means the command did not exist
exitCode = 127
- if strings.Contains(err.Error(), "permission denied") || strings.Contains(err.Error(), "file not found") {
+ e := strings.ToLower(err.Error())
+ if strings.Contains(e, "permission denied") || strings.Contains(e, "operation not permitted") || strings.Contains(e, "file not found") || strings.Contains(e, "no such file or directory") {
exitCode = 126
}
return exitCode, err
@@ -405,12 +406,13 @@ func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode
}
// This means the command did not exist
exitCode = 127
- if strings.Contains(err.Error(), "permission denied") {
+ e := strings.ToLower(err.Error())
+ if strings.Contains(e, "permission denied") || strings.Contains(e, "operation not permitted") {
exitCode = 126
}
if c.IsSet("rm") {
if deleteError := r.Runtime.RemoveContainer(ctx, ctr, true, false); deleteError != nil {
- logrus.Errorf("unable to remove container %s after failing to start and attach to it", ctr.ID())
+ logrus.Debugf("unable to remove container %s after failing to start and attach to it", ctr.ID())
}
}
return exitCode, err
@@ -1092,28 +1094,145 @@ func (r *LocalRuntime) Port(c *cliconfig.PortValues) ([]*Container, error) {
return portContainers, nil
}
-// GenerateSystemd creates a unit file for a container
-func (r *LocalRuntime) GenerateSystemd(c *cliconfig.GenerateSystemdValues) (string, error) {
- ctr, err := r.Runtime.LookupContainer(c.InputArgs[0])
+// generateServiceName generates the container name and the service name for systemd service.
+func generateServiceName(c *cliconfig.GenerateSystemdValues, ctr *libpod.Container, pod *libpod.Pod) (string, string) {
+ var kind, name, ctrName string
+ if pod == nil {
+ kind = "container"
+ name = ctr.ID()
+ if c.Name {
+ name = ctr.Name()
+ }
+ ctrName = name
+ } else {
+ kind = "pod"
+ name = pod.ID()
+ ctrName = ctr.ID()
+ if c.Name {
+ name = pod.Name()
+ ctrName = ctr.Name()
+ }
+ }
+ return ctrName, fmt.Sprintf("%s-%s", kind, name)
+}
+
+// generateSystemdgenContainerInfo is a helper to generate a
+// systemdgen.ContainerInfo for `GenerateSystemd`.
+func (r *LocalRuntime) generateSystemdgenContainerInfo(c *cliconfig.GenerateSystemdValues, nameOrID string, pod *libpod.Pod) (*systemdgen.ContainerInfo, bool, error) {
+ ctr, err := r.Runtime.LookupContainer(nameOrID)
if err != nil {
- return "", err
+ return nil, false, err
}
+
timeout := int(ctr.StopTimeout())
if c.StopTimeout >= 0 {
timeout = c.StopTimeout
}
- name := ctr.ID()
- if c.Name {
- name = ctr.Name()
- }
config := ctr.Config()
conmonPidFile := config.ConmonPidFile
if conmonPidFile == "" {
- return "", errors.Errorf("conmon PID file path is empty, try to recreate the container with --conmon-pidfile flag")
+ return nil, true, errors.Errorf("conmon PID file path is empty, try to recreate the container with --conmon-pidfile flag")
+ }
+
+ name, serviceName := generateServiceName(c, ctr, pod)
+ info := &systemdgen.ContainerInfo{
+ ServiceName: serviceName,
+ ContainerName: name,
+ RestartPolicy: c.RestartPolicy,
+ PIDFile: conmonPidFile,
+ StopTimeout: timeout,
+ GenerateTimestamp: true,
+ }
+
+ return info, true, nil
+}
+
+// GenerateSystemd creates a unit file for a container or pod.
+func (r *LocalRuntime) GenerateSystemd(c *cliconfig.GenerateSystemdValues) (string, error) {
+ // First assume it's a container.
+ if info, found, err := r.generateSystemdgenContainerInfo(c, c.InputArgs[0], nil); found && err != nil {
+ return "", err
+ } else if found && err == nil {
+ return systemdgen.CreateContainerSystemdUnit(info, c.Files)
+ }
+
+ // We're either having a pod or garbage.
+ pod, err := r.Runtime.LookupPod(c.InputArgs[0])
+ if err != nil {
+ return "", err
+ }
+
+ // Error out if the pod has no infra container, which we require to be the
+ // main service.
+ if !pod.HasInfraContainer() {
+ return "", fmt.Errorf("error generating systemd unit files: Pod %q has no infra container", pod.Name())
+ }
+
+ // 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
+ }
+ podInfo, _, err := r.generateSystemdgenContainerInfo(c, infraID, pod)
+ if err != nil {
+ return "", nil
+ }
+
+ // Compute the container-dependency graph for the Pod.
+ containers, err := pod.AllContainers()
+ if err != nil {
+ return "", err
+ }
+ if len(containers) == 0 {
+ return "", fmt.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 := []*systemdgen.ContainerInfo{podInfo}
+ for ctr, dependencies := range graph.DependencyMap() {
+ // Skip the infra container as we already generated it.
+ if ctr.ID() == infraID {
+ continue
+ }
+ ctrInfo, _, err := r.generateSystemdgenContainerInfo(c, ctr.ID(), nil)
+ 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 := generateServiceName(c, dep, nil)
+ 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 := systemdgen.CreateContainerSystemdUnit(info, c.Files)
+ if err != nil {
+ return "", err
+ }
+ builder.WriteString(out)
}
- return systemdgen.CreateSystemdUnitAsString(name, ctr.ID(), c.RestartPolicy, conmonPidFile, timeout)
+ return builder.String(), nil
}
// GetNamespaces returns namespace information about a container for PS
diff --git a/pkg/adapter/containers_remote.go b/pkg/adapter/containers_remote.go
index 5a26f537f..590fef43f 100644
--- a/pkg/adapter/containers_remote.go
+++ b/pkg/adapter/containers_remote.go
@@ -951,7 +951,7 @@ func (r *LocalRuntime) Port(c *cliconfig.PortValues) ([]*Container, error) {
// GenerateSystemd creates a systemd until for a container
func (r *LocalRuntime) GenerateSystemd(c *cliconfig.GenerateSystemdValues) (string, error) {
- return iopodman.GenerateSystemd().Call(r.Conn, c.InputArgs[0], c.RestartPolicy, int64(c.StopTimeout), c.Name)
+ return "", errors.New("systemd generation not supported for remote clients")
}
// GetNamespaces returns namespace information about a container for PS
diff --git a/pkg/adapter/pods.go b/pkg/adapter/pods.go
index 1dd72babf..ded805de2 100644
--- a/pkg/adapter/pods.go
+++ b/pkg/adapter/pods.go
@@ -256,6 +256,10 @@ func (r *LocalRuntime) CreatePod(ctx context.Context, cli *cliconfig.PodCreateVa
options = append(options, libpod.WithPodName(cli.Name))
}
+ if cli.Flag("hostname").Changed {
+ options = append(options, libpod.WithPodHostname(cli.Hostname))
+ }
+
if cli.Infra {
options = append(options, libpod.WithInfraContainer())
nsOptions, err := shared.GetNamespaceOptions(strings.Split(cli.Share, ","))
@@ -476,6 +480,12 @@ func (r *LocalRuntime) PlayKubeYAML(ctx context.Context, c *cliconfig.KubePlayVa
podOptions = append(podOptions, 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
+ if hostname == "" {
+ hostname = podName
+ }
+ podOptions = append(podOptions, libpod.WithPodHostname(hostname))
+
nsOptions, err := shared.GetNamespaceOptions(strings.Split(shared.DefaultKernelNamespaces, ","))
if err != nil {
return nil, err
diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go
index ba988aaf7..0537308f8 100644
--- a/pkg/adapter/runtime.go
+++ b/pkg/adapter/runtime.go
@@ -201,16 +201,16 @@ func (r *LocalRuntime) RemoveVolumes(ctx context.Context, c *cliconfig.VolumeRmV
}
// Push is a wrapper to push an image to a registry
-func (r *LocalRuntime) Push(ctx context.Context, srcName, destination, manifestMIMEType, authfile, signaturePolicyPath string, writer io.Writer, forceCompress bool, signingOptions image.SigningOptions, dockerRegistryOptions *image.DockerRegistryOptions, additionalDockerArchiveTags []reference.NamedTagged) error {
+func (r *LocalRuntime) Push(ctx context.Context, srcName, destination, manifestMIMEType, authfile, digestfile, signaturePolicyPath string, writer io.Writer, forceCompress bool, signingOptions image.SigningOptions, dockerRegistryOptions *image.DockerRegistryOptions, additionalDockerArchiveTags []reference.NamedTagged) error {
newImage, err := r.ImageRuntime().NewFromLocal(srcName)
if err != nil {
return err
}
- return newImage.PushImageToHeuristicDestination(ctx, destination, manifestMIMEType, authfile, signaturePolicyPath, writer, forceCompress, signingOptions, dockerRegistryOptions, nil)
+ return newImage.PushImageToHeuristicDestination(ctx, destination, manifestMIMEType, authfile, digestfile, signaturePolicyPath, writer, forceCompress, signingOptions, dockerRegistryOptions, nil)
}
// InspectVolumes returns a slice of volumes based on an arg list or --all
-func (r *LocalRuntime) InspectVolumes(ctx context.Context, c *cliconfig.VolumeInspectValues) ([]*Volume, error) {
+func (r *LocalRuntime) InspectVolumes(ctx context.Context, c *cliconfig.VolumeInspectValues) ([]*libpod.InspectVolumeData, error) {
var (
volumes []*libpod.Volume
err error
@@ -230,7 +230,17 @@ func (r *LocalRuntime) InspectVolumes(ctx context.Context, c *cliconfig.VolumeIn
if err != nil {
return nil, err
}
- return libpodVolumeToVolume(volumes), nil
+
+ inspectVols := make([]*libpod.InspectVolumeData, 0, len(volumes))
+ for _, vol := range volumes {
+ inspectOut, err := vol.Inspect()
+ if err != nil {
+ return nil, errors.Wrapf(err, "error inspecting volume %s", vol.Name())
+ }
+ inspectVols = append(inspectVols, inspectOut)
+ }
+
+ return inspectVols, nil
}
// Volumes returns a slice of localruntime volumes
diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go
index 420c9d0bb..8588966b6 100644
--- a/pkg/adapter/runtime_remote.go
+++ b/pkg/adapter/runtime_remote.go
@@ -21,7 +21,7 @@ import (
"github.com/containers/image/types"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/remoteclientconfig"
- "github.com/containers/libpod/cmd/podman/varlink"
+ iopodman "github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/libpod/events"
@@ -619,7 +619,7 @@ func (r *LocalRuntime) RemoveVolumes(ctx context.Context, c *cliconfig.VolumeRmV
return iopodman.VolumeRemove().Call(r.Conn, rmOpts)
}
-func (r *LocalRuntime) Push(ctx context.Context, srcName, destination, manifestMIMEType, authfile, signaturePolicyPath string, writer io.Writer, forceCompress bool, signingOptions image.SigningOptions, dockerRegistryOptions *image.DockerRegistryOptions, additionalDockerArchiveTags []reference.NamedTagged) error {
+func (r *LocalRuntime) Push(ctx context.Context, srcName, destination, manifestMIMEType, authfile, digestfile, signaturePolicyPath string, writer io.Writer, forceCompress bool, signingOptions image.SigningOptions, dockerRegistryOptions *image.DockerRegistryOptions, additionalDockerArchiveTags []reference.NamedTagged) error {
reply, err := iopodman.PushImage().Send(r.Conn, varlink.More, srcName, destination, forceCompress, manifestMIMEType, signingOptions.RemoveSignatures, signingOptions.SignBy)
if err != nil {
@@ -669,7 +669,6 @@ func varlinkVolumeToVolume(r *LocalRuntime, volumes []iopodman.Volume) []*Volume
MountPoint: v.MountPoint,
Driver: v.Driver,
Options: v.Options,
- Scope: v.Scope,
}
n := remoteVolume{
Runtime: r,
@@ -813,7 +812,7 @@ func IsImageNotFound(err error) bool {
// HealthCheck executes a container's healthcheck over a varlink connection
func (r *LocalRuntime) HealthCheck(c *cliconfig.HealthCheckValues) (string, error) {
- return "", define.ErrNotImplemented
+ return iopodman.HealthCheckRun().Call(r.Conn, c.InputArgs[0])
}
// Events monitors libpod/podman events over a varlink connection
diff --git a/pkg/adapter/volumes_remote.go b/pkg/adapter/volumes_remote.go
index beacd943a..58f9ba625 100644
--- a/pkg/adapter/volumes_remote.go
+++ b/pkg/adapter/volumes_remote.go
@@ -29,5 +29,5 @@ func (v *Volume) MountPoint() string {
// Scope returns the scope for an adapter.volume
func (v *Volume) Scope() string {
- return v.config.Scope
+ return "local"
}
diff --git a/pkg/cgroups/cgroups.go b/pkg/cgroups/cgroups.go
index 085718855..9711e8120 100644
--- a/pkg/cgroups/cgroups.go
+++ b/pkg/cgroups/cgroups.go
@@ -10,6 +10,7 @@ import (
"strconv"
"strings"
+ "github.com/containers/libpod/pkg/rootless"
systemdDbus "github.com/coreos/go-systemd/dbus"
"github.com/godbus/dbus"
spec "github.com/opencontainers/runtime-spec/specs-go"
@@ -19,7 +20,9 @@ import (
var (
// ErrCgroupDeleted means the cgroup was deleted
- ErrCgroupDeleted = errors.New("cgroups: cgroup deleted")
+ ErrCgroupDeleted = errors.New("cgroup deleted")
+ // ErrCgroupV1Rootless means the cgroup v1 were attempted to be used in rootless environmen
+ ErrCgroupV1Rootless = errors.New("no support for CGroups V1 in rootless environments")
)
// CgroupControl controls a cgroup hierarchy
@@ -339,6 +342,9 @@ func Load(path string) (*CgroupControl, error) {
p := control.getCgroupv1Path(name)
if _, err := os.Stat(p); err != nil {
if os.IsNotExist(err) {
+ if rootless.IsRootless() {
+ return nil, ErrCgroupV1Rootless
+ }
// compatible with the error code
// used by containerd/cgroups
return nil, ErrCgroupDeleted
diff --git a/pkg/firewall/common.go b/pkg/firewall/common.go
deleted file mode 100644
index a65d4f03d..000000000
--- a/pkg/firewall/common.go
+++ /dev/null
@@ -1,55 +0,0 @@
-package firewall
-
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-import (
- "net"
-
- "github.com/containernetworking/cni/pkg/types/current"
-)
-
-// FirewallNetConf represents the firewall configuration.
-// Nolint applied for firewall.Firewall... name duplication notice.
-//nolint
-type FirewallNetConf struct {
- //types.NetConf
-
- // IptablesAdminChainName is an optional name to use instead of the default
- // admin rules override chain name that includes the interface name.
- IptablesAdminChainName string
-
- // FirewalldZone is an optional firewalld zone to place the interface into. If
- // the firewalld backend is used but the zone is not given, it defaults
- // to 'trusted'
- FirewalldZone string
-
- PrevResult *current.Result
-}
-
-// FirewallBackend is an interface to the system firewall, allowing addition and
-// removal of firewall rules.
-// Nolint applied for firewall.Firewall... name duplication notice.
-//nolint
-type FirewallBackend interface {
- Add(*FirewallNetConf) error
- Del(*FirewallNetConf) error
-}
-
-func ipString(ip net.IPNet) string {
- if ip.IP.To4() == nil {
- return ip.IP.String() + "/128"
- }
- return ip.IP.String() + "/32"
-}
diff --git a/pkg/firewall/firewall_linux.go b/pkg/firewall/firewall_linux.go
deleted file mode 100644
index 4ac45427b..000000000
--- a/pkg/firewall/firewall_linux.go
+++ /dev/null
@@ -1,47 +0,0 @@
-// +build linux
-
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package firewall
-
-import (
- "fmt"
-)
-
-// GetBackend retrieves a firewall backend for adding or removing firewall rules
-// on the system.
-// Valid backend names are firewalld, iptables, and none.
-// If the empty string is given, a firewalld backend will be returned if
-// firewalld is running, and an iptables backend will be returned otherwise.
-func GetBackend(backend string) (FirewallBackend, error) {
- switch backend {
- case "firewalld":
- return newFirewalldBackend()
- case "iptables":
- return newIptablesBackend()
- case "none":
- return newNoneBackend()
- case "":
- // Default to firewalld if it's running
- if isFirewalldRunning() {
- return newFirewalldBackend()
- }
-
- // Otherwise iptables
- return newIptablesBackend()
- default:
- return nil, fmt.Errorf("unrecognized firewall backend %q", backend)
- }
-}
diff --git a/pkg/firewall/firewall_none.go b/pkg/firewall/firewall_none.go
deleted file mode 100644
index 9add24842..000000000
--- a/pkg/firewall/firewall_none.go
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package firewall
-
-import (
- "fmt"
-)
-
-// FirewallNone is a firewall backend for environments where manipulating the
-// system firewall is unsupported (for example, when running without root).
-// Nolint applied to avoid firewall.FirewallNone name duplication notes.
-//nolint
-type FirewallNone struct{}
-
-func newNoneBackend() (FirewallBackend, error) {
- return &FirewallNone{}, nil
-}
-
-// Add adds a rule to the system firewall.
-// No action is taken and an error is unconditionally returned as this backend
-// does not support manipulating the firewall.
-func (f *FirewallNone) Add(conf *FirewallNetConf) error {
- return fmt.Errorf("cannot modify system firewall rules")
-}
-
-// Del deletes a rule from the system firewall.
-// No action is taken and an error is unconditionally returned as this backend
-// does not support manipulating the firewall.
-func (f *FirewallNone) Del(conf *FirewallNetConf) error {
- return fmt.Errorf("cannot modify system firewall rules")
-}
diff --git a/pkg/firewall/firewall_unsupported.go b/pkg/firewall/firewall_unsupported.go
deleted file mode 100644
index 24c07a8a9..000000000
--- a/pkg/firewall/firewall_unsupported.go
+++ /dev/null
@@ -1,27 +0,0 @@
-// +build !linux
-
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package firewall
-
-import (
- "fmt"
-)
-
-// GetBackend retrieves a firewall backend for adding or removing firewall rules
-// on the system.
-func GetBackend(backend string) (FirewallBackend, error) {
- return nil, fmt.Errorf("firewall backends are not presently supported on this OS")
-}
diff --git a/pkg/firewall/firewalld.go b/pkg/firewall/firewalld.go
deleted file mode 100644
index 15e845cb7..000000000
--- a/pkg/firewall/firewalld.go
+++ /dev/null
@@ -1,122 +0,0 @@
-// +build linux
-
-// Copyright 2018 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package firewall
-
-import (
- "fmt"
- "github.com/sirupsen/logrus"
- "strings"
-
- "github.com/godbus/dbus"
-)
-
-const (
- dbusName = "org.freedesktop.DBus"
- dbusPath = "/org/freedesktop/DBus"
- dbusGetNameOwnerMethod = "GetNameOwner"
-
- firewalldName = "org.fedoraproject.FirewallD1"
- firewalldPath = "/org/fedoraproject/FirewallD1"
- firewalldZoneInterface = "org.fedoraproject.FirewallD1.zone"
- firewalldAddSourceMethod = "addSource"
- firewalldRemoveSourceMethod = "removeSource"
-
- errZoneAlreadySet = "ZONE_ALREADY_SET"
-)
-
-// Only used for testcases to override the D-Bus connection
-var testConn *dbus.Conn
-
-type fwdBackend struct {
- conn *dbus.Conn
-}
-
-// fwdBackend implements the FirewallBackend interface
-var _ FirewallBackend = &fwdBackend{}
-
-func getConn() (*dbus.Conn, error) {
- if testConn != nil {
- return testConn, nil
- }
- return dbus.SystemBus()
-}
-
-// isFirewalldRunning checks whether firewalld is running.
-func isFirewalldRunning() bool {
- conn, err := getConn()
- if err != nil {
- return false
- }
-
- dbusObj := conn.Object(dbusName, dbusPath)
- var res string
- if err := dbusObj.Call(dbusName+"."+dbusGetNameOwnerMethod, 0, firewalldName).Store(&res); err != nil {
- return false
- }
-
- return true
-}
-
-func newFirewalldBackend() (FirewallBackend, error) {
- conn, err := getConn()
- if err != nil {
- return nil, err
- }
-
- backend := &fwdBackend{
- conn: conn,
- }
- return backend, nil
-}
-
-func getFirewalldZone(conf *FirewallNetConf) string {
- if conf.FirewalldZone != "" {
- return conf.FirewalldZone
- }
-
- return "trusted"
-}
-
-func (fb *fwdBackend) Add(conf *FirewallNetConf) error {
- zone := getFirewalldZone(conf)
-
- for _, ip := range conf.PrevResult.IPs {
- ipStr := ipString(ip.Address)
- // Add a firewalld rule which assigns the given source IP to the given zone
- firewalldObj := fb.conn.Object(firewalldName, firewalldPath)
- var res string
- if err := firewalldObj.Call(firewalldZoneInterface+"."+firewalldAddSourceMethod, 0, zone, ipStr).Store(&res); err != nil {
- if !strings.Contains(err.Error(), errZoneAlreadySet) {
- return fmt.Errorf("failed to add the address %v to %v zone: %v", ipStr, zone, err)
- }
- }
- }
- return nil
-}
-
-func (fb *fwdBackend) Del(conf *FirewallNetConf) error {
- for _, ip := range conf.PrevResult.IPs {
- ipStr := ipString(ip.Address)
- // Remove firewalld rules which assigned the given source IP to the given zone
- firewalldObj := fb.conn.Object(firewalldName, firewalldPath)
- var res string
- if err := firewalldObj.Call(firewalldZoneInterface+"."+firewalldRemoveSourceMethod, 0, getFirewalldZone(conf), ipStr).Store(&res); err != nil {
- logrus.Errorf("unable to store firewallobj")
- }
- }
- return nil
-}
diff --git a/pkg/firewall/iptables.go b/pkg/firewall/iptables.go
deleted file mode 100644
index 169ddc1d7..000000000
--- a/pkg/firewall/iptables.go
+++ /dev/null
@@ -1,195 +0,0 @@
-// +build linux
-
-// Copyright 2016 CNI authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// This is a "meta-plugin". It reads in its own netconf, it does not create
-// any network interface but just changes the network sysctl.
-
-package firewall
-
-import (
- "fmt"
- "github.com/sirupsen/logrus"
- "net"
-
- "github.com/coreos/go-iptables/iptables"
-)
-
-func getPrivChainRules(ip string) [][]string {
- var rules [][]string
- rules = append(rules, []string{"-d", ip, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"})
- rules = append(rules, []string{"-s", ip, "-j", "ACCEPT"})
- return rules
-}
-
-func ensureChain(ipt *iptables.IPTables, table, chain string) error {
- chains, err := ipt.ListChains(table)
- if err != nil {
- return fmt.Errorf("failed to list iptables chains: %v", err)
- }
- for _, ch := range chains {
- if ch == chain {
- return nil
- }
- }
-
- return ipt.NewChain(table, chain)
-}
-
-func generateFilterRule(privChainName string) []string {
- return []string{"-m", "comment", "--comment", "CNI firewall plugin rules", "-j", privChainName}
-}
-
-func cleanupRules(ipt *iptables.IPTables, privChainName string, rules [][]string) {
- for _, rule := range rules {
- if err := ipt.Delete("filter", privChainName, rule...); err != nil {
- logrus.Errorf("failed to delete iptables rule %s", privChainName)
- }
- }
-}
-
-func ensureFirstChainRule(ipt *iptables.IPTables, chain string, rule []string) error {
- exists, err := ipt.Exists("filter", chain, rule...)
- if !exists && err == nil {
- err = ipt.Insert("filter", chain, 1, rule...)
- }
- return err
-}
-
-func (ib *iptablesBackend) setupChains(ipt *iptables.IPTables) error {
- privRule := generateFilterRule(ib.privChainName)
- adminRule := generateFilterRule(ib.adminChainName)
-
- // Ensure our private chains exist
- if err := ensureChain(ipt, "filter", ib.privChainName); err != nil {
- return err
- }
- if err := ensureChain(ipt, "filter", ib.adminChainName); err != nil {
- return err
- }
-
- // Ensure our filter rule exists in the forward chain
- if err := ensureFirstChainRule(ipt, "FORWARD", privRule); err != nil {
- return err
- }
-
- // Ensure our admin override chain rule exists in our private chain
- if err := ensureFirstChainRule(ipt, ib.privChainName, adminRule); err != nil {
- return err
- }
-
- return nil
-}
-
-func protoForIP(ip net.IPNet) iptables.Protocol {
- if ip.IP.To4() != nil {
- return iptables.ProtocolIPv4
- }
- return iptables.ProtocolIPv6
-}
-
-func (ib *iptablesBackend) addRules(conf *FirewallNetConf, ipt *iptables.IPTables, proto iptables.Protocol) error {
- rules := make([][]string, 0)
- for _, ip := range conf.PrevResult.IPs {
- if protoForIP(ip.Address) == proto {
- rules = append(rules, getPrivChainRules(ipString(ip.Address))...)
- }
- }
-
- if len(rules) > 0 {
- if err := ib.setupChains(ipt); err != nil {
- return err
- }
-
- // Clean up on any errors
- var err error
- defer func() {
- if err != nil {
- cleanupRules(ipt, ib.privChainName, rules)
- }
- }()
-
- for _, rule := range rules {
- err = ipt.AppendUnique("filter", ib.privChainName, rule...)
- if err != nil {
- return err
- }
- }
- }
-
- return nil
-}
-
-func (ib *iptablesBackend) delRules(conf *FirewallNetConf, ipt *iptables.IPTables, proto iptables.Protocol) error {
- rules := make([][]string, 0)
- for _, ip := range conf.PrevResult.IPs {
- if protoForIP(ip.Address) == proto {
- rules = append(rules, getPrivChainRules(ipString(ip.Address))...)
- }
- }
-
- if len(rules) > 0 {
- cleanupRules(ipt, ib.privChainName, rules)
- }
-
- return nil
-}
-
-type iptablesBackend struct {
- protos map[iptables.Protocol]*iptables.IPTables
- privChainName string
- adminChainName string
-}
-
-// iptablesBackend implements the FirewallBackend interface
-var _ FirewallBackend = &iptablesBackend{}
-
-func newIptablesBackend() (FirewallBackend, error) {
- adminChainName := "CNI-ADMIN"
-
- backend := &iptablesBackend{
- privChainName: "CNI-FORWARD",
- adminChainName: adminChainName,
- protos: make(map[iptables.Protocol]*iptables.IPTables),
- }
-
- for _, proto := range []iptables.Protocol{iptables.ProtocolIPv4, iptables.ProtocolIPv6} {
- ipt, err := iptables.NewWithProtocol(proto)
- if err != nil {
- return nil, fmt.Errorf("could not initialize iptables protocol %v: %v", proto, err)
- }
- backend.protos[proto] = ipt
- }
-
- return backend, nil
-}
-
-func (ib *iptablesBackend) Add(conf *FirewallNetConf) error {
- for proto, ipt := range ib.protos {
- if err := ib.addRules(conf, ipt, proto); err != nil {
- return err
- }
- }
- return nil
-}
-
-func (ib *iptablesBackend) Del(conf *FirewallNetConf) error {
- for proto, ipt := range ib.protos {
- if err := ib.delRules(conf, ipt, proto); err != nil {
- logrus.Errorf("failed to delete iptables backend rule %s", conf.IptablesAdminChainName)
- }
- }
- return nil
-}
diff --git a/pkg/systemdgen/systemdgen.go b/pkg/systemdgen/systemdgen.go
index 06c5ebde5..09d3c6fd5 100644
--- a/pkg/systemdgen/systemdgen.go
+++ b/pkg/systemdgen/systemdgen.go
@@ -1,29 +1,59 @@
package systemdgen
import (
+ "bytes"
"fmt"
+ "io/ioutil"
"os"
+ "path/filepath"
+ "sort"
+ "text/template"
+ "time"
+ "github.com/containers/libpod/version"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
-var template = `[Unit]
-Description=%s Podman Container
-[Service]
-Restart=%s
-ExecStart=%s start %s
-ExecStop=%s stop -t %d %s
-KillMode=none
-Type=forking
-PIDFile=%s
-[Install]
-WantedBy=multi-user.target`
+// 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 int
+ // 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
+}
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 {
+// validateRestartPolicy checks that the user-provided policy is valid.
+func validateRestartPolicy(restart string) error {
for _, i := range restartPolicies {
if i == restart {
return nil
@@ -32,28 +62,87 @@ func ValidateRestartPolicy(restart string) error {
return errors.Errorf("%s is not a valid restart policy", restart)
}
-// CreateSystemdUnitAsString takes variables to create a systemd unit file used to control
-// a libpod container
-func CreateSystemdUnitAsString(name, cid, restart, pidFile string, stopTimeout int) (string, error) {
- podmanExe := getPodmanExecutable()
- return createSystemdUnitAsString(podmanExe, name, cid, restart, pidFile, stopTimeout)
-}
+const containerTemplate = `# {{.ServiceName}}.service
+# autogenerated by Podman {{.PodmanVersion}}
+{{- if .TimeStamp}}
+# {{.TimeStamp}}
+{{- end}}
+
+[Unit]
+Description=Podman {{.ServiceName}}.service
+Documentation=man:podman-generate-systemd(1)
+{{- 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]
+Restart={{.RestartPolicy}}
+ExecStart={{.Executable}} start {{.ContainerName}}
+ExecStop={{.Executable}} stop {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}} {{.ContainerName}}
+KillMode=none
+Type=forking
+PIDFile={{.PIDFile}}
+
+[Install]
+WantedBy=multi-user.target`
-func createSystemdUnitAsString(exe, name, cid, restart, pidFile string, stopTimeout int) (string, error) {
- if err := ValidateRestartPolicy(restart); err != nil {
+// CreateContainerSystemdUnit creates a systemd unit file for a container.
+func CreateContainerSystemdUnit(info *ContainerInfo, generateFiles bool) (string, error) {
+ if err := validateRestartPolicy(info.RestartPolicy); err != nil {
return "", err
}
- unit := fmt.Sprintf(template, name, restart, exe, name, exe, stopTimeout, name, pidFile)
- return unit, nil
-}
+ // 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
+ }
+
+ if info.PodmanVersion == "" {
+ info.PodmanVersion = version.Version
+ }
+ if info.GenerateTimestamp {
+ info.TimeStamp = fmt.Sprintf("%v", time.Now().Format(time.UnixDate))
+ }
-func getPodmanExecutable() string {
- podmanExe, err := os.Executable()
+ // 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 {
- podmanExe = "/usr/bin/podman"
- logrus.Warnf("Could not obtain podman executable location, using default %s", podmanExe)
+ return "", errors.Wrap(err, "error parsing systemd service template")
}
- return podmanExe
+ var buf bytes.Buffer
+ if err := templ.Execute(&buf, info); err != nil {
+ return "", err
+ }
+
+ if !generateFiles {
+ 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/systemdgen/systemdgen_test.go b/pkg/systemdgen/systemdgen_test.go
index e413b24ce..1ddb0c514 100644
--- a/pkg/systemdgen/systemdgen_test.go
+++ b/pkg/systemdgen/systemdgen_test.go
@@ -5,36 +5,41 @@ import (
)
func TestValidateRestartPolicy(t *testing.T) {
- type args struct {
+ type ContainerInfo struct {
restart string
}
tests := []struct {
- name string
- args args
- wantErr bool
+ name string
+ ContainerInfo ContainerInfo
+ wantErr bool
}{
- {"good-on", args{restart: "no"}, false},
- {"good-on-success", args{restart: "on-success"}, false},
- {"good-on-failure", args{restart: "on-failure"}, false},
- {"good-on-abnormal", args{restart: "on-abnormal"}, false},
- {"good-on-watchdog", args{restart: "on-watchdog"}, false},
- {"good-on-abort", args{restart: "on-abort"}, false},
- {"good-always", args{restart: "always"}, false},
- {"fail", args{restart: "foobar"}, true},
- {"failblank", args{restart: ""}, true},
+ {"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 {
t.Run(tt.name, func(t *testing.T) {
- if err := ValidateRestartPolicy(tt.args.restart); (err != nil) != tt.wantErr {
+ if err := validateRestartPolicy(tt.ContainerInfo.restart); (err != nil) != tt.wantErr {
t.Errorf("ValidateRestartPolicy() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
-func TestCreateSystemdUnitAsString(t *testing.T) {
- goodID := `[Unit]
-Description=639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401 Podman Container
+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)
+
[Service]
Restart=always
ExecStart=/usr/bin/podman start 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
@@ -42,11 +47,17 @@ ExecStop=/usr/bin/podman stop -t 10 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6
KillMode=none
Type=forking
PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
+
[Install]
WantedBy=multi-user.target`
- goodName := `[Unit]
-Description=foobar Podman Container
+ goodName := `# container-foobar.service
+# autogenerated by Podman CI
+
+[Unit]
+Description=Podman container-foobar.service
+Documentation=man:podman-generate-systemd(1)
+
[Service]
Restart=always
ExecStart=/usr/bin/podman start foobar
@@ -54,56 +65,121 @@ ExecStop=/usr/bin/podman stop -t 10 foobar
KillMode=none
Type=forking
PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
+
+[Install]
+WantedBy=multi-user.target`
+
+ goodNameBoundTo := `# container-foobar.service
+# autogenerated by Podman CI
+
+[Unit]
+Description=Podman container-foobar.service
+Documentation=man:podman-generate-systemd(1)
+RefuseManualStart=yes
+RefuseManualStop=yes
+BindsTo=a.service b.service c.service pod.service
+After=a.service b.service c.service pod.service
+
+[Service]
+Restart=always
+ExecStart=/usr/bin/podman start foobar
+ExecStop=/usr/bin/podman stop -t 10 foobar
+KillMode=none
+Type=forking
+PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
+
+[Install]
+WantedBy=multi-user.target`
+
+ podGoodName := `# pod-123abc.service
+# autogenerated by Podman CI
+
+[Unit]
+Description=Podman pod-123abc.service
+Documentation=man:podman-generate-systemd(1)
+Requires=container-1.service container-2.service
+Before=container-1.service container-2.service
+
+[Service]
+Restart=always
+ExecStart=/usr/bin/podman start jadda-jadda-infra
+ExecStop=/usr/bin/podman stop -t 10 jadda-jadda-infra
+KillMode=none
+Type=forking
+PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid
+
[Install]
WantedBy=multi-user.target`
- type args struct {
- exe string
- name string
- cid string
- restart string
- pidFile string
- stopTimeout int
- }
tests := []struct {
name string
- args args
+ info ContainerInfo
want string
wantErr bool
}{
{"good with id",
- args{
- "/usr/bin/podman",
- "639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
- "639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
- "always",
- "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- 10,
+ 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",
- args{
- "/usr/bin/podman",
- "foobar",
- "639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
- "always",
- "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- 10,
+ 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",
- args{
- "/usr/bin/podman",
- "639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
- "639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
- "never",
- "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
- 10,
+ 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,
@@ -111,13 +187,13 @@ WantedBy=multi-user.target`
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- got, err := createSystemdUnitAsString(tt.args.exe, tt.args.name, tt.args.cid, tt.args.restart, tt.args.pidFile, tt.args.stopTimeout)
+ got, err := CreateContainerSystemdUnit(&tt.info, false)
if (err != nil) != tt.wantErr {
- t.Errorf("CreateSystemdUnitAsString() error = %v, wantErr %v", err, tt.wantErr)
+ t.Errorf("CreateContainerSystemdUnit() error = \n%v, wantErr \n%v", err, tt.wantErr)
return
}
if got != tt.want {
- t.Errorf("CreateSystemdUnitAsString() = %v, want %v", got, tt.want)
+ t.Errorf("CreateContainerSystemdUnit() = \n%v, want \n%v", got, tt.want)
}
})
}
diff --git a/pkg/util/utils_supported.go b/pkg/util/utils_supported.go
index c7c8787a0..707e193e9 100644
--- a/pkg/util/utils_supported.go
+++ b/pkg/util/utils_supported.go
@@ -16,8 +16,8 @@ import (
"github.com/sirupsen/logrus"
)
-// GetRootlessRuntimeDir returns the runtime directory when running as non root
-func GetRootlessRuntimeDir() (string, error) {
+// GetRuntimeDir returns the runtime directory
+func GetRuntimeDir() (string, error) {
var rootlessRuntimeDirError error
rootlessRuntimeDirOnce.Do(func() {
@@ -100,7 +100,7 @@ func GetRootlessConfigHomeDir() (string, error) {
// GetRootlessPauseProcessPidPath returns the path to the file that holds the pid for
// the pause process
func GetRootlessPauseProcessPidPath() (string, error) {
- runtimeDir, err := GetRootlessRuntimeDir()
+ runtimeDir, err := GetRuntimeDir()
if err != nil {
return "", err
}
diff --git a/pkg/util/utils_windows.go b/pkg/util/utils_windows.go
index e781e6717..9bba2d1ee 100644
--- a/pkg/util/utils_windows.go
+++ b/pkg/util/utils_windows.go
@@ -25,12 +25,12 @@ func GetRootlessPauseProcessPidPath() (string, error) {
return "", errors.Wrap(errNotImplemented, "GetRootlessPauseProcessPidPath")
}
-// GetRootlessRuntimeDir returns the runtime directory when running as non root
-func GetRootlessRuntimeDir() (string, error) {
- return "", errors.Wrap(errNotImplemented, "GetRootlessRuntimeDir")
+// GetRuntimeDir returns the runtime directory
+func GetRuntimeDir() (string, error) {
+ return "", errors.New("this function is not implemented for windows")
}
// GetRootlessConfigHomeDir returns the config home directory when running as non root
func GetRootlessConfigHomeDir() (string, error) {
- return "", errors.Wrap(errNotImplemented, "GetRootlessConfigHomeDir")
+ return "", errors.New("this function is not implemented for windows")
}
diff --git a/pkg/varlinkapi/containers.go b/pkg/varlinkapi/containers.go
index c7aa5233f..2dcdbc089 100644
--- a/pkg/varlinkapi/containers.go
+++ b/pkg/varlinkapi/containers.go
@@ -14,7 +14,7 @@ import (
"time"
"github.com/containers/libpod/cmd/podman/shared"
- "github.com/containers/libpod/cmd/podman/varlink"
+ iopodman "github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/libpod/logs"
@@ -864,3 +864,16 @@ func (i *LibpodAPI) ExecContainer(call iopodman.VarlinkCall, opts iopodman.ExecO
return ecErr.Error
}
+
+//HealthCheckRun executes defined container's healthcheck command and returns the container's health status.
+func (i *LibpodAPI) HealthCheckRun(call iopodman.VarlinkCall, nameOrID string) error {
+ hcStatus, err := i.Runtime.HealthCheck(nameOrID)
+ if err != nil && hcStatus != libpod.HealthCheckFailure {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ status := libpod.HealthCheckUnhealthy
+ if hcStatus == libpod.HealthCheckSuccess {
+ status = libpod.HealthCheckHealthy
+ }
+ return call.ReplyHealthCheckRun(status)
+}
diff --git a/pkg/varlinkapi/generate.go b/pkg/varlinkapi/generate.go
index 9dc20d582..19010097d 100644
--- a/pkg/varlinkapi/generate.go
+++ b/pkg/varlinkapi/generate.go
@@ -4,9 +4,9 @@ package varlinkapi
import (
"encoding/json"
+
"github.com/containers/libpod/cmd/podman/shared"
iopodman "github.com/containers/libpod/cmd/podman/varlink"
- "github.com/containers/libpod/pkg/systemdgen"
)
// GenerateKube ...
@@ -29,24 +29,3 @@ func (i *LibpodAPI) GenerateKube(call iopodman.VarlinkCall, name string, service
Service: string(servB),
})
}
-
-// GenerateSystemd ...
-func (i *LibpodAPI) GenerateSystemd(call iopodman.VarlinkCall, nameOrID, restart string, stopTimeout int64, useName bool) error {
- ctr, err := i.Runtime.LookupContainer(nameOrID)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- timeout := int(ctr.StopTimeout())
- if stopTimeout >= 0 {
- timeout = int(stopTimeout)
- }
- name := ctr.ID()
- if useName {
- name = ctr.Name()
- }
- unit, err := systemdgen.CreateSystemdUnitAsString(name, ctr.ID(), restart, ctr.Config().StaticDir, timeout)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- return call.ReplyGenerateSystemd(unit)
-}
diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go
index fe7f11b4d..c184155a9 100644
--- a/pkg/varlinkapi/images.go
+++ b/pkg/varlinkapi/images.go
@@ -142,7 +142,14 @@ func (i *LibpodAPI) BuildImage(call iopodman.VarlinkCall, config iopodman.BuildI
return call.ReplyErrorOccurred(fmt.Sprintf("unable to untar context dir %s", contextDir))
}
logrus.Debugf("untar of %s successful", contextDir)
-
+ defer func() {
+ if err := os.Remove(contextDir); err != nil {
+ logrus.Errorf("unable to delete file '%s': %q", contextDir, err)
+ }
+ if err := os.RemoveAll(newContextDir); err != nil {
+ logrus.Errorf("unable to delete directory '%s': %q", newContextDir, err)
+ }
+ }()
// All output (stdout, stderr) is captured in output as well
var output bytes.Buffer
@@ -331,7 +338,7 @@ func (i *LibpodAPI) PushImage(call iopodman.VarlinkCall, name, tag string, compr
dockerRegistryOptions := image.DockerRegistryOptions{}
if format != "" {
switch format {
- case "oci": //nolint
+ case "oci": // nolint
manifestType = v1.MediaTypeImageManifest
case "v2s1":
manifestType = manifest.DockerV2Schema1SignedMediaType
@@ -353,7 +360,12 @@ func (i *LibpodAPI) PushImage(call iopodman.VarlinkCall, name, tag string, compr
output := bytes.NewBuffer([]byte{})
c := make(chan error)
go func() {
- err := newImage.PushImageToHeuristicDestination(getContext(), destname, manifestType, "", "", output, compress, so, &dockerRegistryOptions, nil)
+ writer := bytes.NewBuffer([]byte{})
+ err := newImage.PushImageToHeuristicDestination(getContext(), destname, manifestType, "", "", "", writer, compress, so, &dockerRegistryOptions, nil)
+ if err != nil {
+ c <- err
+ }
+ _, err = io.CopyBuffer(output, writer, nil)
c <- err
close(c)
}()
@@ -381,6 +393,7 @@ func (i *LibpodAPI) PushImage(call iopodman.VarlinkCall, name, tag string, compr
}
br := iopodman.MoreResponse{
Logs: log,
+ Id: newImage.ID(),
}
call.ReplyPushImage(br)
log = []string{}
@@ -396,6 +409,7 @@ func (i *LibpodAPI) PushImage(call iopodman.VarlinkCall, name, tag string, compr
br := iopodman.MoreResponse{
Logs: log,
+ Id: newImage.ID(),
}
return call.ReplyPushImage(br)
}
@@ -523,7 +537,7 @@ func (i *LibpodAPI) Commit(call iopodman.VarlinkCall, name, imageName string, ch
}
sc := image.GetSystemContext(rtc.SignaturePolicyPath, "", false)
switch manifestType {
- case "oci", "": //nolint
+ case "oci", "": // nolint
mimeType = buildah.OCIv1ImageManifest
case "docker":
mimeType = manifest.DockerV2Schema2MediaType
@@ -615,7 +629,7 @@ func (i *LibpodAPI) ExportImage(call iopodman.VarlinkCall, name, destination str
return err
}
- if err := newImage.PushImageToHeuristicDestination(getContext(), destination, "", "", "", nil, compress, image.SigningOptions{}, &image.DockerRegistryOptions{}, additionalTags); err != nil {
+ if err := newImage.PushImageToHeuristicDestination(getContext(), destination, "", "", "", "", nil, compress, image.SigningOptions{}, &image.DockerRegistryOptions{}, additionalTags); err != nil {
return call.ReplyErrorOccurred(err.Error())
}
return call.ReplyExportImage(newImage.ID())
@@ -814,7 +828,7 @@ func (i *LibpodAPI) ImageSave(call iopodman.VarlinkCall, options iopodman.ImageS
// Image has been saved to `output`
if outputToDir {
// If the output is a directory, we need to tar up the directory to send it back
- //Create a tempfile for the directory tarball
+ // Create a tempfile for the directory tarball
outputFile, err := ioutil.TempFile("", "varlink_save_dir")
if err != nil {
return err
diff --git a/pkg/varlinkapi/volumes.go b/pkg/varlinkapi/volumes.go
index 19ba38e7c..6dd86d831 100644
--- a/pkg/varlinkapi/volumes.go
+++ b/pkg/varlinkapi/volumes.go
@@ -68,7 +68,6 @@ func (i *LibpodAPI) GetVolumes(call iopodman.VarlinkCall, args []string, all boo
MountPoint: v.MountPoint(),
Name: v.Name(),
Options: v.Options(),
- Scope: v.Scope(),
}
volumes = append(volumes, newVol)
}