Use libpod GetDefaultStorage to report proper storage config

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>

Closes: #1124
Approved by: rhatdan
This commit is contained in:
Daniel J Walsh 2018-10-22 12:54:28 -04:00 committed by Atomic Bot
parent e15cb2d9f6
commit 1f537a95ce
9 changed files with 347 additions and 11 deletions

View File

@ -5,6 +5,7 @@ import (
"os"
"github.com/containers/buildah"
"github.com/containers/libpod/pkg/util"
"github.com/containers/storage"
ispecs "github.com/opencontainers/image-spec/specs-go"
rspecs "github.com/opencontainers/runtime-spec/specs-go"
@ -19,6 +20,11 @@ func main() {
if buildah.InitReexec() {
return
}
storageOptions, err := util.GetDefaultStoreOptions()
if err != nil {
logrus.Errorf(err.Error())
cli.OsExiter(1)
}
app := cli.NewApp()
app.Name = buildah.Package
@ -45,17 +51,17 @@ func main() {
cli.StringFlag{
Name: "root",
Usage: "storage root dir",
Value: storage.DefaultStoreOptions.GraphRoot,
Value: storageOptions.GraphRoot,
},
cli.StringFlag{
Name: "runroot",
Usage: "storage state dir",
Value: storage.DefaultStoreOptions.RunRoot,
Value: storageOptions.RunRoot,
},
cli.StringFlag{
Name: "storage-driver",
Usage: "storage driver",
Value: storage.DefaultStoreOptions.GraphDriverName,
Value: storageOptions.GraphDriverName,
},
cli.StringSliceFlag{
Name: "storage-opt",
@ -117,8 +123,7 @@ func main() {
unshareCommand,
versionCommand,
}
err := app.Run(os.Args)
if err != nil {
if err := app.Run(os.Args); err != nil {
if debug {
logrus.Errorf(err.Error())
} else {

View File

@ -57,7 +57,7 @@ Default state dir is configured in /etc/containers/storage.conf
**--storage-driver** **value**
Storage driver. The default storage driver for UID 0 is configured in /etc/containers/storage.conf, and is *vfs* for other users. The `STORAGE_DRIVER` environment variable overrides the default. The --storage-driver specified driver overrides all.
Storage driver. The default storage driver for UID 0 is configured in /etc/containers/storage.conf (`$HOME/.config/containers/storage.conf` in rootless mode), and is *vfs* for other users. The `STORAGE_DRIVER` environment variable overrides the default. The --storage-driver specified driver overrides all.
Examples: "overlay", "devicemapper", "vfs"
@ -66,7 +66,7 @@ specify additional options via the `--storage-opt` flag.
**--storage-opt** **value**
Storage driver option, Default storage driver options are configured in /etc/containers/storage.conf. The `STORAGE_OPTS` environment variable overrides the default. The --storage-opt specified options overrides all.
Storage driver option, Default storage driver options are configured in /etc/containers/storage.conf (`$HOME/.config/containers/storage.conf` in rootless mode). The `STORAGE_OPTS` environment variable overrides the default. The --storage-opt specified options overrides all.
**--userns-uid-map** *mapping*

View File

@ -4,7 +4,7 @@ github.com/BurntSushi/toml master
github.com/containerd/continuity master
github.com/containernetworking/cni v0.7.0-alpha1
github.com/containers/image 5e5b67d6b1cf43cc349128ec3ed7d5283a6cc0d1
github.com/containers/libpod 2afadeec6696fefac468a49c8ba24b0bc275aa75
github.com/containers/libpod f3b08379749e8d09cdec45238486ae0b91b4c6ee
github.com/containers/storage bd5818eda84012cf1db4dafbddd4b7509bb77142
github.com/docker/distribution 5f6282db7d65e6d72ad7c2cc66310724a57be716
github.com/docker/docker 86f080cff0914e9694068ed78d503701667c4c00

View File

@ -1,7 +1,7 @@
![PODMAN logo](logo/podman-logo-source.svg)
# libpod - library for running OCI-based containers in Pods
### Latest Version: 0.9.3.1
### Latest Version: 0.10.1.3
### Status: Active Development
## What is the scope of this project?

View File

@ -99,3 +99,10 @@ func GetAdditionalGroupsForUser(rootdir string, userid uint64) ([]uint32, error)
}
return gids, nil
}
// LookupUIDInContainer returns username and gid associated with a UID in a container
// it will use the /etc/passwd files inside of the rootdir
// to return this information.
func LookupUIDInContainer(rootdir string, uid uint64) (user string, gid uint64, err error) {
return lookupUIDInContainer(rootdir, uid)
}

View File

@ -21,3 +21,7 @@ func lookupGroupForUIDInContainer(rootdir string, userid uint64) (string, uint64
func lookupAdditionalGroupsForUIDInContainer(rootdir string, userid uint64) (gid []uint32, err error) {
return nil, errors.New("supplemental groups list lookup by uid not supported")
}
func lookupUIDInContainer(rootdir string, uid uint64) (string, uint64, error) {
return "", 0, errors.New("UID lookup not supported")
}

View File

@ -265,3 +265,29 @@ func lookupGroupInContainer(rootdir, groupname string) (gid uint64, err error) {
return 0, user.UnknownGroupError(fmt.Sprintf("error looking up group %q", groupname))
}
func lookupUIDInContainer(rootdir string, uid uint64) (string, uint64, error) {
cmd, f, err := openChrootedFile(rootdir, "/etc/passwd")
if err != nil {
return "", 0, err
}
defer func() {
_ = cmd.Wait()
}()
rc := bufio.NewReader(f)
defer f.Close()
lookupUser.Lock()
defer lookupUser.Unlock()
pwd := parseNextPasswd(rc)
for pwd != nil {
if pwd.uid != uid {
pwd = parseNextPasswd(rc)
continue
}
return pwd.name, pwd.gid, nil
}
return "", 0, user.UnknownUserError(fmt.Sprintf("error looking up uid %q", uid))
}

294
vendor/github.com/containers/libpod/pkg/util/utils.go generated vendored Normal file
View File

@ -0,0 +1,294 @@
package util
import (
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
"syscall"
"github.com/containers/image/types"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/storage"
"github.com/containers/storage/pkg/idtools"
"github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"golang.org/x/crypto/ssh/terminal"
)
// Helper function to determine the username/password passed
// in the creds string. It could be either or both.
func parseCreds(creds string) (string, string) {
if creds == "" {
return "", ""
}
up := strings.SplitN(creds, ":", 2)
if len(up) == 1 {
return up[0], ""
}
return up[0], up[1]
}
// ParseRegistryCreds takes a credentials string in the form USERNAME:PASSWORD
// and returns a DockerAuthConfig
func ParseRegistryCreds(creds string) (*types.DockerAuthConfig, error) {
username, password := parseCreds(creds)
if username == "" {
fmt.Print("Username: ")
fmt.Scanln(&username)
}
if password == "" {
fmt.Print("Password: ")
termPassword, err := terminal.ReadPassword(0)
if err != nil {
return nil, errors.Wrapf(err, "could not read password from terminal")
}
password = string(termPassword)
}
return &types.DockerAuthConfig{
Username: username,
Password: password,
}, nil
}
// StringInSlice determines if a string is in a string slice, returns bool
func StringInSlice(s string, sl []string) bool {
for _, i := range sl {
if i == s {
return true
}
}
return false
}
// GetImageConfig converts the --change flag values in the format "CMD=/bin/bash USER=example"
// to a type v1.ImageConfig
func GetImageConfig(changes []string) (v1.ImageConfig, error) {
// USER=value | EXPOSE=value | ENV=value | ENTRYPOINT=value |
// CMD=value | VOLUME=value | WORKDIR=value | LABEL=key=value | STOPSIGNAL=value
var (
user string
env []string
entrypoint []string
cmd []string
workingDir string
stopSignal string
)
exposedPorts := make(map[string]struct{})
volumes := make(map[string]struct{})
labels := make(map[string]string)
for _, ch := range changes {
pair := strings.Split(ch, "=")
if len(pair) == 1 {
return v1.ImageConfig{}, errors.Errorf("no value given for instruction %q", ch)
}
switch pair[0] {
case "USER":
user = pair[1]
case "EXPOSE":
var st struct{}
exposedPorts[pair[1]] = st
case "ENV":
env = append(env, pair[1])
case "ENTRYPOINT":
entrypoint = append(entrypoint, pair[1])
case "CMD":
cmd = append(cmd, pair[1])
case "VOLUME":
var st struct{}
volumes[pair[1]] = st
case "WORKDIR":
workingDir = pair[1]
case "LABEL":
if len(pair) == 3 {
labels[pair[1]] = pair[2]
} else {
labels[pair[1]] = ""
}
case "STOPSIGNAL":
stopSignal = pair[1]
}
}
return v1.ImageConfig{
User: user,
ExposedPorts: exposedPorts,
Env: env,
Entrypoint: entrypoint,
Cmd: cmd,
Volumes: volumes,
WorkingDir: workingDir,
Labels: labels,
StopSignal: stopSignal,
}, nil
}
// ParseIDMapping takes idmappings and subuid and subgid maps and returns a storage mapping
func ParseIDMapping(UIDMapSlice, GIDMapSlice []string, subUIDMap, subGIDMap string) (*storage.IDMappingOptions, error) {
options := storage.IDMappingOptions{
HostUIDMapping: true,
HostGIDMapping: true,
}
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())}
}
parseTriple := func(spec []string) (container, host, size int, err error) {
cid, err := strconv.ParseUint(spec[0], 10, 32)
if err != nil {
return 0, 0, 0, fmt.Errorf("error parsing id map value %q: %v", spec[0], err)
}
hid, err := strconv.ParseUint(spec[1], 10, 32)
if err != nil {
return 0, 0, 0, fmt.Errorf("error parsing id map value %q: %v", spec[1], err)
}
sz, err := strconv.ParseUint(spec[2], 10, 32)
if err != nil {
return 0, 0, 0, fmt.Errorf("error parsing id map value %q: %v", spec[2], err)
}
return int(cid), int(hid), int(sz), nil
}
parseIDMap := func(spec []string) (idmap []idtools.IDMap, err error) {
for _, uid := range spec {
splitmap := strings.SplitN(uid, ":", 3)
if len(splitmap) < 3 {
return nil, fmt.Errorf("invalid mapping requires 3 fields: %q", uid)
}
cid, hid, size, err := parseTriple(splitmap)
if err != nil {
return nil, err
}
pmap := idtools.IDMap{
ContainerID: cid,
HostID: hid,
Size: size,
}
idmap = append(idmap, pmap)
}
return idmap, nil
}
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 := parseIDMap(UIDMapSlice)
if err != nil {
return nil, err
}
parsedGIDMap, err := parseIDMap(GIDMapSlice)
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
}
// GetRootlessRuntimeDir returns the runtime directory when running as non root
func GetRootlessRuntimeDir() (string, error) {
runtimeDir := os.Getenv("XDG_RUNTIME_DIR")
uid := fmt.Sprintf("%d", rootless.GetRootlessUID())
if runtimeDir == "" {
tmpDir := filepath.Join("/run", "user", uid)
os.MkdirAll(tmpDir, 0700)
st, err := os.Stat(tmpDir)
if err == nil && int(st.Sys().(*syscall.Stat_t).Uid) == os.Getuid() && st.Mode().Perm() == 0700 {
runtimeDir = tmpDir
}
}
if runtimeDir == "" {
tmpDir := filepath.Join(os.TempDir(), "user", uid)
os.MkdirAll(tmpDir, 0700)
st, err := os.Stat(tmpDir)
if err == nil && int(st.Sys().(*syscall.Stat_t).Uid) == os.Getuid() && st.Mode().Perm() == 0700 {
runtimeDir = tmpDir
}
}
if runtimeDir == "" {
home := os.Getenv("HOME")
if home == "" {
return "", fmt.Errorf("neither XDG_RUNTIME_DIR nor HOME was set non-empty")
}
resolvedHome, err := filepath.EvalSymlinks(home)
if err != nil {
return "", errors.Wrapf(err, "cannot resolve %s", home)
}
runtimeDir = filepath.Join(resolvedHome, "rundir")
}
return runtimeDir, nil
}
func GetRootlessStorageOpts() (storage.StoreOptions, error) {
var opts storage.StoreOptions
rootlessRuntime, err := GetRootlessRuntimeDir()
if err != nil {
return opts, err
}
opts.RunRoot = filepath.Join(rootlessRuntime, "run")
dataDir := os.Getenv("XDG_DATA_HOME")
if dataDir == "" {
home := os.Getenv("HOME")
if home == "" {
return opts, fmt.Errorf("neither XDG_DATA_HOME nor HOME was set non-empty")
}
// runc doesn't like symlinks in the rootfs path, and at least
// on CoreOS /home is a symlink to /var/home, so resolve any symlink.
resolvedHome, err := filepath.EvalSymlinks(home)
if err != nil {
return opts, errors.Wrapf(err, "cannot resolve %s", home)
}
dataDir = filepath.Join(resolvedHome, ".local", "share")
}
opts.GraphRoot = filepath.Join(dataDir, "containers", "storage")
opts.GraphDriverName = "vfs"
return opts, nil
}
func GetDefaultStoreOptions() (storage.StoreOptions, error) {
storageOpts := storage.DefaultStoreOptions
if rootless.IsRootless() {
var err error
storageOpts, err = GetRootlessStorageOpts()
if err != nil {
return storageOpts, err
}
storageConf := filepath.Join(os.Getenv("HOME"), ".config/containers/storage.conf")
if _, err := os.Stat(storageConf); err == nil {
storage.ReloadConfigurationFile(storageConf, &storageOpts)
}
}
return storageOpts, nil
}

View File

@ -10,7 +10,7 @@ github.com/containerd/cgroups 58556f5ad8448d99a6f7bea69ea4bdb7747cfeb0
github.com/containerd/continuity master
github.com/containernetworking/cni v0.7.0-alpha1
github.com/containernetworking/plugins 1562a1e60ed101aacc5e08ed9dbeba8e9f3d4ec1
github.com/containers/image 918dbb93e6e099b196b498c38d079f6bb924d0c8
github.com/containers/image bd10b1b53b2976f215b3f2f848fb8e7cad779aeb
github.com/containers/storage 41294c85d97bef688e18f710402895dbecde3308
github.com/containers/psgo 5dde6da0bc8831b35243a847625bcf18183bd1ee
github.com/coreos/go-systemd v14
@ -91,7 +91,7 @@ k8s.io/kube-openapi 275e2ce91dec4c05a4094a7b1daee5560b555ac9 https://github.com/
k8s.io/utils 258e2a2fa64568210fbd6267cf1d8fd87c3cb86e https://github.com/kubernetes/utils
github.com/mrunalp/fileutils master
github.com/varlink/go master
github.com/containers/buildah af8cb28f84d81ee1bca04c893142cd790b908c75
github.com/containers/buildah 46c577c87d5a7ab30ef40cfa695cd2b96b32b117
github.com/Nvveen/Gotty master
github.com/fsouza/go-dockerclient master
github.com/openshift/imagebuilder master