add libpod/config

Refactor the `RuntimeConfig` along with related code from libpod into
libpod/config.  Note that this is a first step of consolidating code
into more coherent packages to make the code more maintainable and less
prone to regressions on the long runs.

Some libpod definitions were moved to `libpod/define` to resolve
circular dependencies.

Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
This commit is contained in:
Valentin Rothberg 2019-10-21 19:48:23 +02:00
parent fb5367f295
commit 11c282ab02
33 changed files with 1256 additions and 920 deletions

View file

@ -74,8 +74,8 @@ ASMFLAGS ?= all=-trimpath=${PWD}
LDFLAGS_PODMAN ?= $(LDFLAGS) \ LDFLAGS_PODMAN ?= $(LDFLAGS) \
-X $(LIBPOD)/define.gitCommit=$(GIT_COMMIT) \ -X $(LIBPOD)/define.gitCommit=$(GIT_COMMIT) \
-X $(LIBPOD)/define.buildInfo=$(BUILD_INFO) \ -X $(LIBPOD)/define.buildInfo=$(BUILD_INFO) \
-X $(LIBPOD).installPrefix=$(PREFIX) \ -X $(LIBPOD)/config._installPrefix=$(PREFIX) \
-X $(LIBPOD).etcDir=$(ETCDIR) -X $(LIBPOD)/config._etcDir=$(ETCDIR)
#Update to LIBSECCOMP_COMMIT should reflect in Dockerfile too. #Update to LIBSECCOMP_COMMIT should reflect in Dockerfile too.
LIBSECCOMP_COMMIT := release-2.3 LIBSECCOMP_COMMIT := release-2.3
# Rarely if ever should integration tests take more than 50min, # Rarely if ever should integration tests take more than 50min,

View file

@ -11,7 +11,7 @@ import (
buildahcli "github.com/containers/buildah/pkg/cli" buildahcli "github.com/containers/buildah/pkg/cli"
"github.com/containers/image/v5/types" "github.com/containers/image/v5/types"
"github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/adapter" "github.com/containers/libpod/pkg/adapter"
"github.com/docker/go-units" "github.com/docker/go-units"
"github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-spec/specs-go"
@ -260,7 +260,7 @@ func buildCmd(c *cliconfig.BuildValues) error {
if err != nil { if err != nil {
return err return err
} }
if conf != nil && conf.CgroupManager == libpod.SystemdCgroupsManager { if conf != nil && conf.CgroupManager == define.SystemdCgroupsManager {
runtimeFlags = append(runtimeFlags, "--systemd-cgroup") runtimeFlags = append(runtimeFlags, "--systemd-cgroup")
} }
// end from buildah // end from buildah

View file

@ -16,7 +16,8 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod/config"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/cgroups" "github.com/containers/libpod/pkg/cgroups"
"github.com/containers/libpod/pkg/rootless" "github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/tracing" "github.com/containers/libpod/pkg/tracing"
@ -32,8 +33,8 @@ import (
const remote = false const remote = false
func init() { func init() {
cgroupManager := libpod.SystemdCgroupsManager cgroupManager := define.SystemdCgroupsManager
if runtimeConfig, err := libpod.DefaultRuntimeConfig(); err == nil { if runtimeConfig, err := config.NewConfig(""); err == nil {
cgroupManager = runtimeConfig.CgroupManager cgroupManager = runtimeConfig.CgroupManager
} }
cgroupHelp := "Cgroup manager to use (cgroupfs or systemd)" cgroupHelp := "Cgroup manager to use (cgroupfs or systemd)"
@ -181,7 +182,7 @@ func setupRootless(cmd *cobra.Command, args []string) error {
if !ownsCgroup { if !ownsCgroup {
unitName := fmt.Sprintf("podman-%d.scope", os.Getpid()) unitName := fmt.Sprintf("podman-%d.scope", os.Getpid())
if err := utils.RunUnderSystemdScope(os.Getpid(), "user.slice", unitName); err != nil { if err := utils.RunUnderSystemdScope(os.Getpid(), "user.slice", unitName); err != nil {
if conf.CgroupManager == libpod.SystemdCgroupsManager { if conf.CgroupManager == define.SystemdCgroupsManager {
logrus.Warnf("Failed to add podman to systemd sandbox cgroup: %v", err) logrus.Warnf("Failed to add podman to systemd sandbox cgroup: %v", err)
} else { } else {
logrus.Debugf("Failed to add podman to systemd sandbox cgroup: %v", err) logrus.Debugf("Failed to add podman to systemd sandbox cgroup: %v", err)
@ -225,7 +226,7 @@ func setupRootless(cmd *cobra.Command, args []string) error {
if err != nil { if err != nil {
return err return err
} }
if conf.CgroupManager == libpod.SystemdCgroupsManager { if conf.CgroupManager == define.SystemdCgroupsManager {
logrus.Warnf("Failed to add pause process to systemd sandbox cgroup: %v", err) logrus.Warnf("Failed to add pause process to systemd sandbox cgroup: %v", err)
} else { } else {
logrus.Debugf("Failed to add pause process to systemd sandbox cgroup: %v", err) logrus.Debugf("Failed to add pause process to systemd sandbox cgroup: %v", err)

15
go.sum
View file

@ -55,12 +55,8 @@ github.com/containernetworking/cni v0.7.1 h1:fE3r16wpSEyaqY4Z4oFrLMmIGfBYIKpPrHK
github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
github.com/containernetworking/plugins v0.8.2 h1:5lnwfsAYO+V7yXhysJKy3E1A2Gy9oVut031zfdOzI9w= github.com/containernetworking/plugins v0.8.2 h1:5lnwfsAYO+V7yXhysJKy3E1A2Gy9oVut031zfdOzI9w=
github.com/containernetworking/plugins v0.8.2/go.mod h1:TxALKWZpWL79BC3GOYKJzzXr7U8R23PdhwaLp6F3adc= github.com/containernetworking/plugins v0.8.2/go.mod h1:TxALKWZpWL79BC3GOYKJzzXr7U8R23PdhwaLp6F3adc=
github.com/containers/buildah v1.11.3 h1:L5vFj+ao58IGq3G30jN94vRQrIgMU/uTOEKduDr3Nyg=
github.com/containers/buildah v1.11.3/go.mod h1:jqZmSU/PhFwTHHlOotnw4bbs1JbkRQLh8dut5DF4Qek=
github.com/containers/buildah v1.11.4-0.20191028173731-21b4778b359e h1:iDavHEx5Yr7o+0l6495Ya6N0YEPplIUZuWC2e14baDM= github.com/containers/buildah v1.11.4-0.20191028173731-21b4778b359e h1:iDavHEx5Yr7o+0l6495Ya6N0YEPplIUZuWC2e14baDM=
github.com/containers/buildah v1.11.4-0.20191028173731-21b4778b359e/go.mod h1:Igrk75FAxLnzDaHUbtpWB8pwL+Bv+cnakWMvqAXW2v8= github.com/containers/buildah v1.11.4-0.20191028173731-21b4778b359e/go.mod h1:Igrk75FAxLnzDaHUbtpWB8pwL+Bv+cnakWMvqAXW2v8=
github.com/containers/image/v4 v4.0.1 h1:idNGHChj0Pyv3vLrxul2oSVMZLeFqpoq3CjLeVgapSQ=
github.com/containers/image/v4 v4.0.1/go.mod h1:0ASJH1YgJiX/eqFZObqepgsvIA4XjCgpyfwn9pDGafA=
github.com/containers/image/v5 v5.0.0 h1:arnXgbt1ucsC/ndtSpiQY87rA0UjhF+/xQnPzqdBDn4= github.com/containers/image/v5 v5.0.0 h1:arnXgbt1ucsC/ndtSpiQY87rA0UjhF+/xQnPzqdBDn4=
github.com/containers/image/v5 v5.0.0/go.mod h1:MgiLzCfIeo8lrHi+4Lb8HP+rh513sm0Mlk6RrhjFOLY= github.com/containers/image/v5 v5.0.0/go.mod h1:MgiLzCfIeo8lrHi+4Lb8HP+rh513sm0Mlk6RrhjFOLY=
github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b h1:Q8ePgVfHDplZ7U33NwHZkrVELsZP5fYj9pM5WBZB2GE= github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b h1:Q8ePgVfHDplZ7U33NwHZkrVELsZP5fYj9pM5WBZB2GE=
@ -102,8 +98,6 @@ github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BU
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v0.0.0-20171019062838-86f080cff091/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v0.0.0-20171019062838-86f080cff091/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v0.0.0-20180522102801-da99009bbb11/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v0.0.0-20180522102801-da99009bbb11/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v1.4.2-0.20190710153559-aa8249ae1b8b h1:+Ga+YpCDpcY1fln6GI0fiiirpqHGcob5/Vk3oKNuGdU=
github.com/docker/docker v1.4.2-0.20190710153559-aa8249ae1b8b/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v1.4.2-0.20190927142053-ada3c14355ce h1:H3csZuxZESJeeEiOxq4YXPNmLFbjl7u2qVBrAAGX/sA= github.com/docker/docker v1.4.2-0.20190927142053-ada3c14355ce h1:H3csZuxZESJeeEiOxq4YXPNmLFbjl7u2qVBrAAGX/sA=
github.com/docker/docker v1.4.2-0.20190927142053-ada3c14355ce/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v1.4.2-0.20190927142053-ada3c14355ce/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.6.0/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/docker-credential-helpers v0.6.0/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
@ -139,8 +133,6 @@ github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8
github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsouza/go-dockerclient v1.4.4 h1:Sd5nD4wdAgiPxvrbYUzT2ZZNmPk3z+GGnZ+frvw8z04=
github.com/fsouza/go-dockerclient v1.4.4/go.mod h1:PrwszSL5fbmsESocROrOGq/NULMXRw+bajY0ltzD6MA=
github.com/fsouza/go-dockerclient v1.5.0 h1:7OtayOe5HnoG+KWMHgyyPymwaodnB2IDYuVfseKyxbA= github.com/fsouza/go-dockerclient v1.5.0 h1:7OtayOe5HnoG+KWMHgyyPymwaodnB2IDYuVfseKyxbA=
github.com/fsouza/go-dockerclient v1.5.0/go.mod h1:AqZZK/zFO3phxYxlTsAaeAMSdQ9mgHuhy+bjN034Qds= github.com/fsouza/go-dockerclient v1.5.0/go.mod h1:AqZZK/zFO3phxYxlTsAaeAMSdQ9mgHuhy+bjN034Qds=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
@ -210,8 +202,6 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd h1:anPrsicrIi2ColgWTVPk+TrN42hJIWlfPHSBP9S0ZkM=
github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd/go.mod h1:3LVOLeyx9XVvwPgrt2be44XgSqndprz1G18rSk8KD84=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
@ -322,8 +312,6 @@ github.com/opencontainers/selinux v1.3.0 h1:xsI95WzPZu5exzA6JzkLSfdr/DilzOhCJOqG
github.com/opencontainers/selinux v1.3.0/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs= github.com/opencontainers/selinux v1.3.0/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs=
github.com/openshift/api v3.9.1-0.20190810003144-27fb16909b15+incompatible h1:s55wx8JIG/CKnewev892HifTBrtKzMdvgB3rm4rxC2s= github.com/openshift/api v3.9.1-0.20190810003144-27fb16909b15+incompatible h1:s55wx8JIG/CKnewev892HifTBrtKzMdvgB3rm4rxC2s=
github.com/openshift/api v3.9.1-0.20190810003144-27fb16909b15+incompatible/go.mod h1:dh9o4Fs58gpFXGSYfnVxGR9PnV53I8TW84pQaJDdGiY= github.com/openshift/api v3.9.1-0.20190810003144-27fb16909b15+incompatible/go.mod h1:dh9o4Fs58gpFXGSYfnVxGR9PnV53I8TW84pQaJDdGiY=
github.com/openshift/imagebuilder v1.1.0 h1:oT704SkwMEzmIMU/+Uv1Wmvt+p10q3v2WuYMeFI18c4=
github.com/openshift/imagebuilder v1.1.0/go.mod h1:9aJRczxCH0mvT6XQ+5STAQaPWz7OsWcU5/mRkt8IWeo=
github.com/openshift/imagebuilder v1.1.1 h1:KAUR31p8UBJdfVO42azWgb+LeMAed2zaKQ19e0C0X2I= github.com/openshift/imagebuilder v1.1.1 h1:KAUR31p8UBJdfVO42azWgb+LeMAed2zaKQ19e0C0X2I=
github.com/openshift/imagebuilder v1.1.1/go.mod h1:9aJRczxCH0mvT6XQ+5STAQaPWz7OsWcU5/mRkt8IWeo= github.com/openshift/imagebuilder v1.1.1/go.mod h1:9aJRczxCH0mvT6XQ+5STAQaPWz7OsWcU5/mRkt8IWeo=
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
@ -444,8 +432,6 @@ golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad h1:5E5raQxcv+6CZ11RrBYQe5WRbUIWpScjh0kvHZkZIrQ= golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad h1:5E5raQxcv+6CZ11RrBYQe5WRbUIWpScjh0kvHZkZIrQ=
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -495,7 +481,6 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190902133755-9109b7679e13 h1:tdsQdquKbTNMsSZLqnLELJGzCANp9oXhu6zFBW6ODx4= golang.org/x/sys v0.0.0-20190902133755-9109b7679e13 h1:tdsQdquKbTNMsSZLqnLELJGzCANp9oXhu6zFBW6ODx4=
golang.org/x/sys v0.0.0-20190902133755-9109b7679e13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190902133755-9109b7679e13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

View file

@ -6,6 +6,7 @@ import (
"strings" "strings"
"sync" "sync"
"github.com/containers/libpod/libpod/config"
"github.com/containers/libpod/libpod/define" "github.com/containers/libpod/libpod/define"
bolt "github.com/etcd-io/bbolt" bolt "github.com/etcd-io/bbolt"
jsoniter "github.com/json-iterator/go" jsoniter "github.com/json-iterator/go"
@ -291,12 +292,12 @@ func (s *BoltState) Refresh() error {
// GetDBConfig retrieves runtime configuration fields that were created when // GetDBConfig retrieves runtime configuration fields that were created when
// the database was first initialized // the database was first initialized
func (s *BoltState) GetDBConfig() (*DBConfig, error) { func (s *BoltState) GetDBConfig() (*config.DBConfig, error) {
if !s.valid { if !s.valid {
return nil, define.ErrDBClosed return nil, define.ErrDBClosed
} }
cfg := new(DBConfig) cfg := new(config.DBConfig)
db, err := s.getDBCon() db, err := s.getDBCon()
if err != nil { if err != nil {

View file

@ -7,6 +7,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/containers/libpod/libpod/config"
"github.com/containers/libpod/libpod/define" "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/libpod/lock" "github.com/containers/libpod/libpod/lock"
"github.com/cri-o/ocicni/pkg/ocicni" "github.com/cri-o/ocicni/pkg/ocicni"
@ -74,7 +75,7 @@ func getTestContainer(id, name string, manager lock.Manager) (*Container, error)
}, },
}, },
runtime: &Runtime{ runtime: &Runtime{
config: &RuntimeConfig{ config: &config.Config{
VolumePath: "/does/not/exist/tmp/volumes", VolumePath: "/does/not/exist/tmp/volumes",
}, },
}, },

549
libpod/config/config.go Normal file
View file

@ -0,0 +1,549 @@
package config
import (
"bytes"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"regexp"
"strconv"
"strings"
"github.com/BurntSushi/toml"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/util"
"github.com/containers/storage"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
const (
// _defaultTransport is a prefix that we apply to an image name to check
// docker hub first for the image.
_defaultTransport = "docker://"
// _rootlessConfigPath is the path to the rootless libpod.conf in $HOME.
_rootlessConfigPath = ".config/containers/libpod.conf"
// _conmonMinMajorVersion is the major version required for conmon.
_conmonMinMajorVersion = 2
// _conmonMinMinorVersion is the minor version required for conmon.
_conmonMinMinorVersion = 0
// _conmonMinPatchVersion is the sub-minor version required for conmon.
_conmonMinPatchVersion = 1
// _conmonVersionFormatErr is used when the expected versio-format of conmon
// has changed.
_conmonVersionFormatErr = "conmon version changed format"
// InstallPrefix is the prefix where podman will be installed.
// It can be overridden at build time.
_installPrefix = "/usr"
// EtcDir is the sysconfdir where podman should look for system config files.
// It can be overridden at build time.
_etcDir = "/etc"
// SeccompDefaultPath defines the default seccomp path.
SeccompDefaultPath = _installPrefix + "/share/containers/seccomp.json"
// SeccompOverridePath if this exists it overrides the default seccomp path.
SeccompOverridePath = _etcDir + "/crio/seccomp.json"
// _rootConfigPath is the path to the libpod configuration file
// This file is loaded to replace the builtin default config before
// runtime options (e.g. WithStorageConfig) are applied.
// If it is not present, the builtin default config is used instead
// This path can be overridden when the runtime is created by using
// NewRuntimeFromConfig() instead of NewRuntime().
_rootConfigPath = _installPrefix + "/share/containers/libpod.conf"
// _rootOverrideConfigPath is the path to an override for the default libpod
// configuration file. If OverrideConfigPath exists, it will be used in
// place of the configuration file pointed to by ConfigPath.
_rootOverrideConfigPath = _etcDir + "/containers/libpod.conf"
)
// SetOptions contains a subset of options in a Config. It's used to indicate if
// a given option has either been set by the user or by a parsed libpod
// configuration file. If not, the corresponding option might be overwritten by
// values from the database. This behavior guarantess backwards compat with
// older version of libpod and Podman.
type SetOptions struct {
// StorageConfigRunRootSet indicates if the RunRoot has been explicitly set
// by the config or by the user. It's required to guarantee backwards
// compatibility with older versions of libpod for which we must query the
// database configuration. Not included in the on-disk config.
StorageConfigRunRootSet bool `toml:"-"`
// StorageConfigGraphRootSet indicates if the RunRoot has been explicitly
// set by the config or by the user. It's required to guarantee backwards
// compatibility with older versions of libpod for which we must query the
// database configuration. Not included in the on-disk config.
StorageConfigGraphRootSet bool `toml:"-"`
// StorageConfigGraphDriverNameSet indicates if the GraphDriverName has been
// explicitly set by the config or by the user. It's required to guarantee
// backwards compatibility with older versions of libpod for which we must
// query the database configuration. Not included in the on-disk config.
StorageConfigGraphDriverNameSet bool `toml:"-"`
// VolumePathSet indicates if the VolumePath has been explicitly set by the
// config or by the user. It's required to guarantee backwards compatibility
// with older versions of libpod for which we must query the database
// configuration. Not included in the on-disk config.
VolumePathSet bool `toml:"-"`
// StaticDirSet indicates if the StaticDir has been explicitly set by the
// config or by the user. It's required to guarantee backwards compatibility
// with older versions of libpod for which we must query the database
// configuration. Not included in the on-disk config.
StaticDirSet bool `toml:"-"`
// TmpDirSet indicates if the TmpDir has been explicitly set by the config
// or by the user. It's required to guarantee backwards compatibility with
// older versions of libpod for which we must query the database
// configuration. Not included in the on-disk config.
TmpDirSet bool `toml:"-"`
}
// Config contains configuration options used to set up a libpod runtime
type Config struct {
// NOTE: when changing this struct, make sure to update (*Config).Merge().
// SetOptions contains a subset of config options. It's used to indicate if
// a given option has either been set by the user or by a parsed libpod
// configuration file. If not, the corresponding option might be
// overwritten by values from the database. This behavior guarantess
// backwards compat with older version of libpod and Podman.
SetOptions
// StateType is the type of the backing state store. Avoid using multiple
// values for this with the same containers/storage configuration on the
// same system. Different state types do not interact, and each will see a
// separate set of containers, which may cause conflicts in
// containers/storage. As such this is not exposed via the config file.
StateType define.RuntimeStateStore `toml:"-"`
// StorageConfig is the configuration used by containers/storage Not
// included in the on-disk config, use the dedicated containers/storage
// configuration file instead.
StorageConfig storage.StoreOptions `toml:"-"`
// VolumePath is the default location that named volumes will be created
// under. This convention is followed by the default volume driver, but
// may not be by other drivers.
VolumePath string `toml:"volume_path"`
// ImageDefaultTransport is the default transport method used to fetch
// images.
ImageDefaultTransport string `toml:"image_default_transport"`
// SignaturePolicyPath is the path to a signature policy to use for
// validating images. If left empty, the containers/image default signature
// policy will be used.
SignaturePolicyPath string `toml:"signature_policy_path,omitempty"`
// OCIRuntime is the OCI runtime to use.
OCIRuntime string `toml:"runtime"`
// OCIRuntimes are the set of configured OCI runtimes (default is runc).
OCIRuntimes map[string][]string `toml:"runtimes"`
// RuntimeSupportsJSON is the list of the OCI runtimes that support
// --format=json.
RuntimeSupportsJSON []string `toml:"runtime_supports_json"`
// RuntimeSupportsNoCgroups is a list of OCI runtimes that support
// running containers without CGroups.
RuntimeSupportsNoCgroups []string `toml:"runtime_supports_nocgroups"`
// RuntimePath is the path to OCI runtime binary for launching containers.
// The first path pointing to a valid file will be used This is used only
// when there are no OCIRuntime/OCIRuntimes defined. It is used only to be
// backward compatible with older versions of Podman.
RuntimePath []string `toml:"runtime_path"`
// ConmonPath is the path to the Conmon binary used for managing containers.
// The first path pointing to a valid file will be used.
ConmonPath []string `toml:"conmon_path"`
// ConmonEnvVars are environment variables to pass to the Conmon binary
// when it is launched.
ConmonEnvVars []string `toml:"conmon_env_vars"`
// CGroupManager is the CGroup Manager to use Valid values are "cgroupfs"
// and "systemd".
CgroupManager string `toml:"cgroup_manager"`
// InitPath is the path to the container-init binary.
InitPath string `toml:"init_path"`
// StaticDir is the path to a persistent directory to store container
// files.
StaticDir string `toml:"static_dir"`
// TmpDir is the path to a temporary directory to store per-boot container
// files. Must be stored in a tmpfs.
TmpDir string `toml:"tmp_dir"`
// MaxLogSize is the maximum size of container logfiles.
MaxLogSize int64 `toml:"max_log_size,omitempty"`
// NoPivotRoot sets whether to set no-pivot-root in the OCI runtime.
NoPivotRoot bool `toml:"no_pivot_root"`
// CNIConfigDir sets the directory where CNI configuration files are
// stored.
CNIConfigDir string `toml:"cni_config_dir"`
// CNIPluginDir sets a number of directories where the CNI network
// plugins can be located.
CNIPluginDir []string `toml:"cni_plugin_dir"`
// CNIDefaultNetwork is the network name of the default CNI network
// to attach pods to.
CNIDefaultNetwork string `toml:"cni_default_network,omitempty"`
// HooksDir holds paths to the directories containing hooks
// configuration files. When the same filename is present in in
// multiple directories, the file in the directory listed last in
// this slice takes precedence.
HooksDir []string `toml:"hooks_dir"`
// DefaultMountsFile is the path to the default mounts file for testing
// purposes only.
DefaultMountsFile string `toml:"-"`
// Namespace is the libpod namespace to use. Namespaces are used to create
// scopes to separate containers and pods in the state. When namespace is
// set, libpod will only view containers and pods in the same namespace. All
// containers and pods created will default to the namespace set here. A
// namespace of "", the empty string, is equivalent to no namespace, and all
// containers and pods will be visible. The default namespace is "".
Namespace string `toml:"namespace,omitempty"`
// InfraImage is the image a pod infra container will use to manage
// namespaces.
InfraImage string `toml:"infra_image"`
// InfraCommand is the command run to start up a pod infra container.
InfraCommand string `toml:"infra_command"`
// EnablePortReservation determines whether libpod will reserve ports on the
// host when they are forwarded to containers. When enabled, when ports are
// forwarded to containers, they are held open by conmon as long as the
// container is running, ensuring that they cannot be reused by other
// programs on the host. However, this can cause significant memory usage if
// a container has many ports forwarded to it. Disabling this can save
// memory.
EnablePortReservation bool `toml:"enable_port_reservation"`
// EnableLabeling indicates whether libpod will support container labeling.
EnableLabeling bool `toml:"label"`
// NetworkCmdPath is the path to the slirp4netns binary.
NetworkCmdPath string `toml:"network_cmd_path"`
// NumLocks is the number of locks to make available for containers and
// pods.
NumLocks uint32 `toml:"num_locks,omitempty"`
// LockType is the type of locking to use.
LockType string `toml:"lock_type,omitempty"`
// EventsLogger determines where events should be logged.
EventsLogger string `toml:"events_logger"`
// EventsLogFilePath is where the events log is stored.
EventsLogFilePath string `toml:"events_logfile_path"`
//DetachKeys is the sequence of keys used to detach a container.
DetachKeys string `toml:"detach_keys"`
// SDNotify tells Libpod to allow containers to notify the host systemd of
// readiness using the SD_NOTIFY mechanism.
SDNotify bool
}
// DBConfig is a set of Libpod runtime configuration settings that are saved in
// a State when it is first created, and can subsequently be retrieved.
type DBConfig struct {
LibpodRoot string
LibpodTmp string
StorageRoot string
StorageTmp string
GraphDriver string
VolumePath string
}
// readConfigFromFile reads the specified config file at `path` and attempts to
// unmarshal its content into a Config.
func readConfigFromFile(path string) (*Config, error) {
var config Config
configBytes, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
logrus.Debugf("Reading configuration file %q", path)
err = toml.Unmarshal(configBytes, &config)
// For the sake of backwards compat we need to check if the config fields
// with *Set suffix are set in the config. Note that the storage-related
// fields are NOT set in the config here but in the storage.conf OR directly
// by the user.
if config.VolumePath != "" {
config.VolumePathSet = true
}
if config.StaticDir != "" {
config.StaticDirSet = true
}
if config.TmpDir != "" {
config.TmpDirSet = true
}
return &config, err
}
// Write decodes the config as TOML and writes it to the specified path.
func (c *Config) Write(path string) error {
f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0666)
if err != nil {
return errors.Wrapf(err, "error opening config file %q", path)
}
buffer := new(bytes.Buffer)
if err := toml.NewEncoder(buffer).Encode(c); err != nil {
return errors.Wrapf(err, "error encoding config")
}
if _, err := f.WriteString(buffer.String()); err != nil {
return errors.Wrapf(err, "error writing config %q", path)
}
return err
}
// FindConmon iterates over (*Config).ConmonPath and returns the path to first
// (version) matching conmon binary. If non is found, we try to do a path lookup
// of "conmon".
func (c *Config) FindConmon() (string, error) {
foundOutdatedConmon := false
for _, path := range c.ConmonPath {
stat, err := os.Stat(path)
if err != nil {
continue
}
if stat.IsDir() {
continue
}
if err := probeConmon(path); err != nil {
logrus.Warnf("Conmon at %s invalid: %v", path, err)
foundOutdatedConmon = true
continue
}
logrus.Debugf("Using conmon: %q", path)
return path, nil
}
// Search the $PATH as last fallback
if path, err := exec.LookPath("conmon"); err == nil {
if err := probeConmon(path); err != nil {
logrus.Warnf("Conmon at %s is invalid: %v", path, err)
foundOutdatedConmon = true
} else {
logrus.Debugf("Using conmon from $PATH: %q", path)
return path, nil
}
}
if foundOutdatedConmon {
return "", errors.Wrapf(define.ErrConmonOutdated,
"please update to v%d.%d.%d or later",
_conmonMinMajorVersion, _conmonMinMinorVersion, _conmonMinPatchVersion)
}
return "", errors.Wrapf(define.ErrInvalidArg,
"could not find a working conmon binary (configured options: %v)",
c.ConmonPath)
}
// probeConmon calls conmon --version and verifies it is a new enough version for
// the runtime expectations podman currently has.
func probeConmon(conmonBinary string) error {
cmd := exec.Command(conmonBinary, "--version")
var out bytes.Buffer
cmd.Stdout = &out
err := cmd.Run()
if err != nil {
return err
}
r := regexp.MustCompile(`^conmon version (?P<Major>\d+).(?P<Minor>\d+).(?P<Patch>\d+)`)
matches := r.FindStringSubmatch(out.String())
if len(matches) != 4 {
return errors.Wrap(err, _conmonVersionFormatErr)
}
major, err := strconv.Atoi(matches[1])
if err != nil {
return errors.Wrap(err, _conmonVersionFormatErr)
}
if major < _conmonMinMajorVersion {
return define.ErrConmonOutdated
}
if major > _conmonMinMajorVersion {
return nil
}
minor, err := strconv.Atoi(matches[2])
if err != nil {
return errors.Wrap(err, _conmonVersionFormatErr)
}
if minor < _conmonMinMinorVersion {
return define.ErrConmonOutdated
}
if minor > _conmonMinMinorVersion {
return nil
}
patch, err := strconv.Atoi(matches[3])
if err != nil {
return errors.Wrap(err, _conmonVersionFormatErr)
}
if patch < _conmonMinPatchVersion {
return define.ErrConmonOutdated
}
if patch > _conmonMinPatchVersion {
return nil
}
return nil
}
// NewConfig creates a new Config. It starts with an empty config and, if
// specified, merges the config at `userConfigPath` path. Depending if we're
// running as root or rootless, we then merge the system configuration followed
// by merging the default config (hard-coded default in memory).
//
// Note that the OCI runtime is hard-set to `crun` if we're running on a system
// with cgroupsv2. Other OCI runtimes are not yet supporting cgroupsv2. This
// might change in the future.
func NewConfig(userConfigPath string) (*Config, error) {
config := &Config{} // start with an empty config
// First, try to read the user-specified config
if userConfigPath != "" {
var err error
config, err = readConfigFromFile(userConfigPath)
if err != nil {
return nil, errors.Wrapf(err, "error reading user config %q", userConfigPath)
}
}
// Now, check if the user can access system configs and merge them if needed.
if configs, err := systemConfigs(); err != nil {
return nil, errors.Wrapf(err, "error finding config on system")
} else {
for _, path := range configs {
systemConfig, err := readConfigFromFile(path)
if err != nil {
return nil, errors.Wrapf(err, "error reading system config %q", path)
}
// Merge the it into the config. Any unset field in config will be
// over-written by the systemConfig.
if err := config.mergeConfig(systemConfig); err != nil {
return nil, errors.Wrapf(err, "error merging system config")
}
logrus.Debugf("Merged system config %q: %v", path, config)
}
}
// Finally, create a default config from memory and forcefully merge it into
// the config. This way we try to make sure that all fields are properly set
// and that user AND system config can partially set.
if defaultConfig, err := defaultConfigFromMemory(); err != nil {
return nil, errors.Wrapf(err, "error generating default config from memory")
} else {
if err := config.mergeConfig(defaultConfig); err != nil {
return nil, errors.Wrapf(err, "error merging default config from memory")
}
}
// Relative paths can cause nasty bugs, because core paths we use could
// shift between runs (or even parts of the program - the OCI runtime
// uses a different working directory than we do, for example.
if !filepath.IsAbs(config.StaticDir) {
return nil, errors.Wrapf(define.ErrInvalidArg, "static directory must be an absolute path - instead got %q", config.StaticDir)
}
if !filepath.IsAbs(config.TmpDir) {
return nil, errors.Wrapf(define.ErrInvalidArg, "temporary directory must be an absolute path - instead got %q", config.TmpDir)
}
if !filepath.IsAbs(config.VolumePath) {
return nil, errors.Wrapf(define.ErrInvalidArg, "volume path must be an absolute path - instead got %q", config.VolumePath)
}
// Check if we need to switch to cgroupfs on rootless.
config.checkCgroupsAndAdjustConfig()
return config, nil
}
func rootlessConfigPath() (string, error) {
home, err := util.HomeDir()
if err != nil {
return "", err
}
return filepath.Join(home, _rootlessConfigPath), nil
}
func systemConfigs() ([]string, error) {
if rootless.IsRootless() {
path, err := rootlessConfigPath()
if err != nil {
return nil, err
}
if _, err := os.Stat(path); err == nil {
return []string{path}, nil
}
return nil, err
}
configs := []string{}
if _, err := os.Stat(_rootOverrideConfigPath); err == nil {
configs = append(configs, _rootOverrideConfigPath)
}
if _, err := os.Stat(_rootConfigPath); err == nil {
configs = append(configs, _rootConfigPath)
}
return configs, nil
}
// checkCgroupsAndAdjustConfig checks if we're running rootless with the systemd
// cgroup manager. In case the user session isn't available, we're switching the
// cgroup manager to cgroupfs. Note, this only applies to rootless.
func (c *Config) checkCgroupsAndAdjustConfig() {
if !rootless.IsRootless() || c.CgroupManager != define.SystemdCgroupsManager {
return
}
session := os.Getenv("DBUS_SESSION_BUS_ADDRESS")
hasSession := session != ""
if hasSession && strings.HasPrefix(session, "unix:path=") {
_, err := os.Stat(strings.TrimPrefix(session, "unix:path="))
hasSession = err == nil
}
if !hasSession {
logrus.Warningf("The cgroups manager is set to systemd but there is no systemd user session available")
logrus.Warningf("For using systemd, you may need to login using an user session")
logrus.Warningf("Alternatively, you can enable lingering with: `loginctl enable-linger %d` (possibly as root)", rootless.GetRootlessUID())
logrus.Warningf("Falling back to --cgroup-manager=cgroupfs")
c.CgroupManager = define.CgroupfsCgroupsManager
}
}

View file

@ -0,0 +1,64 @@
package config
import (
"reflect"
"testing"
"github.com/containers/libpod/libpod/define"
"github.com/containers/storage"
"github.com/stretchr/testify/assert"
)
func TestEmptyConfig(t *testing.T) {
// Make sure that we can read empty configs
config, err := readConfigFromFile("testdata/empty.conf")
assert.NotNil(t, config)
assert.Nil(t, err)
}
func TestDefaultLibpodConf(t *testing.T) {
// Make sure that we can read the default libpod.conf
config, err := readConfigFromFile("testdata/libpod.conf")
assert.NotNil(t, config)
assert.Nil(t, err)
}
func TestMergeEmptyAndDefaultMemoryConfig(t *testing.T) {
// Make sure that when we merge the default config into an empty one that we
// effectively get the default config.
defaultConfig, err := defaultConfigFromMemory()
assert.NotNil(t, defaultConfig)
assert.Nil(t, err)
defaultConfig.StateType = define.InvalidStateStore
defaultConfig.StorageConfig = storage.StoreOptions{}
emptyConfig, err := readConfigFromFile("testdata/empty.conf")
assert.NotNil(t, emptyConfig)
assert.Nil(t, err)
err = emptyConfig.mergeConfig(defaultConfig)
assert.Nil(t, err)
equal := reflect.DeepEqual(emptyConfig, defaultConfig)
assert.True(t, equal)
}
func TestMergeEmptyAndLibpodConfig(t *testing.T) {
// Make sure that when we merge the default config into an empty one that we
// effectively get the default config.
libpodConfig, err := readConfigFromFile("testdata/libpod.conf")
assert.NotNil(t, libpodConfig)
assert.Nil(t, err)
libpodConfig.StateType = define.InvalidStateStore
libpodConfig.StorageConfig = storage.StoreOptions{}
emptyConfig, err := readConfigFromFile("testdata/empty.conf")
assert.NotNil(t, emptyConfig)
assert.Nil(t, err)
err = emptyConfig.mergeConfig(libpodConfig)
assert.Nil(t, err)
equal := reflect.DeepEqual(emptyConfig, libpodConfig)
assert.True(t, equal)
}

137
libpod/config/default.go Normal file
View file

@ -0,0 +1,137 @@
package config
import (
"os"
"path/filepath"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/libpod/events"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/util"
"github.com/containers/storage"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
const (
// _defaultGraphRoot points to the default path of the graph root.
_defaultGraphRoot = "/var/lib/containers/storage"
// _defaultRootlessSignaturePolicyPath points to the default path of the
// rootless policy.json file.
_defaultRootlessSignaturePolicyPath = ".config/containers/policy.json"
)
// defaultConfigFromMemory returns a default libpod configuration. Note that the
// config is different for root and rootless. It also parses the storage.conf.
func defaultConfigFromMemory() (*Config, error) {
c := new(Config)
if tmp, err := defaultTmpDir(); err != nil {
return nil, err
} else {
c.TmpDir = tmp
}
c.EventsLogFilePath = filepath.Join(c.TmpDir, "events", "events.log")
storeOpts, err := storage.DefaultStoreOptions(rootless.IsRootless(), rootless.GetRootlessUID())
if err != nil {
return nil, err
}
if storeOpts.GraphRoot == "" {
logrus.Warnf("Storage configuration is unset - using hardcoded default graph root %q", _defaultGraphRoot)
storeOpts.GraphRoot = _defaultGraphRoot
}
c.StaticDir = filepath.Join(storeOpts.GraphRoot, "libpod")
c.VolumePath = filepath.Join(storeOpts.GraphRoot, "volumes")
c.StorageConfig = storeOpts
c.ImageDefaultTransport = _defaultTransport
c.StateType = define.BoltDBStateStore
c.OCIRuntime = "runc"
c.OCIRuntimes = map[string][]string{
"runc": {
"/usr/bin/runc",
"/usr/sbin/runc",
"/usr/local/bin/runc",
"/usr/local/sbin/runc",
"/sbin/runc",
"/bin/runc",
"/usr/lib/cri-o-runc/sbin/runc",
"/run/current-system/sw/bin/runc",
},
// TODO - should we add "crun" defaults here as well?
}
c.ConmonPath = []string{
"/usr/libexec/podman/conmon",
"/usr/local/libexec/podman/conmon",
"/usr/local/lib/podman/conmon",
"/usr/bin/conmon",
"/usr/sbin/conmon",
"/usr/local/bin/conmon",
"/usr/local/sbin/conmon",
"/run/current-system/sw/bin/conmon",
}
c.ConmonEnvVars = []string{
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
}
c.RuntimeSupportsJSON = []string{
"crun",
"runc",
}
c.RuntimeSupportsNoCgroups = []string{"crun"}
c.InitPath = define.DefaultInitPath
c.CgroupManager = define.SystemdCgroupsManager
c.MaxLogSize = -1
c.NoPivotRoot = false
c.CNIConfigDir = _etcDir + "/cni/net.d/"
c.CNIPluginDir = []string{
"/usr/libexec/cni",
"/usr/lib/cni",
"/usr/local/lib/cni",
"/opt/cni/bin",
}
c.CNIDefaultNetwork = "podman"
c.InfraCommand = define.DefaultInfraCommand
c.InfraImage = define.DefaultInfraImage
c.EnablePortReservation = true
c.EnableLabeling = true
c.NumLocks = 2048
c.EventsLogger = events.DefaultEventerType.String()
c.DetachKeys = define.DefaultDetachKeys
// TODO - ideally we should expose a `type LockType string` along with
// constants.
c.LockType = "shm"
if rootless.IsRootless() {
home, err := util.HomeDir()
if err != nil {
return nil, err
}
sigPath := filepath.Join(home, _defaultRootlessSignaturePolicyPath)
if _, err := os.Stat(sigPath); err == nil {
c.SignaturePolicyPath = sigPath
}
}
return c, nil
}
func defaultTmpDir() (string, error) {
if !rootless.IsRootless() {
return "/var/run/libpod", nil
}
runtimeDir, err := util.GetRuntimeDir()
if err != nil {
return "", err
}
libpodRuntimeDir := filepath.Join(runtimeDir, "libpod")
if err := os.Mkdir(libpodRuntimeDir, 0700|os.ModeSticky); err != nil {
if !os.IsExist(err) {
return "", errors.Wrapf(err, "cannot mkdir %s", libpodRuntimeDir)
} else if err := os.Chmod(libpodRuntimeDir, 0700|os.ModeSticky); err != nil {
// The directory already exist, just set the sticky bit
return "", errors.Wrapf(err, "could not set sticky bit on %s", libpodRuntimeDir)
}
}
return filepath.Join(libpodRuntimeDir, "tmp"), nil
}

183
libpod/config/merge.go Normal file
View file

@ -0,0 +1,183 @@
package config
import (
"path/filepath"
"github.com/containers/libpod/libpod/define"
"github.com/sirupsen/logrus"
)
// Merge merges the other config into the current one. Note that a field of the
// other config is only merged when it's not already set in the current one.
//
// Note that the StateType and the StorageConfig will NOT be changed.
func (c *Config) mergeConfig(other *Config) error {
// strings
c.CgroupManager = mergeStrings(c.CgroupManager, other.CgroupManager)
c.CNIConfigDir = mergeStrings(c.CNIConfigDir, other.CNIConfigDir)
c.CNIDefaultNetwork = mergeStrings(c.CNIDefaultNetwork, other.CNIDefaultNetwork)
c.DefaultMountsFile = mergeStrings(c.DefaultMountsFile, other.DefaultMountsFile)
c.DetachKeys = mergeStrings(c.DetachKeys, other.DetachKeys)
c.EventsLogFilePath = mergeStrings(c.EventsLogFilePath, other.EventsLogFilePath)
c.EventsLogger = mergeStrings(c.EventsLogger, other.EventsLogger)
c.ImageDefaultTransport = mergeStrings(c.ImageDefaultTransport, other.ImageDefaultTransport)
c.InfraCommand = mergeStrings(c.InfraCommand, other.InfraCommand)
c.InfraImage = mergeStrings(c.InfraImage, other.InfraImage)
c.InitPath = mergeStrings(c.InitPath, other.InitPath)
c.LockType = mergeStrings(c.LockType, other.LockType)
c.Namespace = mergeStrings(c.Namespace, other.Namespace)
c.NetworkCmdPath = mergeStrings(c.NetworkCmdPath, other.NetworkCmdPath)
c.OCIRuntime = mergeStrings(c.OCIRuntime, other.OCIRuntime)
c.SignaturePolicyPath = mergeStrings(c.SignaturePolicyPath, other.SignaturePolicyPath)
c.StaticDir = mergeStrings(c.StaticDir, other.StaticDir)
c.TmpDir = mergeStrings(c.TmpDir, other.TmpDir)
c.VolumePath = mergeStrings(c.VolumePath, other.VolumePath)
// string map of slices
c.OCIRuntimes = mergeStringMaps(c.OCIRuntimes, other.OCIRuntimes)
// string slices
c.CNIPluginDir = mergeStringSlices(c.CNIPluginDir, other.CNIPluginDir)
c.ConmonEnvVars = mergeStringSlices(c.ConmonEnvVars, other.ConmonEnvVars)
c.ConmonPath = mergeStringSlices(c.ConmonPath, other.ConmonPath)
c.HooksDir = mergeStringSlices(c.HooksDir, other.HooksDir)
c.RuntimePath = mergeStringSlices(c.RuntimePath, other.RuntimePath)
c.RuntimeSupportsJSON = mergeStringSlices(c.RuntimeSupportsJSON, other.RuntimeSupportsJSON)
c.RuntimeSupportsNoCgroups = mergeStringSlices(c.RuntimeSupportsNoCgroups, other.RuntimeSupportsNoCgroups)
// int64s
c.MaxLogSize = mergeInt64s(c.MaxLogSize, other.MaxLogSize)
// uint32s
c.NumLocks = mergeUint32s(c.NumLocks, other.NumLocks)
// bools
c.EnableLabeling = mergeBools(c.EnableLabeling, other.EnableLabeling)
c.EnablePortReservation = mergeBools(c.EnablePortReservation, other.EnablePortReservation)
c.NoPivotRoot = mergeBools(c.NoPivotRoot, other.NoPivotRoot)
c.SDNotify = mergeBools(c.SDNotify, other.SDNotify)
// state type
if c.StateType == define.InvalidStateStore {
c.StateType = other.StateType
}
// store options - need to check all fields since some configs might only
// set it partially
c.StorageConfig.RunRoot = mergeStrings(c.StorageConfig.RunRoot, other.StorageConfig.RunRoot)
c.StorageConfig.GraphRoot = mergeStrings(c.StorageConfig.GraphRoot, other.StorageConfig.GraphRoot)
c.StorageConfig.GraphDriverName = mergeStrings(c.StorageConfig.GraphDriverName, other.StorageConfig.GraphDriverName)
c.StorageConfig.GraphDriverOptions = mergeStringSlices(c.StorageConfig.GraphDriverOptions, other.StorageConfig.GraphDriverOptions)
if c.StorageConfig.UIDMap == nil {
c.StorageConfig.UIDMap = other.StorageConfig.UIDMap
}
if c.StorageConfig.GIDMap == nil {
c.StorageConfig.GIDMap = other.StorageConfig.GIDMap
}
// backwards compat *Set fields
c.StorageConfigRunRootSet = mergeBools(c.StorageConfigRunRootSet, other.StorageConfigRunRootSet)
c.StorageConfigGraphRootSet = mergeBools(c.StorageConfigGraphRootSet, other.StorageConfigGraphRootSet)
c.StorageConfigGraphDriverNameSet = mergeBools(c.StorageConfigGraphDriverNameSet, other.StorageConfigGraphDriverNameSet)
c.VolumePathSet = mergeBools(c.VolumePathSet, other.VolumePathSet)
c.StaticDirSet = mergeBools(c.StaticDirSet, other.StaticDirSet)
c.TmpDirSet = mergeBools(c.TmpDirSet, other.TmpDirSet)
return nil
}
// MergeDBConfig merges the configuration from the database.
func (c *Config) MergeDBConfig(dbConfig *DBConfig) error {
if !c.StorageConfigRunRootSet && dbConfig.StorageTmp != "" {
if c.StorageConfig.RunRoot != dbConfig.StorageTmp &&
c.StorageConfig.RunRoot != "" {
logrus.Debugf("Overriding run root %q with %q from database",
c.StorageConfig.RunRoot, dbConfig.StorageTmp)
}
c.StorageConfig.RunRoot = dbConfig.StorageTmp
}
if !c.StorageConfigGraphRootSet && dbConfig.StorageRoot != "" {
if c.StorageConfig.GraphRoot != dbConfig.StorageRoot &&
c.StorageConfig.GraphRoot != "" {
logrus.Debugf("Overriding graph root %q with %q from database",
c.StorageConfig.GraphRoot, dbConfig.StorageRoot)
}
c.StorageConfig.GraphRoot = dbConfig.StorageRoot
}
if !c.StorageConfigGraphDriverNameSet && dbConfig.GraphDriver != "" {
if c.StorageConfig.GraphDriverName != dbConfig.GraphDriver &&
c.StorageConfig.GraphDriverName != "" {
logrus.Errorf("User-selected graph driver %q overwritten by graph driver %q from database - delete libpod local files to resolve",
c.StorageConfig.GraphDriverName, dbConfig.GraphDriver)
}
c.StorageConfig.GraphDriverName = dbConfig.GraphDriver
}
if !c.StaticDirSet && dbConfig.LibpodRoot != "" {
if c.StaticDir != dbConfig.LibpodRoot && c.StaticDir != "" {
logrus.Debugf("Overriding static dir %q with %q from database", c.StaticDir, dbConfig.LibpodRoot)
}
c.StaticDir = dbConfig.LibpodRoot
}
if !c.TmpDirSet && dbConfig.LibpodTmp != "" {
if c.TmpDir != dbConfig.LibpodTmp && c.TmpDir != "" {
logrus.Debugf("Overriding tmp dir %q with %q from database", c.TmpDir, dbConfig.LibpodTmp)
}
c.TmpDir = dbConfig.LibpodTmp
c.EventsLogFilePath = filepath.Join(dbConfig.LibpodTmp, "events", "events.log")
}
if !c.VolumePathSet && dbConfig.VolumePath != "" {
if c.VolumePath != dbConfig.VolumePath && c.VolumePath != "" {
logrus.Debugf("Overriding volume path %q with %q from database", c.VolumePath, dbConfig.VolumePath)
}
c.VolumePath = dbConfig.VolumePath
}
return nil
}
func mergeStrings(a, b string) string {
if a == "" {
return b
}
return a
}
func mergeStringSlices(a, b []string) []string {
if len(a) == 0 && b != nil {
return b
}
return a
}
func mergeStringMaps(a, b map[string][]string) map[string][]string {
if len(a) == 0 && b != nil {
return b
}
return a
}
func mergeInt64s(a, b int64) int64 {
if a == 0 {
return b
}
return a
}
func mergeUint32s(a, b uint32) uint32 {
if a == 0 {
return b
}
return a
}
func mergeBools(a, b bool) bool {
if !a {
return b
}
return a
}

157
libpod/config/merge_test.go Normal file
View file

@ -0,0 +1,157 @@
package config
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestMergeStrings(t *testing.T) {
testData := []struct {
a string
b string
res string
}{
{"", "", ""},
{"a", "", "a"},
{"a", "b", "a"},
{"", "b", "b"},
}
for _, data := range testData {
res := mergeStrings(data.a, data.b)
assert.Equal(t, data.res, res)
}
}
func TestMergeStringSlices(t *testing.T) {
testData := []struct {
a []string
b []string
res []string
}{
{
nil, nil, nil,
},
{
nil,
[]string{},
[]string{},
},
{
[]string{},
nil,
[]string{},
},
{
[]string{},
[]string{},
[]string{},
},
{
[]string{"a"},
[]string{},
[]string{"a"},
},
{
[]string{"a"},
[]string{"b"},
[]string{"a"},
},
{
[]string{},
[]string{"b"},
[]string{"b"},
},
}
for _, data := range testData {
res := mergeStringSlices(data.a, data.b)
assert.Equal(t, data.res, res)
}
}
func TestMergeStringMaps(t *testing.T) {
testData := []struct {
a map[string][]string
b map[string][]string
res map[string][]string
}{
{
nil, nil, nil,
},
{
nil,
map[string][]string{},
map[string][]string{}},
{
map[string][]string{"a": {"a"}},
nil,
map[string][]string{"a": {"a"}},
},
{
nil,
map[string][]string{"b": {"b"}},
map[string][]string{"b": {"b"}},
},
{
map[string][]string{"a": {"a"}},
map[string][]string{"b": {"b"}},
map[string][]string{"a": {"a"}},
},
}
for _, data := range testData {
res := mergeStringMaps(data.a, data.b)
assert.Equal(t, data.res, res)
}
}
func TestMergeInts64(t *testing.T) {
testData := []struct {
a int64
b int64
res int64
}{
{int64(0), int64(0), int64(0)},
{int64(1), int64(0), int64(1)},
{int64(0), int64(1), int64(1)},
{int64(2), int64(1), int64(2)},
{int64(-1), int64(1), int64(-1)},
{int64(0), int64(-1), int64(-1)},
}
for _, data := range testData {
res := mergeInt64s(data.a, data.b)
assert.Equal(t, data.res, res)
}
}
func TestMergeUint32(t *testing.T) {
testData := []struct {
a uint32
b uint32
res uint32
}{
{uint32(0), uint32(0), uint32(0)},
{uint32(1), uint32(0), uint32(1)},
{uint32(0), uint32(1), uint32(1)},
{uint32(2), uint32(1), uint32(2)},
}
for _, data := range testData {
res := mergeUint32s(data.a, data.b)
assert.Equal(t, data.res, res)
}
}
func TestMergeBools(t *testing.T) {
testData := []struct {
a bool
b bool
res bool
}{
{false, false, false},
{true, false, true},
{false, true, true},
{true, true, true},
}
for _, data := range testData {
res := mergeBools(data.a, data.b)
assert.Equal(t, data.res, res)
}
}

0
libpod/config/testdata/empty.conf vendored Normal file
View file

1
libpod/config/testdata/libpod.conf vendored Symbolic link
View file

@ -0,0 +1 @@
../../../libpod.conf

View file

@ -1059,9 +1059,9 @@ func (c *Container) NamespacePath(linuxNS LinuxNS) (string, error) { //nolint:in
// CGroupPath returns a cgroups "path" for a given container. // CGroupPath returns a cgroups "path" for a given container.
func (c *Container) CGroupPath() (string, error) { func (c *Container) CGroupPath() (string, error) {
switch c.runtime.config.CgroupManager { switch c.runtime.config.CgroupManager {
case CgroupfsCgroupsManager: case define.CgroupfsCgroupsManager:
return filepath.Join(c.config.CgroupParent, fmt.Sprintf("libpod-%s", c.ID())), nil return filepath.Join(c.config.CgroupParent, fmt.Sprintf("libpod-%s", c.ID())), nil
case SystemdCgroupsManager: case define.SystemdCgroupsManager:
if rootless.IsRootless() { if rootless.IsRootless() {
uid := rootless.GetRootlessUID() uid := rootless.GetRootlessUID()
return filepath.Join(c.config.CgroupParent, fmt.Sprintf("user-%d.slice/user@%d.service/user.slice", uid, uid), createUnitName("libpod", c.ID())), nil return filepath.Join(c.config.CgroupParent, fmt.Sprintf("user-%d.slice/user@%d.service/user.slice", uid, uid), createUnitName("libpod", c.ID())), nil

View file

@ -1322,9 +1322,9 @@ func (c *Container) generateInspectContainerHostConfig(ctrSpec *spec.Spec, named
// Need to check if it's the default, and not print if so. // Need to check if it's the default, and not print if so.
defaultCgroupParent := "" defaultCgroupParent := ""
switch c.runtime.config.CgroupManager { switch c.runtime.config.CgroupManager {
case CgroupfsCgroupsManager: case define.CgroupfsCgroupsManager:
defaultCgroupParent = CgroupfsDefaultCgroupParent defaultCgroupParent = CgroupfsDefaultCgroupParent
case SystemdCgroupsManager: case define.SystemdCgroupsManager:
defaultCgroupParent = SystemdDefaultCgroupParent defaultCgroupParent = SystemdDefaultCgroupParent
} }
if c.config.CgroupParent != defaultCgroupParent { if c.config.CgroupParent != defaultCgroupParent {

View file

@ -1326,14 +1326,14 @@ func (c *Container) getOCICgroupPath() (string, error) {
} }
if (rootless.IsRootless() && !unified) || c.config.NoCgroups { if (rootless.IsRootless() && !unified) || c.config.NoCgroups {
return "", nil return "", nil
} else if c.runtime.config.CgroupManager == SystemdCgroupsManager { } else if c.runtime.config.CgroupManager == define.SystemdCgroupsManager {
// When runc is set to use Systemd as a cgroup manager, it // When runc is set to use Systemd as a cgroup manager, it
// expects cgroups to be passed as follows: // expects cgroups to be passed as follows:
// slice:prefix:name // slice:prefix:name
systemdCgroups := fmt.Sprintf("%s:libpod:%s", path.Base(c.config.CgroupParent), c.ID()) systemdCgroups := fmt.Sprintf("%s:libpod:%s", path.Base(c.config.CgroupParent), c.ID())
logrus.Debugf("Setting CGroups for container %s to %s", c.ID(), systemdCgroups) logrus.Debugf("Setting CGroups for container %s to %s", c.ID(), systemdCgroups)
return systemdCgroups, nil return systemdCgroups, nil
} else if c.runtime.config.CgroupManager == CgroupfsCgroupsManager { } else if c.runtime.config.CgroupManager == define.CgroupfsCgroupsManager {
cgroupPath, err := c.CGroupPath() cgroupPath, err := c.CGroupPath()
if err != nil { if err != nil {
return "", err return "", err

View file

@ -7,11 +7,23 @@ var (
DefaultInfraImage = "k8s.gcr.io/pause:3.1" DefaultInfraImage = "k8s.gcr.io/pause:3.1"
// DefaultInfraCommand to be run in an infra container // DefaultInfraCommand to be run in an infra container
DefaultInfraCommand = "/pause" DefaultInfraCommand = "/pause"
// DefaultSHMLockPath is the default path for SHM locks
DefaultSHMLockPath = "/libpod_lock"
// DefaultRootlessSHMLockPath is the default path for rootless SHM locks
DefaultRootlessSHMLockPath = "/libpod_rootless_lock"
// DefaultDetachKeys is the default keys sequence for detaching a
// container
DefaultDetachKeys = "ctrl-p,ctrl-q"
) )
// CtrRemoveTimeout is the default number of seconds to wait after stopping a container const (
// before sending the kill signal // CtrRemoveTimeout is the default number of seconds to wait after stopping a container
const CtrRemoveTimeout = 10 // before sending the kill signal
CtrRemoveTimeout = 10
// DefaultTransport is a prefix that we apply to an image name
// to check docker hub first for the image
DefaultTransport = "docker://"
)
// InfoData holds the info type, i.e store, host etc and the data for each type // InfoData holds the info type, i.e store, host etc and the data for each type
type InfoData struct { type InfoData struct {

37
libpod/define/runtime.go Normal file
View file

@ -0,0 +1,37 @@
package define
import "time"
// RuntimeStateStore is a constant indicating which state store implementation
// should be used by libpod
type RuntimeStateStore int
const (
// InvalidStateStore is an invalid state store
InvalidStateStore RuntimeStateStore = iota
// InMemoryStateStore is an in-memory state that will not persist data
// on containers and pods between libpod instances or after system
// reboot
InMemoryStateStore RuntimeStateStore = iota
// SQLiteStateStore is a state backed by a SQLite database
// It is presently disabled
SQLiteStateStore RuntimeStateStore = iota
// BoltDBStateStore is a state backed by a BoltDB database
BoltDBStateStore RuntimeStateStore = iota
// CgroupfsCgroupsManager represents cgroupfs native cgroup manager
CgroupfsCgroupsManager = "cgroupfs"
// SystemdCgroupsManager represents systemd native cgroup manager
SystemdCgroupsManager = "systemd"
// ContainerCreateTimeout is the timeout before we decide we've failed
// to create a container.
// TODO: Make this generic - all OCI runtime operations should use the
// same timeout, this one.
// TODO: Consider dropping from 240 to 60 seconds. I don't think waiting
// 4 minutes versus 1 minute makes a real difference.
ContainerCreateTimeout = 240 * time.Second
// DefaultShmSize is the default shm size
DefaultShmSize = 64 * 1024 * 1024
// NsRunDir is the default directory in which running network namespaces
// are stored
NsRunDir = "/var/run/netns"
)

View file

@ -3,6 +3,7 @@ package libpod
import ( import (
"strings" "strings"
"github.com/containers/libpod/libpod/config"
"github.com/containers/libpod/libpod/define" "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/registrar" "github.com/containers/libpod/pkg/registrar"
"github.com/containers/storage/pkg/truncindex" "github.com/containers/storage/pkg/truncindex"
@ -80,8 +81,8 @@ func (s *InMemoryState) Refresh() error {
// GetDBConfig is not implemented for in-memory state. // GetDBConfig is not implemented for in-memory state.
// As we do not store a config, return an empty one. // As we do not store a config, return an empty one.
func (s *InMemoryState) GetDBConfig() (*DBConfig, error) { func (s *InMemoryState) GetDBConfig() (*config.DBConfig, error) {
return &DBConfig{}, nil return &config.DBConfig{}, nil
} }
// ValidateDBConfig is not implemented for the in-memory state. // ValidateDBConfig is not implemented for the in-memory state.

View file

@ -152,7 +152,7 @@ func (c *Container) attachToExec(streams *AttachStreams, keys string, resize <-c
func processDetachKeys(keys string) ([]byte, error) { func processDetachKeys(keys string) ([]byte, error) {
// Check the validity of the provided keys first // Check the validity of the provided keys first
if len(keys) == 0 { if len(keys) == 0 {
keys = DefaultDetachKeys keys = define.DefaultDetachKeys
} }
detachKeys, err := term.ToBytes(keys) detachKeys, err := term.ToBytes(keys)
if err != nil { if err != nil {

View file

@ -16,6 +16,7 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/containers/libpod/libpod/config"
"github.com/containers/libpod/libpod/define" "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/cgroups" "github.com/containers/libpod/pkg/cgroups"
"github.com/containers/libpod/pkg/errorhandling" "github.com/containers/libpod/pkg/errorhandling"
@ -58,7 +59,7 @@ type ConmonOCIRuntime struct {
// The first path that points to a valid executable will be used. // The first path that points to a valid executable will be used.
// Deliberately private. Someone should not be able to construct this outside of // Deliberately private. Someone should not be able to construct this outside of
// libpod. // libpod.
func newConmonOCIRuntime(name string, paths []string, conmonPath string, runtimeCfg *RuntimeConfig, supportsJSON, supportsNoCgroups bool) (OCIRuntime, error) { func newConmonOCIRuntime(name string, paths []string, conmonPath string, runtimeCfg *config.Config, supportsJSON, supportsNoCgroups bool) (OCIRuntime, error) {
if name == "" { if name == "" {
return nil, errors.Wrapf(define.ErrInvalidArg, "the OCI runtime must be provided a non-empty name") return nil, errors.Wrapf(define.ErrInvalidArg, "the OCI runtime must be provided a non-empty name")
} }
@ -114,7 +115,7 @@ func newConmonOCIRuntime(name string, paths []string, conmonPath string, runtime
runtime.exitsDir = filepath.Join(runtime.tmpDir, "exits") runtime.exitsDir = filepath.Join(runtime.tmpDir, "exits")
runtime.socketsDir = filepath.Join(runtime.tmpDir, "socket") runtime.socketsDir = filepath.Join(runtime.tmpDir, "socket")
if runtime.cgroupManager != CgroupfsCgroupsManager && runtime.cgroupManager != SystemdCgroupsManager { if runtime.cgroupManager != define.CgroupfsCgroupsManager && runtime.cgroupManager != define.SystemdCgroupsManager {
return nil, errors.Wrapf(define.ErrInvalidArg, "invalid cgroup manager specified: %s", runtime.cgroupManager) return nil, errors.Wrapf(define.ErrInvalidArg, "invalid cgroup manager specified: %s", runtime.cgroupManager)
} }
@ -1092,7 +1093,7 @@ func (r *ConmonOCIRuntime) configureConmonEnv(runtimeDir string) ([]string, []*o
env = append(env, fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)) env = append(env, fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir))
env = append(env, fmt.Sprintf("_CONTAINERS_USERNS_CONFIGURED=%s", os.Getenv("_CONTAINERS_USERNS_CONFIGURED"))) env = append(env, fmt.Sprintf("_CONTAINERS_USERNS_CONFIGURED=%s", os.Getenv("_CONTAINERS_USERNS_CONFIGURED")))
env = append(env, fmt.Sprintf("_CONTAINERS_ROOTLESS_UID=%s", os.Getenv("_CONTAINERS_ROOTLESS_UID"))) env = append(env, fmt.Sprintf("_CONTAINERS_ROOTLESS_UID=%s", os.Getenv("_CONTAINERS_ROOTLESS_UID")))
home, err := homeDir() home, err := util.HomeDir()
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -1118,7 +1119,7 @@ func (r *ConmonOCIRuntime) configureConmonEnv(runtimeDir string) ([]string, []*o
func (r *ConmonOCIRuntime) sharedConmonArgs(ctr *Container, cuuid, bundlePath, pidPath, logPath, exitDir, ociLogPath string) []string { func (r *ConmonOCIRuntime) sharedConmonArgs(ctr *Container, cuuid, bundlePath, pidPath, logPath, exitDir, ociLogPath string) []string {
// set the conmon API version to be able to use the correct sync struct keys // set the conmon API version to be able to use the correct sync struct keys
args := []string{"--api-version", "1"} args := []string{"--api-version", "1"}
if r.cgroupManager == SystemdCgroupsManager && !ctr.config.NoCgroups { if r.cgroupManager == define.SystemdCgroupsManager && !ctr.config.NoCgroups {
args = append(args, "-s") args = append(args, "-s")
} }
args = append(args, "-c", ctr.ID()) args = append(args, "-c", ctr.ID())
@ -1230,7 +1231,7 @@ func (r *ConmonOCIRuntime) moveConmonToCgroupAndSignal(ctr *Container, cmd *exec
if mustCreateCgroup { if mustCreateCgroup {
cgroupParent := ctr.CgroupParent() cgroupParent := ctr.CgroupParent()
if r.cgroupManager == SystemdCgroupsManager { if r.cgroupManager == define.SystemdCgroupsManager {
unitName := createUnitName("libpod-conmon", ctr.ID()) unitName := createUnitName("libpod-conmon", ctr.ID())
realCgroupParent := cgroupParent realCgroupParent := cgroupParent
@ -1353,7 +1354,7 @@ func readConmonPipeData(pipe *os.File, ociLog string) (int, error) {
return ss.si.Data, errors.Wrapf(define.ErrInternal, "container create failed") return ss.si.Data, errors.Wrapf(define.ErrInternal, "container create failed")
} }
data = ss.si.Data data = ss.si.Data
case <-time.After(ContainerCreateTimeout): case <-time.After(define.ContainerCreateTimeout):
return -1, errors.Wrapf(define.ErrInternal, "container creation timeout") return -1, errors.Wrapf(define.ErrInternal, "container creation timeout")
} }
return data, nil return data, nil

View file

@ -3,6 +3,7 @@
package libpod package libpod
import ( import (
"github.com/containers/libpod/libpod/config"
"github.com/containers/libpod/libpod/define" "github.com/containers/libpod/libpod/define"
) )
@ -15,7 +16,7 @@ type ConmonOCIRuntime struct {
} }
// newConmonOCIRuntime is not supported on this OS. // newConmonOCIRuntime is not supported on this OS.
func newConmonOCIRuntime(name string, paths []string, conmonPath string, runtimeCfg *RuntimeConfig, supportsJSON, supportsNoCgroups bool) (OCIRuntime, error) { func newConmonOCIRuntime(name string, paths []string, conmonPath string, runtimeCfg *config.Config, supportsJSON, supportsNoCgroups bool) (OCIRuntime, error) {
return nil, define.ErrNotImplemented return nil, define.ErrNotImplemented
} }

View file

@ -14,29 +14,9 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
const ( // Timeout before declaring that runtime has failed to kill a given
// CgroupfsCgroupsManager represents cgroupfs native cgroup manager // container
CgroupfsCgroupsManager = "cgroupfs" const killContainerTimeout = 5 * time.Second
// SystemdCgroupsManager represents systemd native cgroup manager
SystemdCgroupsManager = "systemd"
// ContainerCreateTimeout is the timeout before we decide we've failed
// to create a container.
// TODO: Make this generic - all OCI runtime operations should use the
// same timeout, this one.
// TODO: Consider dropping from 240 to 60 seconds. I don't think waiting
// 4 minutes versus 1 minute makes a real difference.
ContainerCreateTimeout = 240 * time.Second
// Timeout before declaring that runtime has failed to kill a given
// container
killContainerTimeout = 5 * time.Second
// DefaultShmSize is the default shm size
DefaultShmSize = 64 * 1024 * 1024
// NsRunDir is the default directory in which running network namespaces
// are stored
NsRunDir = "/var/run/netns"
)
// ociError is used to parse the OCI runtime JSON log. It is not part of the // ociError is used to parse the OCI runtime JSON log. It is not part of the
// OCI runtime specifications, it follows what runc does // OCI runtime specifications, it follows what runc does

View file

@ -39,30 +39,30 @@ func WithStorageConfig(config storage.StoreOptions) RuntimeOption {
if config.RunRoot != "" { if config.RunRoot != "" {
rt.config.StorageConfig.RunRoot = config.RunRoot rt.config.StorageConfig.RunRoot = config.RunRoot
rt.configuredFrom.storageRunRootSet = true rt.config.StorageConfigRunRootSet = true
setField = true setField = true
} }
if config.GraphRoot != "" { if config.GraphRoot != "" {
rt.config.StorageConfig.GraphRoot = config.GraphRoot rt.config.StorageConfig.GraphRoot = config.GraphRoot
rt.configuredFrom.storageGraphRootSet = true rt.config.StorageConfigGraphRootSet = true
// Also set libpod static dir, so we are a subdirectory // Also set libpod static dir, so we are a subdirectory
// of the c/storage store by default // of the c/storage store by default
rt.config.StaticDir = filepath.Join(config.GraphRoot, "libpod") rt.config.StaticDir = filepath.Join(config.GraphRoot, "libpod")
rt.configuredFrom.libpodStaticDirSet = true rt.config.StaticDirSet = true
// Also set libpod volume path, so we are a subdirectory // Also set libpod volume path, so we are a subdirectory
// of the c/storage store by default // of the c/storage store by default
rt.config.VolumePath = filepath.Join(config.GraphRoot, "volumes") rt.config.VolumePath = filepath.Join(config.GraphRoot, "volumes")
rt.configuredFrom.volPathSet = true rt.config.VolumePathSet = true
setField = true setField = true
} }
if config.GraphDriverName != "" { if config.GraphDriverName != "" {
rt.config.StorageConfig.GraphDriverName = config.GraphDriverName rt.config.StorageConfig.GraphDriverName = config.GraphDriverName
rt.configuredFrom.storageGraphDriverSet = true rt.config.StorageConfigGraphDriverNameSet = true
setField = true setField = true
} }
@ -135,13 +135,13 @@ func WithSignaturePolicy(path string) RuntimeOption {
// Please note that information is not portable between backing states. // Please note that information is not portable between backing states.
// As such, if this differs between two libpods running on the same system, // As such, if this differs between two libpods running on the same system,
// they will not share containers, and unspecified behavior may occur. // they will not share containers, and unspecified behavior may occur.
func WithStateType(storeType RuntimeStateStore) RuntimeOption { func WithStateType(storeType define.RuntimeStateStore) RuntimeOption {
return func(rt *Runtime) error { return func(rt *Runtime) error {
if rt.valid { if rt.valid {
return define.ErrRuntimeFinalized return define.ErrRuntimeFinalized
} }
if storeType == InvalidStateStore { if storeType == define.InvalidStateStore {
return errors.Wrapf(define.ErrInvalidArg, "must provide a valid state store type") return errors.Wrapf(define.ErrInvalidArg, "must provide a valid state store type")
} }
@ -224,9 +224,9 @@ func WithCgroupManager(manager string) RuntimeOption {
return define.ErrRuntimeFinalized return define.ErrRuntimeFinalized
} }
if manager != CgroupfsCgroupsManager && manager != SystemdCgroupsManager { if manager != define.CgroupfsCgroupsManager && manager != define.SystemdCgroupsManager {
return errors.Wrapf(define.ErrInvalidArg, "CGroup manager must be one of %s and %s", return errors.Wrapf(define.ErrInvalidArg, "CGroup manager must be one of %s and %s",
CgroupfsCgroupsManager, SystemdCgroupsManager) define.CgroupfsCgroupsManager, define.SystemdCgroupsManager)
} }
rt.config.CgroupManager = manager rt.config.CgroupManager = manager
@ -244,7 +244,7 @@ func WithStaticDir(dir string) RuntimeOption {
} }
rt.config.StaticDir = dir rt.config.StaticDir = dir
rt.configuredFrom.libpodStaticDirSet = true rt.config.StaticDirSet = true
return nil return nil
} }
@ -295,7 +295,7 @@ func WithTmpDir(dir string) RuntimeOption {
return define.ErrRuntimeFinalized return define.ErrRuntimeFinalized
} }
rt.config.TmpDir = dir rt.config.TmpDir = dir
rt.configuredFrom.libpodTmpDirSet = true rt.config.TmpDirSet = true
return nil return nil
} }
@ -395,7 +395,7 @@ func WithVolumePath(volPath string) RuntimeOption {
} }
rt.config.VolumePath = volPath rt.config.VolumePath = volPath
rt.configuredFrom.volPathSet = true rt.config.VolumePathSet = true
return nil return nil
} }

View file

@ -66,13 +66,13 @@ func (p *Pod) refresh() error {
// We need to recreate the pod's cgroup // We need to recreate the pod's cgroup
if p.config.UsePodCgroup { if p.config.UsePodCgroup {
switch p.runtime.config.CgroupManager { switch p.runtime.config.CgroupManager {
case SystemdCgroupsManager: case define.SystemdCgroupsManager:
cgroupPath, err := systemdSliceFromPath(p.config.CgroupParent, fmt.Sprintf("libpod_pod_%s", p.ID())) cgroupPath, err := systemdSliceFromPath(p.config.CgroupParent, fmt.Sprintf("libpod_pod_%s", p.ID()))
if err != nil { if err != nil {
logrus.Errorf("Error creating CGroup for pod %s: %v", p.ID(), err) logrus.Errorf("Error creating CGroup for pod %s: %v", p.ID(), err)
} }
p.state.CgroupPath = cgroupPath p.state.CgroupPath = cgroupPath
case CgroupfsCgroupsManager: case define.CgroupfsCgroupsManager:
p.state.CgroupPath = filepath.Join(p.config.CgroupParent, p.ID()) p.state.CgroupPath = filepath.Join(p.config.CgroupParent, p.ID())
logrus.Debugf("setting pod cgroup to %s", p.state.CgroupPath) logrus.Debugf("setting pod cgroup to %s", p.state.CgroupPath)

View file

@ -1,28 +1,21 @@
package libpod package libpod
import ( import (
"bytes"
"context" "context"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"os/exec"
"os/user"
"path/filepath" "path/filepath"
"regexp"
"strconv"
"strings" "strings"
"sync" "sync"
"syscall" "syscall"
"github.com/BurntSushi/toml"
is "github.com/containers/image/v5/storage" is "github.com/containers/image/v5/storage"
"github.com/containers/image/v5/types" "github.com/containers/image/v5/types"
"github.com/containers/libpod/libpod/config"
"github.com/containers/libpod/libpod/define" "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/libpod/events" "github.com/containers/libpod/libpod/events"
"github.com/containers/libpod/libpod/image" "github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/libpod/lock" "github.com/containers/libpod/libpod/lock"
"github.com/containers/libpod/pkg/cgroups"
sysreg "github.com/containers/libpod/pkg/registries" sysreg "github.com/containers/libpod/pkg/registries"
"github.com/containers/libpod/pkg/rootless" "github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/util" "github.com/containers/libpod/pkg/util"
@ -33,75 +26,13 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
// RuntimeStateStore is a constant indicating which state store implementation
// should be used by libpod
type RuntimeStateStore int
const (
// InvalidStateStore is an invalid state store
InvalidStateStore RuntimeStateStore = iota
// InMemoryStateStore is an in-memory state that will not persist data
// on containers and pods between libpod instances or after system
// reboot
InMemoryStateStore RuntimeStateStore = iota
// SQLiteStateStore is a state backed by a SQLite database
// It is presently disabled
SQLiteStateStore RuntimeStateStore = iota
// BoltDBStateStore is a state backed by a BoltDB database
BoltDBStateStore RuntimeStateStore = iota
)
var (
// InstallPrefix is the prefix where podman will be installed.
// It can be overridden at build time.
installPrefix = "/usr"
// EtcDir is the sysconfdir where podman should look for system config files.
// It can be overridden at build time.
etcDir = "/etc"
// SeccompDefaultPath defines the default seccomp path
SeccompDefaultPath = installPrefix + "/share/containers/seccomp.json"
// SeccompOverridePath if this exists it overrides the default seccomp path
SeccompOverridePath = etcDir + "/crio/seccomp.json"
// ConfigPath is the path to the libpod configuration file
// This file is loaded to replace the builtin default config before
// runtime options (e.g. WithStorageConfig) are applied.
// If it is not present, the builtin default config is used instead
// This path can be overridden when the runtime is created by using
// NewRuntimeFromConfig() instead of NewRuntime()
ConfigPath = installPrefix + "/share/containers/libpod.conf"
// OverrideConfigPath is the path to an override for the default libpod
// configuration file. If OverrideConfigPath exists, it will be used in
// place of the configuration file pointed to by ConfigPath.
OverrideConfigPath = etcDir + "/containers/libpod.conf"
// DefaultSHMLockPath is the default path for SHM locks
DefaultSHMLockPath = "/libpod_lock"
// DefaultRootlessSHMLockPath is the default path for rootless SHM locks
DefaultRootlessSHMLockPath = "/libpod_rootless_lock"
// DefaultDetachKeys is the default keys sequence for detaching a
// container
DefaultDetachKeys = "ctrl-p,ctrl-q"
// minConmonMajor is the major version required for conmon
minConmonMajor = 2
// minConmonMinor is the minor version required for conmon
minConmonMinor = 0
// minConmonPatch is the sub-minor version required for conmon
minConmonPatch = 1
)
// A RuntimeOption is a functional option which alters the Runtime created by // A RuntimeOption is a functional option which alters the Runtime created by
// NewRuntime // NewRuntime
type RuntimeOption func(*Runtime) error type RuntimeOption func(*Runtime) error
// Runtime is the core libpod runtime // Runtime is the core libpod runtime
type Runtime struct { type Runtime struct {
config *RuntimeConfig config *config.Config
state State state State
store storage.Store store storage.Store
@ -113,7 +44,6 @@ type Runtime struct {
conmonPath string conmonPath string
imageRuntime *image.Runtime imageRuntime *image.Runtime
lockManager lock.Manager lockManager lock.Manager
configuredFrom *runtimeConfiguredFrom
// doRenumber indicates that the runtime should perform a lock renumber // doRenumber indicates that the runtime should perform a lock renumber
// during initialization. // during initialization.
@ -141,223 +71,6 @@ type Runtime struct {
noStore bool noStore bool
} }
// RuntimeConfig contains configuration options used to set up the runtime
type RuntimeConfig struct {
// StorageConfig is the configuration used by containers/storage
// Not included in on-disk config, use the dedicated containers/storage
// configuration file instead
StorageConfig storage.StoreOptions `toml:"-"`
// VolumePath is the default location that named volumes will be created
// under. This convention is followed by the default volume driver, but
// may not be by other drivers.
VolumePath string `toml:"volume_path"`
// ImageDefaultTransport is the default transport method used to fetch
// images
ImageDefaultTransport string `toml:"image_default_transport"`
// SignaturePolicyPath is the path to a signature policy to use for
// validating images
// If left empty, the containers/image default signature policy will
// be used
SignaturePolicyPath string `toml:"signature_policy_path,omitempty"`
// StateType is the type of the backing state store.
// Avoid using multiple values for this with the same containers/storage
// configuration on the same system. Different state types do not
// interact, and each will see a separate set of containers, which may
// cause conflicts in containers/storage
// As such this is not exposed via the config file
StateType RuntimeStateStore `toml:"-"`
// OCIRuntime is the OCI runtime to use.
OCIRuntime string `toml:"runtime"`
// OCIRuntimes are the set of configured OCI runtimes (default is runc)
OCIRuntimes map[string][]string `toml:"runtimes"`
// RuntimeSupportsJSON is the list of the OCI runtimes that support
// --format=json.
RuntimeSupportsJSON []string `toml:"runtime_supports_json"`
// RuntimeSupportsNoCgroups is a list of OCI runtimes that support
// running containers without CGroups.
RuntimeSupportsNoCgroups []string `toml:"runtime_supports_nocgroups"`
// RuntimePath is the path to OCI runtime binary for launching
// containers.
// The first path pointing to a valid file will be used
// This is used only when there are no OCIRuntime/OCIRuntimes defined. It
// is used only to be backward compatible with older versions of Podman.
RuntimePath []string `toml:"runtime_path"`
// ConmonPath is the path to the Conmon binary used for managing
// containers
// The first path pointing to a valid file will be used
ConmonPath []string `toml:"conmon_path"`
// ConmonEnvVars are environment variables to pass to the Conmon binary
// when it is launched
ConmonEnvVars []string `toml:"conmon_env_vars"`
// CGroupManager is the CGroup Manager to use
// Valid values are "cgroupfs" and "systemd"
CgroupManager string `toml:"cgroup_manager"`
// InitPath is the path to the container-init binary.
InitPath string `toml:"init_path"`
// StaticDir is the path to a persistent directory to store container
// files
StaticDir string `toml:"static_dir"`
// TmpDir is the path to a temporary directory to store per-boot
// container files
// Must be stored in a tmpfs
TmpDir string `toml:"tmp_dir"`
// MaxLogSize is the maximum size of container logfiles
MaxLogSize int64 `toml:"max_log_size,omitempty"`
// NoPivotRoot sets whether to set no-pivot-root in the OCI runtime
NoPivotRoot bool `toml:"no_pivot_root"`
// CNIConfigDir sets the directory where CNI configuration files are
// stored
CNIConfigDir string `toml:"cni_config_dir"`
// CNIPluginDir sets a number of directories where the CNI network
// plugins can be located
CNIPluginDir []string `toml:"cni_plugin_dir"`
// CNIDefaultNetwork is the network name of the default CNI network
// to attach pods to
CNIDefaultNetwork string `toml:"cni_default_network,omitempty"`
// HooksDir holds paths to the directories containing hooks
// configuration files. When the same filename is present in in
// multiple directories, the file in the directory listed last in
// this slice takes precedence.
HooksDir []string `toml:"hooks_dir"`
// DefaultMountsFile is the path to the default mounts file for testing
// purposes only
DefaultMountsFile string `toml:"-"`
// Namespace is the libpod namespace to use.
// Namespaces are used to create scopes to separate containers and pods
// in the state.
// When namespace is set, libpod will only view containers and pods in
// the same namespace. All containers and pods created will default to
// the namespace set here.
// A namespace of "", the empty string, is equivalent to no namespace,
// and all containers and pods will be visible.
// The default namespace is "".
Namespace string `toml:"namespace,omitempty"`
// InfraImage is the image a pod infra container will use to manage namespaces
InfraImage string `toml:"infra_image"`
// InfraCommand is the command run to start up a pod infra container
InfraCommand string `toml:"infra_command"`
// EnablePortReservation determines whether libpod will reserve ports on
// the host when they are forwarded to containers.
// When enabled, when ports are forwarded to containers, they are
// held open by conmon as long as the container is running, ensuring
// that they cannot be reused by other programs on the host.
// However, this can cause significant memory usage if a container has
// many ports forwarded to it. Disabling this can save memory.
EnablePortReservation bool `toml:"enable_port_reservation"`
// EnableLabeling indicates wether libpod will support container labeling
EnableLabeling bool `toml:"label"`
// NetworkCmdPath is the path to the slirp4netns binary
NetworkCmdPath string `toml:"network_cmd_path"`
// NumLocks is the number of locks to make available for containers and
// pods.
NumLocks uint32 `toml:"num_locks,omitempty"`
// LockType is the type of locking to use.
LockType string `toml:"lock_type,omitempty"`
// EventsLogger determines where events should be logged
EventsLogger string `toml:"events_logger"`
// EventsLogFilePath is where the events log is stored.
EventsLogFilePath string `toml:"events_logfile_path"`
//DetachKeys is the sequence of keys used to detach a container
DetachKeys string `toml:"detach_keys"`
// SDNotify tells Libpod to allow containers to notify the host
// systemd of readiness using the SD_NOTIFY mechanism
SDNotify bool
// CgroupCheck verifies if the cgroup check for correct OCI runtime has been done.
CgroupCheck bool `toml:"cgroup_check,omitempty"`
}
// runtimeConfiguredFrom is a struct used during early runtime init to help
// assemble the full RuntimeConfig struct from defaults.
// It indicated whether several fields in the runtime configuration were set
// explicitly.
// If they were not, we may override them with information from the database,
// if it exists and differs from what is present in the system already.
type runtimeConfiguredFrom struct {
storageGraphDriverSet bool
storageGraphRootSet bool
storageRunRootSet bool
libpodStaticDirSet bool
libpodTmpDirSet bool
volPathSet bool
conmonPath bool
conmonEnvVars bool
initPath bool
ociRuntimes bool
runtimePath bool
cniPluginDir bool
noPivotRoot bool
runtimeSupportsJSON bool
runtimeSupportsNoCgroups bool
ociRuntime bool
}
func defaultRuntimeConfig() (RuntimeConfig, error) {
storeOpts, err := storage.DefaultStoreOptions(rootless.IsRootless(), rootless.GetRootlessUID())
if err != nil {
return RuntimeConfig{}, err
}
graphRoot := storeOpts.GraphRoot
if graphRoot == "" {
logrus.Warnf("Storage configuration is unset - using hardcoded default paths")
graphRoot = "/var/lib/containers/storage"
}
volumePath := filepath.Join(graphRoot, "volumes")
staticDir := filepath.Join(graphRoot, "libpod")
return RuntimeConfig{
// Leave this empty so containers/storage will use its defaults
StorageConfig: storage.StoreOptions{},
VolumePath: volumePath,
ImageDefaultTransport: DefaultTransport,
StateType: BoltDBStateStore,
OCIRuntime: "runc",
OCIRuntimes: map[string][]string{
"runc": {
"/usr/bin/runc",
"/usr/sbin/runc",
"/usr/local/bin/runc",
"/usr/local/sbin/runc",
"/sbin/runc",
"/bin/runc",
"/usr/lib/cri-o-runc/sbin/runc",
"/run/current-system/sw/bin/runc",
},
},
ConmonPath: []string{
"/usr/libexec/podman/conmon",
"/usr/local/lib/podman/conmon",
"/usr/bin/conmon",
"/usr/sbin/conmon",
"/usr/local/bin/conmon",
"/usr/local/sbin/conmon",
"/run/current-system/sw/bin/conmon",
},
ConmonEnvVars: []string{
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
},
InitPath: define.DefaultInitPath,
CgroupManager: SystemdCgroupsManager,
StaticDir: staticDir,
TmpDir: "",
MaxLogSize: -1,
NoPivotRoot: false,
CNIConfigDir: etcDir + "/cni/net.d/",
CNIPluginDir: []string{"/usr/libexec/cni", "/usr/lib/cni", "/usr/local/lib/cni", "/opt/cni/bin"},
InfraCommand: define.DefaultInfraCommand,
InfraImage: define.DefaultInfraImage,
EnablePortReservation: true,
EnableLabeling: true,
NumLocks: 2048,
EventsLogger: events.DefaultEventerType.String(),
DetachKeys: DefaultDetachKeys,
LockType: "shm",
}, nil
}
// SetXdgDirs ensures the XDG_RUNTIME_DIR env and XDG_CONFIG_HOME variables are set. // SetXdgDirs ensures the XDG_RUNTIME_DIR env and XDG_CONFIG_HOME variables are set.
// containers/image uses XDG_RUNTIME_DIR to locate the auth file, XDG_CONFIG_HOME is // containers/image uses XDG_RUNTIME_DIR to locate the auth file, XDG_CONFIG_HOME is
// use for the libpod.conf configuration file. // use for the libpod.conf configuration file.
@ -400,28 +113,6 @@ func SetXdgDirs() error {
return nil return nil
} }
func getDefaultTmpDir() (string, error) {
if !rootless.IsRootless() {
return "/var/run/libpod", nil
}
runtimeDir, err := util.GetRuntimeDir()
if err != nil {
return "", err
}
libpodRuntimeDir := filepath.Join(runtimeDir, "libpod")
if err := os.Mkdir(libpodRuntimeDir, 0700|os.ModeSticky); err != nil {
if !os.IsExist(err) {
return "", errors.Wrapf(err, "cannot mkdir %s", libpodRuntimeDir)
} else if err := os.Chmod(libpodRuntimeDir, 0700|os.ModeSticky); err != nil {
// The directory already exist, just set the sticky bit
return "", errors.Wrapf(err, "could not set sticky bit on %s", libpodRuntimeDir)
}
}
return filepath.Join(libpodRuntimeDir, "tmp"), nil
}
// NewRuntime creates a new container runtime // NewRuntime creates a new container runtime
// Options can be passed to override the default configuration for the runtime // Options can be passed to override the default configuration for the runtime
func NewRuntime(ctx context.Context, options ...RuntimeOption) (runtime *Runtime, err error) { func NewRuntime(ctx context.Context, options ...RuntimeOption) (runtime *Runtime, err error) {
@ -440,260 +131,14 @@ func NewRuntimeFromConfig(ctx context.Context, userConfigPath string, options ..
return newRuntimeFromConfig(ctx, userConfigPath, options...) return newRuntimeFromConfig(ctx, userConfigPath, options...)
} }
func homeDir() (string, error) {
home := os.Getenv("HOME")
if home == "" {
usr, err := user.LookupId(fmt.Sprintf("%d", rootless.GetRootlessUID()))
if err != nil {
return "", errors.Wrapf(err, "unable to resolve HOME directory")
}
home = usr.HomeDir
}
return home, nil
}
func getRootlessConfigPath() (string, error) {
home, err := homeDir()
if err != nil {
return "", err
}
return filepath.Join(home, ".config/containers/libpod.conf"), nil
}
func getConfigPath() (string, error) {
if rootless.IsRootless() {
path, err := getRootlessConfigPath()
if err != nil {
return "", err
}
if _, err := os.Stat(path); err == nil {
return path, nil
}
return "", err
}
if _, err := os.Stat(OverrideConfigPath); err == nil {
// Use the override configuration path
return OverrideConfigPath, nil
}
if _, err := os.Stat(ConfigPath); err == nil {
return ConfigPath, nil
}
return "", nil
}
// DefaultRuntimeConfig reads default config path and returns the RuntimeConfig
func DefaultRuntimeConfig() (*RuntimeConfig, error) {
configPath, err := getConfigPath()
if err != nil {
return nil, err
}
contents, err := ioutil.ReadFile(configPath)
if err != nil {
return nil, errors.Wrapf(err, "error reading configuration file %s", configPath)
}
// This is ugly, but we need to decode twice.
// Once to check if libpod static and tmp dirs were explicitly
// set (not enough to check if they're not the default value,
// might have been explicitly configured to the default).
// A second time to actually get a usable config.
tmpConfig := new(RuntimeConfig)
if _, err := toml.Decode(string(contents), tmpConfig); err != nil {
return nil, errors.Wrapf(err, "error decoding configuration file %s",
configPath)
}
return tmpConfig, nil
}
func newRuntimeFromConfig(ctx context.Context, userConfigPath string, options ...RuntimeOption) (runtime *Runtime, err error) { func newRuntimeFromConfig(ctx context.Context, userConfigPath string, options ...RuntimeOption) (runtime *Runtime, err error) {
runtime = new(Runtime) runtime = new(Runtime)
runtime.config = new(RuntimeConfig)
runtime.configuredFrom = new(runtimeConfiguredFrom)
// Copy the default configuration conf, err := config.NewConfig(userConfigPath)
tmpDir, err := getDefaultTmpDir()
if err != nil { if err != nil {
return nil, err return nil, err
} }
runtime.config = conf
// storage.conf
storageConfFile, err := storage.DefaultConfigFile(rootless.IsRootless())
if err != nil {
return nil, err
}
createStorageConfFile := false
if _, err := os.Stat(storageConfFile); os.IsNotExist(err) {
createStorageConfFile = true
}
defRunConf, err := defaultRuntimeConfig()
if err != nil {
return nil, err
}
if err := JSONDeepCopy(defRunConf, runtime.config); err != nil {
return nil, errors.Wrapf(err, "error copying runtime default config")
}
runtime.config.TmpDir = tmpDir
storageConf, err := storage.DefaultStoreOptions(rootless.IsRootless(), rootless.GetRootlessUID())
if err != nil {
return nil, errors.Wrapf(err, "error retrieving storage config")
}
runtime.config.StorageConfig = storageConf
runtime.config.StaticDir = filepath.Join(storageConf.GraphRoot, "libpod")
runtime.config.VolumePath = filepath.Join(storageConf.GraphRoot, "volumes")
configPath, err := getConfigPath()
if err != nil {
return nil, err
}
if rootless.IsRootless() {
home, err := homeDir()
if err != nil {
return nil, err
}
if runtime.config.SignaturePolicyPath == "" {
newPath := filepath.Join(home, ".config/containers/policy.json")
if _, err := os.Stat(newPath); err == nil {
runtime.config.SignaturePolicyPath = newPath
}
}
}
if userConfigPath != "" {
configPath = userConfigPath
if _, err := os.Stat(configPath); err != nil {
// If the user specified a config file, we must fail immediately
// when it doesn't exist
return nil, errors.Wrapf(err, "cannot stat %s", configPath)
}
}
// If we have a valid configuration file, load it in
if configPath != "" {
contents, err := ioutil.ReadFile(configPath)
if err != nil {
return nil, errors.Wrapf(err, "error reading configuration file %s", configPath)
}
// This is ugly, but we need to decode twice.
// Once to check if libpod static and tmp dirs were explicitly
// set (not enough to check if they're not the default value,
// might have been explicitly configured to the default).
// A second time to actually get a usable config.
tmpConfig := new(RuntimeConfig)
if _, err := toml.Decode(string(contents), tmpConfig); err != nil {
return nil, errors.Wrapf(err, "error decoding configuration file %s",
configPath)
}
if err := cgroupV2Check(configPath, tmpConfig); err != nil {
return nil, err
}
if tmpConfig.StaticDir != "" {
runtime.configuredFrom.libpodStaticDirSet = true
}
if tmpConfig.TmpDir != "" {
runtime.configuredFrom.libpodTmpDirSet = true
}
if tmpConfig.VolumePath != "" {
runtime.configuredFrom.volPathSet = true
}
if tmpConfig.ConmonPath != nil {
runtime.configuredFrom.conmonPath = true
}
if tmpConfig.ConmonEnvVars != nil {
runtime.configuredFrom.conmonEnvVars = true
}
if tmpConfig.InitPath != "" {
runtime.configuredFrom.initPath = true
}
if tmpConfig.OCIRuntimes != nil {
runtime.configuredFrom.ociRuntimes = true
}
if tmpConfig.RuntimePath != nil {
runtime.configuredFrom.runtimePath = true
}
if tmpConfig.CNIPluginDir != nil {
runtime.configuredFrom.cniPluginDir = true
}
if tmpConfig.NoPivotRoot {
runtime.configuredFrom.noPivotRoot = true
}
if tmpConfig.RuntimeSupportsJSON != nil {
runtime.configuredFrom.runtimeSupportsJSON = true
}
if tmpConfig.RuntimeSupportsNoCgroups != nil {
runtime.configuredFrom.runtimeSupportsNoCgroups = true
}
if tmpConfig.OCIRuntime != "" {
runtime.configuredFrom.ociRuntime = true
}
if _, err := toml.Decode(string(contents), runtime.config); err != nil {
return nil, errors.Wrapf(err, "error decoding configuration file %s", configPath)
}
} else if rootless.IsRootless() {
// If the configuration file was not found but we are running in rootless, a subset of the
// global config file is used.
for _, path := range []string{OverrideConfigPath, ConfigPath} {
contents, err := ioutil.ReadFile(path)
if err != nil {
// Ignore any error, the file might not be readable by us.
continue
}
tmpConfig := new(RuntimeConfig)
if _, err := toml.Decode(string(contents), tmpConfig); err != nil {
return nil, errors.Wrapf(err, "error decoding configuration file %s", path)
}
// Cherry pick the settings we want from the global configuration
if !runtime.configuredFrom.conmonPath {
runtime.config.ConmonPath = tmpConfig.ConmonPath
}
if !runtime.configuredFrom.conmonEnvVars {
runtime.config.ConmonEnvVars = tmpConfig.ConmonEnvVars
}
if !runtime.configuredFrom.initPath {
runtime.config.InitPath = tmpConfig.InitPath
}
if !runtime.configuredFrom.ociRuntimes {
runtime.config.OCIRuntimes = tmpConfig.OCIRuntimes
}
if !runtime.configuredFrom.runtimePath {
runtime.config.RuntimePath = tmpConfig.RuntimePath
}
if !runtime.configuredFrom.cniPluginDir {
runtime.config.CNIPluginDir = tmpConfig.CNIPluginDir
}
if !runtime.configuredFrom.noPivotRoot {
runtime.config.NoPivotRoot = tmpConfig.NoPivotRoot
}
if !runtime.configuredFrom.runtimeSupportsJSON {
runtime.config.RuntimeSupportsJSON = tmpConfig.RuntimeSupportsJSON
}
if !runtime.configuredFrom.runtimeSupportsNoCgroups {
runtime.config.RuntimeSupportsNoCgroups = tmpConfig.RuntimeSupportsNoCgroups
}
if !runtime.configuredFrom.ociRuntime {
runtime.config.OCIRuntime = tmpConfig.OCIRuntime
}
cgroupsV2, err := cgroups.IsCgroup2UnifiedMode()
if err != nil {
return nil, err
}
if cgroupsV2 {
runtime.config.CgroupCheck = true
}
break
}
}
// Overwrite config with user-given configuration options // Overwrite config with user-given configuration options
for _, opt := range options { for _, opt := range options {
@ -702,36 +147,6 @@ func newRuntimeFromConfig(ctx context.Context, userConfigPath string, options ..
} }
} }
if rootless.IsRootless() && configPath == "" {
if createStorageConfFile {
if err := util.WriteStorageConfigFile(&runtime.config.StorageConfig, storageConfFile); err != nil {
return nil, errors.Wrapf(err, "cannot write config file %s", storageConfFile)
}
}
configPath, err := getRootlessConfigPath()
if err != nil {
return nil, err
}
if configPath != "" {
if err := os.MkdirAll(filepath.Dir(configPath), 0711); err != nil {
return nil, err
}
file, err := os.OpenFile(configPath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
if err != nil && !os.IsExist(err) {
return nil, errors.Wrapf(err, "cannot open file %s", configPath)
}
if err == nil {
defer file.Close()
enc := toml.NewEncoder(file)
if err := enc.Encode(runtime.config); err != nil {
if removeErr := os.Remove(configPath); removeErr != nil {
logrus.Debugf("unable to remove %s: %q", configPath, err)
}
}
}
}
}
if err := makeRuntime(ctx, runtime); err != nil { if err := makeRuntime(ctx, runtime); err != nil {
return nil, err return nil, err
} }
@ -758,9 +173,9 @@ func getLockManager(runtime *Runtime) (lock.Manager, error) {
} }
case "", "shm": case "", "shm":
lockPath := DefaultSHMLockPath lockPath := define.DefaultSHMLockPath
if rootless.IsRootless() { if rootless.IsRootless() {
lockPath = fmt.Sprintf("%s_%d", DefaultRootlessSHMLockPath, rootless.GetRootlessUID()) lockPath = fmt.Sprintf("%s_%d", define.DefaultRootlessSHMLockPath, rootless.GetRootlessUID())
} }
// Set up the lock manager // Set up the lock manager
manager, err = lock.OpenSHMLockManager(lockPath, runtime.config.NumLocks) manager, err = lock.OpenSHMLockManager(lockPath, runtime.config.NumLocks)
@ -794,119 +209,14 @@ func getLockManager(runtime *Runtime) (lock.Manager, error) {
return manager, nil return manager, nil
} }
// probeConmon calls conmon --version and verifies it is a new enough version for
// the runtime expectations podman currently has
func probeConmon(conmonBinary string) error {
versionFormatErr := "conmon version changed format"
cmd := exec.Command(conmonBinary, "--version")
var out bytes.Buffer
cmd.Stdout = &out
err := cmd.Run()
if err != nil {
return err
}
r := regexp.MustCompile(`^conmon version (?P<Major>\d+).(?P<Minor>\d+).(?P<Patch>\d+)`)
matches := r.FindStringSubmatch(out.String())
if len(matches) != 4 {
return errors.Wrapf(err, versionFormatErr)
}
major, err := strconv.Atoi(matches[1])
if err != nil {
return errors.Wrapf(err, versionFormatErr)
}
if major < minConmonMajor {
return define.ErrConmonOutdated
}
if major > minConmonMajor {
return nil
}
minor, err := strconv.Atoi(matches[2])
if err != nil {
return errors.Wrapf(err, versionFormatErr)
}
if minor < minConmonMinor {
return define.ErrConmonOutdated
}
if minor > minConmonMinor {
return nil
}
patch, err := strconv.Atoi(matches[3])
if err != nil {
return errors.Wrapf(err, versionFormatErr)
}
if patch < minConmonPatch {
return define.ErrConmonOutdated
}
if patch > minConmonPatch {
return nil
}
return nil
}
// Make a new runtime based on the given configuration // Make a new runtime based on the given configuration
// Sets up containers/storage, state store, OCI runtime // Sets up containers/storage, state store, OCI runtime
func makeRuntime(ctx context.Context, runtime *Runtime) (err error) { func makeRuntime(ctx context.Context, runtime *Runtime) (err error) {
// Let's sanity-check some paths first.
// Relative paths can cause nasty bugs, because core paths we use could
// shift between runs (or even parts of the program - the OCI runtime
// uses a different working directory than we do, for example.
if !filepath.IsAbs(runtime.config.StaticDir) {
return errors.Wrapf(define.ErrInvalidArg, "static directory must be an absolute path - instead got %q", runtime.config.StaticDir)
}
if !filepath.IsAbs(runtime.config.TmpDir) {
return errors.Wrapf(define.ErrInvalidArg, "temporary directory must be an absolute path - instead got %q", runtime.config.TmpDir)
}
if !filepath.IsAbs(runtime.config.VolumePath) {
return errors.Wrapf(define.ErrInvalidArg, "volume path must be an absolute path - instead got %q", runtime.config.VolumePath)
}
// Find a working conmon binary // Find a working conmon binary
foundConmon := false if cPath, err := runtime.config.FindConmon(); err != nil {
foundOutdatedConmon := false return err
for _, path := range runtime.config.ConmonPath { } else {
stat, err := os.Stat(path) runtime.conmonPath = cPath
if err != nil {
continue
}
if stat.IsDir() {
continue
}
if err := probeConmon(path); err != nil {
logrus.Warnf("conmon at %s invalid: %v", path, err)
foundOutdatedConmon = true
continue
}
foundConmon = true
runtime.conmonPath = path
logrus.Debugf("using conmon: %q", path)
break
}
// Search the $PATH as last fallback
if !foundConmon {
if conmon, err := exec.LookPath("conmon"); err == nil {
if err := probeConmon(conmon); err != nil {
logrus.Warnf("conmon at %s is invalid: %v", conmon, err)
foundOutdatedConmon = true
} else {
foundConmon = true
runtime.conmonPath = conmon
logrus.Debugf("using conmon from $PATH: %q", conmon)
}
}
}
if !foundConmon {
if foundOutdatedConmon {
return errors.Errorf("please update to v%d.%d.%d or later: %v", minConmonMajor, minConmonMinor, minConmonPatch, define.ErrConmonOutdated)
}
return errors.Wrapf(define.ErrInvalidArg,
"could not find a working conmon binary (configured options: %v)",
runtime.config.ConmonPath)
} }
// Make the static files directory if it does not exist // Make the static files directory if it does not exist
@ -918,17 +228,22 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (err error) {
} }
} }
// Set up the state // Set up the state.
//
// TODO - if we further break out the state implementation into
// libpod/state, the config could take care of the code below. It
// would further allow to move the types and consts into a coherent
// package.
switch runtime.config.StateType { switch runtime.config.StateType {
case InMemoryStateStore: case define.InMemoryStateStore:
state, err := NewInMemoryState() state, err := NewInMemoryState()
if err != nil { if err != nil {
return err return err
} }
runtime.state = state runtime.state = state
case SQLiteStateStore: case define.SQLiteStateStore:
return errors.Wrapf(define.ErrInvalidArg, "SQLite state is currently disabled") return errors.Wrapf(define.ErrInvalidArg, "SQLite state is currently disabled")
case BoltDBStateStore: case define.BoltDBStateStore:
dbPath := filepath.Join(runtime.config.StaticDir, "bolt_state.db") dbPath := filepath.Join(runtime.config.StaticDir, "bolt_state.db")
state, err := NewBoltState(dbPath, runtime) state, err := NewBoltState(dbPath, runtime)
@ -937,7 +252,7 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (err error) {
} }
runtime.state = state runtime.state = state
default: default:
return errors.Wrapf(define.ErrInvalidArg, "unrecognized state type passed") return errors.Wrapf(define.ErrInvalidArg, "unrecognized state type passed (%v)", runtime.config.StateType)
} }
// Grab config from the database so we can reset some defaults // Grab config from the database so we can reset some defaults
@ -946,51 +261,9 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (err error) {
return errors.Wrapf(err, "error retrieving runtime configuration from database") return errors.Wrapf(err, "error retrieving runtime configuration from database")
} }
// Reset defaults if they were not explicitly set if err := runtime.config.MergeDBConfig(dbConfig); err != nil {
if !runtime.configuredFrom.storageGraphDriverSet && dbConfig.GraphDriver != "" { return errors.Wrapf(err, "error merging database config into runtime config")
if runtime.config.StorageConfig.GraphDriverName != dbConfig.GraphDriver &&
runtime.config.StorageConfig.GraphDriverName != "" {
logrus.Errorf("User-selected graph driver %q overwritten by graph driver %q from database - delete libpod local files to resolve",
runtime.config.StorageConfig.GraphDriverName, dbConfig.GraphDriver)
}
runtime.config.StorageConfig.GraphDriverName = dbConfig.GraphDriver
} }
if !runtime.configuredFrom.storageGraphRootSet && dbConfig.StorageRoot != "" {
if runtime.config.StorageConfig.GraphRoot != dbConfig.StorageRoot &&
runtime.config.StorageConfig.GraphRoot != "" {
logrus.Debugf("Overriding graph root %q with %q from database",
runtime.config.StorageConfig.GraphRoot, dbConfig.StorageRoot)
}
runtime.config.StorageConfig.GraphRoot = dbConfig.StorageRoot
}
if !runtime.configuredFrom.storageRunRootSet && dbConfig.StorageTmp != "" {
if runtime.config.StorageConfig.RunRoot != dbConfig.StorageTmp &&
runtime.config.StorageConfig.RunRoot != "" {
logrus.Debugf("Overriding run root %q with %q from database",
runtime.config.StorageConfig.RunRoot, dbConfig.StorageTmp)
}
runtime.config.StorageConfig.RunRoot = dbConfig.StorageTmp
}
if !runtime.configuredFrom.libpodStaticDirSet && dbConfig.LibpodRoot != "" {
if runtime.config.StaticDir != dbConfig.LibpodRoot && runtime.config.StaticDir != "" {
logrus.Debugf("Overriding static dir %q with %q from database", runtime.config.StaticDir, dbConfig.LibpodRoot)
}
runtime.config.StaticDir = dbConfig.LibpodRoot
}
if !runtime.configuredFrom.libpodTmpDirSet && dbConfig.LibpodTmp != "" {
if runtime.config.TmpDir != dbConfig.LibpodTmp && runtime.config.TmpDir != "" {
logrus.Debugf("Overriding tmp dir %q with %q from database", runtime.config.TmpDir, dbConfig.LibpodTmp)
}
runtime.config.TmpDir = dbConfig.LibpodTmp
}
if !runtime.configuredFrom.volPathSet && dbConfig.VolumePath != "" {
if runtime.config.VolumePath != dbConfig.VolumePath && runtime.config.VolumePath != "" {
logrus.Debugf("Overriding volume path %q with %q from database", runtime.config.VolumePath, dbConfig.VolumePath)
}
runtime.config.VolumePath = dbConfig.VolumePath
}
runtime.config.EventsLogFilePath = filepath.Join(runtime.config.TmpDir, "events", "events.log")
logrus.Debugf("Using graph driver %s", runtime.config.StorageConfig.GraphDriverName) logrus.Debugf("Using graph driver %s", runtime.config.StorageConfig.GraphDriverName)
logrus.Debugf("Using graph root %s", runtime.config.StorageConfig.GraphRoot) logrus.Debugf("Using graph root %s", runtime.config.StorageConfig.GraphRoot)
@ -1269,7 +542,7 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (err error) {
} }
// GetConfig returns a copy of the configuration used by the runtime // GetConfig returns a copy of the configuration used by the runtime
func (r *Runtime) GetConfig() (*RuntimeConfig, error) { func (r *Runtime) GetConfig() (*config.Config, error) {
r.lock.RLock() r.lock.RLock()
defer r.lock.RUnlock() defer r.lock.RUnlock()
@ -1277,7 +550,7 @@ func (r *Runtime) GetConfig() (*RuntimeConfig, error) {
return nil, define.ErrRuntimeStopped return nil, define.ErrRuntimeStopped
} }
config := new(RuntimeConfig) config := new(config.Config)
// Copy so the caller won't be able to modify the actual config // Copy so the caller won't be able to modify the actual config
if err := JSONDeepCopy(r.config, config); err != nil { if err := JSONDeepCopy(r.config, config); err != nil {
@ -1499,56 +772,3 @@ func (r *Runtime) SystemContext() *types.SystemContext {
func (r *Runtime) GetOCIRuntimePath() string { func (r *Runtime) GetOCIRuntimePath() string {
return r.defaultOCIRuntime.Path() return r.defaultOCIRuntime.Path()
} }
// Since runc does not currently support cgroupV2
// Change to default crun on first running of libpod.conf
// TODO Once runc has support for cgroups, this function should be removed.
func cgroupV2Check(configPath string, tmpConfig *RuntimeConfig) error {
if !tmpConfig.CgroupCheck && rootless.IsRootless() {
if tmpConfig.CgroupManager == SystemdCgroupsManager {
// If we are running rootless and the systemd manager is requested, be sure that dbus is accessible
session := os.Getenv("DBUS_SESSION_BUS_ADDRESS")
hasSession := session != ""
if hasSession && strings.HasPrefix(session, "unix:path=") {
_, err := os.Stat(strings.TrimPrefix(session, "unix:path="))
hasSession = err == nil
}
if !hasSession {
logrus.Warningf("The cgroups manager is set to systemd but there is no systemd user session available")
logrus.Warningf("For using systemd, you may need to login using an user session")
logrus.Warningf("Alternatively, you can enable lingering with: `loginctl enable-linger %d` (possibily as root)", rootless.GetRootlessUID())
logrus.Warningf("Falling back to --cgroup-manager=cgroupfs")
tmpConfig.CgroupManager = CgroupfsCgroupsManager
}
}
cgroupsV2, err := cgroups.IsCgroup2UnifiedMode()
if err != nil {
return err
}
if cgroupsV2 {
path, err := exec.LookPath("crun")
if err != nil {
logrus.Warnf("Can not find crun package on the host, containers might fail to run on cgroup V2 systems without crun: %q", err)
// Can't find crun path so do nothing
return nil
}
tmpConfig.CgroupCheck = true
tmpConfig.OCIRuntime = path
file, err := os.OpenFile(configPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return errors.Wrapf(err, "cannot open file %s", configPath)
}
defer file.Close()
enc := toml.NewEncoder(file)
if err := enc.Encode(tmpConfig); err != nil {
if removeErr := os.Remove(configPath); removeErr != nil {
logrus.Debugf("unable to remove %s: %q", configPath, err)
}
}
}
}
return nil
}

View file

@ -75,7 +75,7 @@ func (r *Runtime) initContainerVariables(rSpec *spec.Spec, config *ContainerConf
if config == nil { if config == nil {
ctr.config.ID = stringid.GenerateNonCryptoID() ctr.config.ID = stringid.GenerateNonCryptoID()
ctr.config.ShmSize = DefaultShmSize ctr.config.ShmSize = define.DefaultShmSize
} else { } else {
// This is a restore from an imported checkpoint // This is a restore from an imported checkpoint
ctr.restoreFromCheckpoint = true ctr.restoreFromCheckpoint = true
@ -215,7 +215,7 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (c *Contai
// Only if we're actually configuring CGroups. // Only if we're actually configuring CGroups.
if !ctr.config.NoCgroups { if !ctr.config.NoCgroups {
switch r.config.CgroupManager { switch r.config.CgroupManager {
case CgroupfsCgroupsManager: case define.CgroupfsCgroupsManager:
if ctr.config.CgroupParent == "" { if ctr.config.CgroupParent == "" {
if pod != nil && pod.config.UsePodCgroup { if pod != nil && pod.config.UsePodCgroup {
podCgroup, err := pod.CgroupPath() podCgroup, err := pod.CgroupPath()
@ -232,7 +232,7 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (c *Contai
} else if strings.HasSuffix(path.Base(ctr.config.CgroupParent), ".slice") { } else if strings.HasSuffix(path.Base(ctr.config.CgroupParent), ".slice") {
return nil, errors.Wrapf(define.ErrInvalidArg, "systemd slice received as cgroup parent when using cgroupfs") return nil, errors.Wrapf(define.ErrInvalidArg, "systemd slice received as cgroup parent when using cgroupfs")
} }
case SystemdCgroupsManager: case define.SystemdCgroupsManager:
if ctr.config.CgroupParent == "" { if ctr.config.CgroupParent == "" {
if pod != nil && pod.config.UsePodCgroup { if pod != nil && pod.config.UsePodCgroup {
podCgroup, err := pod.CgroupPath() podCgroup, err := pod.CgroupPath()

View file

@ -76,7 +76,7 @@ func (r *Runtime) NewPod(ctx context.Context, options ...PodCreateOption) (_ *Po
// Check CGroup parent sanity, and set it if it was not set // Check CGroup parent sanity, and set it if it was not set
switch r.config.CgroupManager { switch r.config.CgroupManager {
case CgroupfsCgroupsManager: case define.CgroupfsCgroupsManager:
if pod.config.CgroupParent == "" { if pod.config.CgroupParent == "" {
pod.config.CgroupParent = CgroupfsDefaultCgroupParent pod.config.CgroupParent = CgroupfsDefaultCgroupParent
} else if strings.HasSuffix(path.Base(pod.config.CgroupParent), ".slice") { } else if strings.HasSuffix(path.Base(pod.config.CgroupParent), ".slice") {
@ -89,7 +89,7 @@ func (r *Runtime) NewPod(ctx context.Context, options ...PodCreateOption) (_ *Po
if pod.config.UsePodCgroup { if pod.config.UsePodCgroup {
pod.state.CgroupPath = filepath.Join(pod.config.CgroupParent, pod.ID()) pod.state.CgroupPath = filepath.Join(pod.config.CgroupParent, pod.ID())
} }
case SystemdCgroupsManager: case define.SystemdCgroupsManager:
if pod.config.CgroupParent == "" { if pod.config.CgroupParent == "" {
if rootless.IsRootless() { if rootless.IsRootless() {
pod.config.CgroupParent = SystemdDefaultRootlessCgroupParent pod.config.CgroupParent = SystemdDefaultRootlessCgroupParent
@ -200,7 +200,7 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool)
// the pod and conmon CGroups with a PID limit to prevent them from // the pod and conmon CGroups with a PID limit to prevent them from
// spawning any further processes (particularly cleanup processes) which // spawning any further processes (particularly cleanup processes) which
// would prevent removing the CGroups. // would prevent removing the CGroups.
if p.runtime.config.CgroupManager == CgroupfsCgroupsManager { if p.runtime.config.CgroupManager == define.CgroupfsCgroupsManager {
// Get the conmon CGroup // Get the conmon CGroup
conmonCgroupPath := filepath.Join(p.state.CgroupPath, "conmon") conmonCgroupPath := filepath.Join(p.state.CgroupPath, "conmon")
conmonCgroup, err := cgroups.Load(conmonCgroupPath) conmonCgroup, err := cgroups.Load(conmonCgroupPath)
@ -251,7 +251,7 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool)
logrus.Debugf("Removing pod cgroup %s", p.state.CgroupPath) logrus.Debugf("Removing pod cgroup %s", p.state.CgroupPath)
switch p.runtime.config.CgroupManager { switch p.runtime.config.CgroupManager {
case SystemdCgroupsManager: case define.SystemdCgroupsManager:
if err := deleteSystemdCgroup(p.state.CgroupPath); err != nil { if err := deleteSystemdCgroup(p.state.CgroupPath); err != nil {
if removalErr == nil { if removalErr == nil {
removalErr = errors.Wrapf(err, "error removing pod %s cgroup", p.ID()) removalErr = errors.Wrapf(err, "error removing pod %s cgroup", p.ID())
@ -259,7 +259,7 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool)
logrus.Errorf("Error deleting pod %s cgroup %s: %v", p.ID(), p.state.CgroupPath, err) logrus.Errorf("Error deleting pod %s cgroup %s: %v", p.ID(), p.state.CgroupPath, err)
} }
} }
case CgroupfsCgroupsManager: case define.CgroupfsCgroupsManager:
// Delete the cgroupfs cgroup // Delete the cgroupfs cgroup
// Make sure the conmon cgroup is deleted first // Make sure the conmon cgroup is deleted first
// Since the pod is almost gone, don't bother failing // Since the pod is almost gone, don't bother failing

View file

@ -1,15 +1,6 @@
package libpod package libpod
// DBConfig is a set of Libpod runtime configuration settings that are saved import "github.com/containers/libpod/libpod/config"
// in a State when it is first created, and can subsequently be retrieved.
type DBConfig struct {
LibpodRoot string
LibpodTmp string
StorageRoot string
StorageTmp string
GraphDriver string
VolumePath string
}
// State is a storage backend for libpod's current state. // State is a storage backend for libpod's current state.
// A State is only initialized once per instance of libpod. // A State is only initialized once per instance of libpod.
@ -37,7 +28,7 @@ type State interface {
// root and tmp dirs, and c/storage graph driver. // root and tmp dirs, and c/storage graph driver.
// This is not implemented by the in-memory state, as it has no need to // This is not implemented by the in-memory state, as it has no need to
// validate runtime configuration. // validate runtime configuration.
GetDBConfig() (*DBConfig, error) GetDBConfig() (*config.DBConfig, error)
// ValidateDBConfig validates the config in the given Runtime struct // ValidateDBConfig validates the config in the given Runtime struct
// against paths stored in the configured database. // against paths stored in the configured database.

View file

@ -8,6 +8,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/containers/libpod/libpod/config"
"github.com/containers/libpod/libpod/define" "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/libpod/lock" "github.com/containers/libpod/libpod/lock"
"github.com/containers/storage" "github.com/containers/storage"
@ -52,7 +53,7 @@ func getEmptyBoltState() (s State, p string, m lock.Manager, err error) {
} }
runtime := new(Runtime) runtime := new(Runtime)
runtime.config = new(RuntimeConfig) runtime.config = new(config.Config)
runtime.config.StorageConfig = storage.StoreOptions{} runtime.config.StorageConfig = storage.StoreOptions{}
runtime.lockManager = lockManager runtime.lockManager = lockManager

View file

@ -10,6 +10,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/containers/libpod/libpod/config"
"github.com/containers/libpod/libpod/define" "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/utils" "github.com/containers/libpod/utils"
"github.com/fsnotify/fsnotify" "github.com/fsnotify/fsnotify"
@ -19,10 +20,6 @@ import (
// Runtime API constants // Runtime API constants
const ( const (
// DefaultTransport is a prefix that we apply to an image name
// to check docker hub first for the image
DefaultTransport = "docker://"
unknownPackage = "Unknown" unknownPackage = "Unknown"
) )
@ -191,18 +188,18 @@ func programVersion(mountProgram string) (string, error) {
} }
func DefaultSeccompPath() (string, error) { func DefaultSeccompPath() (string, error) {
_, err := os.Stat(SeccompOverridePath) _, err := os.Stat(config.SeccompOverridePath)
if err == nil { if err == nil {
return SeccompOverridePath, nil return config.SeccompOverridePath, nil
} }
if !os.IsNotExist(err) { if !os.IsNotExist(err) {
return "", errors.Wrapf(err, "can't check if %q exists", SeccompOverridePath) return "", errors.Wrapf(err, "can't check if %q exists", config.SeccompOverridePath)
} }
if _, err := os.Stat(SeccompDefaultPath); err != nil { if _, err := os.Stat(config.SeccompDefaultPath); err != nil {
if !os.IsNotExist(err) { if !os.IsNotExist(err) {
return "", errors.Wrapf(err, "can't check if %q exists", SeccompDefaultPath) return "", errors.Wrapf(err, "can't check if %q exists", config.SeccompDefaultPath)
} }
return "", nil return "", nil
} }
return SeccompDefaultPath, nil return config.SeccompDefaultPath, nil
} }

View file

@ -5,6 +5,8 @@ import (
"strings" "strings"
"github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod"
libpodconfig "github.com/containers/libpod/libpod/config"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/cgroups" "github.com/containers/libpod/pkg/cgroups"
"github.com/containers/libpod/pkg/rootless" "github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/sysinfo" "github.com/containers/libpod/pkg/sysinfo"
@ -300,7 +302,7 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
blockAccessToKernelFilesystems(config, &g) blockAccessToKernelFilesystems(config, &g)
var runtimeConfig *libpod.RuntimeConfig var runtimeConfig *libpodconfig.Config
if runtime != nil { if runtime != nil {
runtimeConfig, err = runtime.GetConfig() runtimeConfig, err = runtime.GetConfig()
@ -321,7 +323,7 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
if err != nil { if err != nil {
return nil, err return nil, err
} }
if (!cgroup2 || (runtimeConfig != nil && runtimeConfig.CgroupManager != libpod.SystemdCgroupsManager)) && config.Resources.PidsLimit == sysinfo.GetDefaultPidsLimit() { if (!cgroup2 || (runtimeConfig != nil && runtimeConfig.CgroupManager != define.SystemdCgroupsManager)) && config.Resources.PidsLimit == sysinfo.GetDefaultPidsLimit() {
setPidLimit = false setPidLimit = false
} }
} }
@ -417,7 +419,7 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
configSpec.Linux.Resources = &spec.LinuxResources{} configSpec.Linux.Resources = &spec.LinuxResources{}
} }
canUseResources := cgroup2 && runtimeConfig != nil && (runtimeConfig.CgroupManager == libpod.SystemdCgroupsManager) canUseResources := cgroup2 && runtimeConfig != nil && (runtimeConfig.CgroupManager == define.SystemdCgroupsManager)
if addedResources && !canUseResources { if addedResources && !canUseResources {
return nil, errors.New("invalid configuration, cannot specify resource limits without cgroups v2 and --cgroup-manager=systemd") return nil, errors.New("invalid configuration, cannot specify resource limits without cgroups v2 and --cgroup-manager=systemd")

View file

@ -3,6 +3,7 @@ package util
import ( import (
"fmt" "fmt"
"os" "os"
"os/user"
"path/filepath" "path/filepath"
"regexp" "regexp"
"strings" "strings"
@ -440,3 +441,16 @@ func ExitCode(err error) int {
return 126 return 126
} }
// HomeDir returns the home directory for the current user.
func HomeDir() (string, error) {
home := os.Getenv("HOME")
if home == "" {
usr, err := user.LookupId(fmt.Sprintf("%d", rootless.GetRootlessUID()))
if err != nil {
return "", errors.Wrapf(err, "unable to resolve HOME directory")
}
home = usr.HomeDir
}
return home, nil
}