mirror of
https://github.com/podman-container-tools/podman.git
synced 2026-09-06 23:57:48 +00:00
With the advent of Podman 2.0.0 we crossed the magical barrier of go modules. While we were able to continue importing all packages inside of the project, the project could not be vendored anymore from the outside. Move the go module to new major version and change all imports to github.com/containers/libpod/v2. The renaming of the imports was done via gomove [1]. [1] https://github.com/KSubedi/gomove Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
359 lines
10 KiB
Go
359 lines
10 KiB
Go
// +build !remote
|
|
|
|
package infra
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"sync"
|
|
|
|
"github.com/containers/libpod/v2/libpod"
|
|
"github.com/containers/libpod/v2/pkg/cgroups"
|
|
"github.com/containers/libpod/v2/pkg/domain/entities"
|
|
"github.com/containers/libpod/v2/pkg/namespaces"
|
|
"github.com/containers/libpod/v2/pkg/rootless"
|
|
"github.com/containers/storage"
|
|
"github.com/containers/storage/pkg/idtools"
|
|
"github.com/pkg/errors"
|
|
flag "github.com/spf13/pflag"
|
|
)
|
|
|
|
var (
|
|
// runtimeSync only guards the non-specialized runtime
|
|
runtimeSync sync.Once
|
|
// The default GetRuntime() always returns the same object and error
|
|
runtimeLib *libpod.Runtime
|
|
runtimeErr error
|
|
)
|
|
|
|
type engineOpts struct {
|
|
name string
|
|
renumber bool
|
|
migrate bool
|
|
noStore bool
|
|
withFDS bool
|
|
config *entities.PodmanConfig
|
|
}
|
|
|
|
// GetRuntimeMigrate gets a libpod runtime that will perform a migration of existing containers
|
|
func GetRuntimeMigrate(ctx context.Context, fs *flag.FlagSet, cfg *entities.PodmanConfig, newRuntime string) (*libpod.Runtime, error) {
|
|
return getRuntime(ctx, fs, &engineOpts{
|
|
name: newRuntime,
|
|
renumber: false,
|
|
migrate: true,
|
|
noStore: false,
|
|
withFDS: true,
|
|
config: cfg,
|
|
})
|
|
}
|
|
|
|
// GetRuntimeDisableFDs gets a libpod runtime that will disable sd notify
|
|
func GetRuntimeDisableFDs(ctx context.Context, fs *flag.FlagSet, cfg *entities.PodmanConfig) (*libpod.Runtime, error) {
|
|
return getRuntime(ctx, fs, &engineOpts{
|
|
renumber: false,
|
|
migrate: false,
|
|
noStore: false,
|
|
withFDS: false,
|
|
config: cfg,
|
|
})
|
|
}
|
|
|
|
// GetRuntimeRenumber gets a libpod runtime that will perform a lock renumber
|
|
func GetRuntimeRenumber(ctx context.Context, fs *flag.FlagSet, cfg *entities.PodmanConfig) (*libpod.Runtime, error) {
|
|
return getRuntime(ctx, fs, &engineOpts{
|
|
renumber: true,
|
|
migrate: false,
|
|
noStore: false,
|
|
withFDS: true,
|
|
config: cfg,
|
|
})
|
|
}
|
|
|
|
// GetRuntime generates a new libpod runtime configured by command line options
|
|
func GetRuntime(ctx context.Context, flags *flag.FlagSet, cfg *entities.PodmanConfig) (*libpod.Runtime, error) {
|
|
runtimeSync.Do(func() {
|
|
runtimeLib, runtimeErr = getRuntime(ctx, flags, &engineOpts{
|
|
renumber: false,
|
|
migrate: false,
|
|
noStore: false,
|
|
withFDS: true,
|
|
config: cfg,
|
|
})
|
|
})
|
|
return runtimeLib, runtimeErr
|
|
}
|
|
|
|
// GetRuntimeNoStore generates a new libpod runtime configured by command line options
|
|
func GetRuntimeNoStore(ctx context.Context, fs *flag.FlagSet, cfg *entities.PodmanConfig) (*libpod.Runtime, error) {
|
|
return getRuntime(ctx, fs, &engineOpts{
|
|
renumber: false,
|
|
migrate: false,
|
|
noStore: true,
|
|
withFDS: true,
|
|
config: cfg,
|
|
})
|
|
}
|
|
|
|
func getRuntime(ctx context.Context, fs *flag.FlagSet, opts *engineOpts) (*libpod.Runtime, error) {
|
|
options := []libpod.RuntimeOption{}
|
|
storageOpts := storage.StoreOptions{}
|
|
cfg := opts.config
|
|
|
|
storageSet := false
|
|
|
|
uidmapFlag := fs.Lookup("uidmap")
|
|
gidmapFlag := fs.Lookup("gidmap")
|
|
subuidname := fs.Lookup("subuidname")
|
|
subgidname := fs.Lookup("subgidname")
|
|
if (uidmapFlag != nil && gidmapFlag != nil && subuidname != nil && subgidname != nil) &&
|
|
(uidmapFlag.Changed || gidmapFlag.Changed || subuidname.Changed || subgidname.Changed) {
|
|
userns, _ := fs.GetString("userns")
|
|
uidmapVal, _ := fs.GetStringSlice("uidmap")
|
|
gidmapVal, _ := fs.GetStringSlice("gidmap")
|
|
subuidVal, _ := fs.GetString("subuidname")
|
|
subgidVal, _ := fs.GetString("subgidname")
|
|
mappings, err := ParseIDMapping(namespaces.UsernsMode(userns), uidmapVal, gidmapVal, subuidVal, subgidVal)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
storageOpts.UIDMap = mappings.UIDMap
|
|
storageOpts.GIDMap = mappings.GIDMap
|
|
|
|
storageSet = true
|
|
}
|
|
|
|
if fs.Changed("root") {
|
|
storageSet = true
|
|
storageOpts.GraphRoot = cfg.Engine.StaticDir
|
|
}
|
|
if fs.Changed("runroot") {
|
|
storageSet = true
|
|
storageOpts.RunRoot = cfg.Runroot
|
|
}
|
|
if len(storageOpts.RunRoot) > 50 {
|
|
return nil, errors.New("the specified runroot is longer than 50 characters")
|
|
}
|
|
if fs.Changed("storage-driver") {
|
|
storageSet = true
|
|
storageOpts.GraphDriverName = cfg.StorageDriver
|
|
// Overriding the default storage driver caused GraphDriverOptions from storage.conf to be ignored
|
|
storageOpts.GraphDriverOptions = []string{}
|
|
}
|
|
// This should always be checked after storage-driver is checked
|
|
if len(cfg.StorageOpts) > 0 {
|
|
storageSet = true
|
|
storageOpts.GraphDriverOptions = cfg.StorageOpts
|
|
}
|
|
if opts.migrate {
|
|
options = append(options, libpod.WithMigrate())
|
|
if opts.name != "" {
|
|
options = append(options, libpod.WithMigrateRuntime(opts.name))
|
|
}
|
|
}
|
|
|
|
if opts.renumber {
|
|
options = append(options, libpod.WithRenumber())
|
|
}
|
|
|
|
// Only set this if the user changes storage config on the command line
|
|
if storageSet {
|
|
options = append(options, libpod.WithStorageConfig(storageOpts))
|
|
}
|
|
|
|
if !storageSet && opts.noStore {
|
|
options = append(options, libpod.WithNoStore())
|
|
}
|
|
// TODO CLI flags for image config?
|
|
// TODO CLI flag for signature policy?
|
|
|
|
if len(cfg.Engine.Namespace) > 0 {
|
|
options = append(options, libpod.WithNamespace(cfg.Engine.Namespace))
|
|
}
|
|
|
|
if fs.Changed("runtime") {
|
|
options = append(options, libpod.WithOCIRuntime(cfg.RuntimePath))
|
|
}
|
|
|
|
if fs.Changed("conmon") {
|
|
options = append(options, libpod.WithConmonPath(cfg.ConmonPath))
|
|
}
|
|
if fs.Changed("tmpdir") {
|
|
options = append(options, libpod.WithTmpDir(cfg.Engine.TmpDir))
|
|
}
|
|
if fs.Changed("network-cmd-path") {
|
|
options = append(options, libpod.WithNetworkCmdPath(cfg.Engine.NetworkCmdPath))
|
|
}
|
|
|
|
if fs.Changed("events-backend") {
|
|
options = append(options, libpod.WithEventsLogger(cfg.Engine.EventsLogger))
|
|
}
|
|
|
|
if fs.Changed("cgroup-manager") {
|
|
options = append(options, libpod.WithCgroupManager(cfg.Engine.CgroupManager))
|
|
} else {
|
|
unified, err := cgroups.IsCgroup2UnifiedMode()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if rootless.IsRootless() && !unified {
|
|
options = append(options, libpod.WithCgroupManager("cgroupfs"))
|
|
}
|
|
}
|
|
|
|
// TODO flag to set libpod static dir?
|
|
// TODO flag to set libpod tmp dir?
|
|
|
|
if fs.Changed("cni-config-dir") {
|
|
options = append(options, libpod.WithCNIConfigDir(cfg.Network.NetworkConfigDir))
|
|
}
|
|
if fs.Changed("default-mounts-file") {
|
|
options = append(options, libpod.WithDefaultMountsFile(cfg.Containers.DefaultMountsFile))
|
|
}
|
|
if fs.Changed("hooks-dir") {
|
|
options = append(options, libpod.WithHooksDir(cfg.Engine.HooksDir...))
|
|
}
|
|
if fs.Changed("registries-conf") {
|
|
options = append(options, libpod.WithRegistriesConf(cfg.RegistriesConf))
|
|
}
|
|
|
|
// TODO flag to set CNI plugins dir?
|
|
|
|
// TODO I don't think these belong here?
|
|
// Will follow up with a different PR to address
|
|
//
|
|
// Pod create options
|
|
|
|
infraImageFlag := fs.Lookup("infra-image")
|
|
if infraImageFlag != nil && infraImageFlag.Changed {
|
|
infraImage, _ := fs.GetString("infra-image")
|
|
options = append(options, libpod.WithDefaultInfraImage(infraImage))
|
|
}
|
|
|
|
infraCommandFlag := fs.Lookup("infra-command")
|
|
if infraCommandFlag != nil && infraImageFlag.Changed {
|
|
infraCommand, _ := fs.GetString("infra-command")
|
|
options = append(options, libpod.WithDefaultInfraCommand(infraCommand))
|
|
}
|
|
|
|
if !opts.withFDS {
|
|
options = append(options, libpod.WithEnableSDNotify())
|
|
}
|
|
return libpod.NewRuntime(ctx, options...)
|
|
}
|
|
|
|
// ParseIDMapping takes idmappings and subuid and subgid maps and returns a storage mapping
|
|
func ParseIDMapping(mode namespaces.UsernsMode, uidMapSlice, gidMapSlice []string, subUIDMap, subGIDMap string) (*storage.IDMappingOptions, error) {
|
|
options := storage.IDMappingOptions{
|
|
HostUIDMapping: true,
|
|
HostGIDMapping: true,
|
|
}
|
|
|
|
if mode.IsAuto() {
|
|
var err error
|
|
options.HostUIDMapping = false
|
|
options.HostGIDMapping = false
|
|
options.AutoUserNs = true
|
|
opts, err := mode.GetAutoOptions()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
options.AutoUserNsOpts = *opts
|
|
return &options, nil
|
|
}
|
|
if mode.IsKeepID() {
|
|
if len(uidMapSlice) > 0 || len(gidMapSlice) > 0 {
|
|
return nil, errors.New("cannot specify custom mappings with --userns=keep-id")
|
|
}
|
|
if len(subUIDMap) > 0 || len(subGIDMap) > 0 {
|
|
return nil, errors.New("cannot specify subuidmap or subgidmap with --userns=keep-id")
|
|
}
|
|
if rootless.IsRootless() {
|
|
min := func(a, b int) int {
|
|
if a < b {
|
|
return a
|
|
}
|
|
return b
|
|
}
|
|
|
|
uid := rootless.GetRootlessUID()
|
|
gid := rootless.GetRootlessGID()
|
|
|
|
uids, gids, err := rootless.GetConfiguredMappings()
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "cannot read mappings")
|
|
}
|
|
maxUID, maxGID := 0, 0
|
|
for _, u := range uids {
|
|
maxUID += u.Size
|
|
}
|
|
for _, g := range gids {
|
|
maxGID += g.Size
|
|
}
|
|
|
|
options.UIDMap, options.GIDMap = nil, nil
|
|
|
|
options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: 0, HostID: 1, Size: min(uid, maxUID)})
|
|
options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: uid, HostID: 0, Size: 1})
|
|
if maxUID > uid {
|
|
options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: uid + 1, HostID: uid + 1, Size: maxUID - uid})
|
|
}
|
|
|
|
options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: 0, HostID: 1, Size: min(gid, maxGID)})
|
|
options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: gid, HostID: 0, Size: 1})
|
|
if maxGID > gid {
|
|
options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: gid + 1, HostID: gid + 1, Size: maxGID - gid})
|
|
}
|
|
|
|
options.HostUIDMapping = false
|
|
options.HostGIDMapping = false
|
|
}
|
|
// Simply ignore the setting and do not setup an inner namespace for root as it is a no-op
|
|
return &options, nil
|
|
}
|
|
|
|
if subGIDMap == "" && subUIDMap != "" {
|
|
subGIDMap = subUIDMap
|
|
}
|
|
if subUIDMap == "" && subGIDMap != "" {
|
|
subUIDMap = subGIDMap
|
|
}
|
|
if len(gidMapSlice) == 0 && len(uidMapSlice) != 0 {
|
|
gidMapSlice = uidMapSlice
|
|
}
|
|
if len(uidMapSlice) == 0 && len(gidMapSlice) != 0 {
|
|
uidMapSlice = gidMapSlice
|
|
}
|
|
if len(uidMapSlice) == 0 && subUIDMap == "" && os.Getuid() != 0 {
|
|
uidMapSlice = []string{fmt.Sprintf("0:%d:1", os.Getuid())}
|
|
}
|
|
if len(gidMapSlice) == 0 && subGIDMap == "" && os.Getuid() != 0 {
|
|
gidMapSlice = []string{fmt.Sprintf("0:%d:1", os.Getgid())}
|
|
}
|
|
|
|
if subUIDMap != "" && subGIDMap != "" {
|
|
mappings, err := idtools.NewIDMappings(subUIDMap, subGIDMap)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
options.UIDMap = mappings.UIDs()
|
|
options.GIDMap = mappings.GIDs()
|
|
}
|
|
parsedUIDMap, err := idtools.ParseIDMap(uidMapSlice, "UID")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
parsedGIDMap, err := idtools.ParseIDMap(gidMapSlice, "GID")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
options.UIDMap = append(options.UIDMap, parsedUIDMap...)
|
|
options.GIDMap = append(options.GIDMap, parsedGIDMap...)
|
|
if len(options.UIDMap) > 0 {
|
|
options.HostUIDMapping = false
|
|
}
|
|
if len(options.GIDMap) > 0 {
|
|
options.HostGIDMapping = false
|
|
}
|
|
return &options, nil
|
|
}
|