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:
parent
e15cb2d9f6
commit
1f537a95ce
|
@ -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 {
|
||||
|
|
|
@ -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*
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||

|
||||
# 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?
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue