Skip to content

Commit

Permalink
Podman System Reset --run-root --graph-root and --user
Browse files Browse the repository at this point in the history
added options to reinstantiate storage after resetting the podman system using
podman system reset. --run-root and --graph-root define the runRoot and graphRoot to initiate
a new runtime with. --user gets a specified user or uid and generates good approximates for the basic storage
locations of that user. these values, once populated into a new libpd runtime, then are used to create a new storage.conf
file at the proper location (root or rootless default location).

These options allow for a more interactive and useful reset program and ill help eliminate many questions regarding how to configure the basic entities
of container storage.

depends on containers/storage#1096

Signed-off-by: cdoern <cdoern@redhat.com>
  • Loading branch information
cdoern authored and cdoern committed Jan 7, 2022
1 parent 63196c2 commit 249932c
Show file tree
Hide file tree
Showing 13 changed files with 262 additions and 16 deletions.
127 changes: 126 additions & 1 deletion cmd/podman/system/reset.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//go:build !remote
// +build !remote

package system
Expand All @@ -6,6 +7,10 @@ import (
"bufio"
"fmt"
"os"
"os/exec"
"os/user"
"path/filepath"
"strconv"
"strings"

"github.com/containers/common/pkg/completion"
Expand All @@ -14,6 +19,7 @@ import (
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/domain/infra"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
Expand All @@ -34,6 +40,9 @@ var (
}

forceFlag bool
givenUser string
runDir string
graphDir string
)

func init() {
Expand All @@ -43,6 +52,15 @@ func init() {
})
flags := systemResetCommand.Flags()
flags.BoolVarP(&forceFlag, "force", "f", false, "Do not prompt for confirmation")

flags.StringVar(&givenUser, "user", "", "User to setup the DB under")
_ = systemResetCommand.RegisterFlagCompletionFunc("user", completion.AutocompleteNone)

flags.StringVar(&runDir, "run-root", "", "run root directory to use for storage")
_ = systemResetCommand.RegisterFlagCompletionFunc("run-root", completion.AutocompleteNone)

flags.StringVar(&graphDir, "graph-root", "", "graph root directory to use")
_ = systemResetCommand.RegisterFlagCompletionFunc("graph-root", completion.AutocompleteNone)
}

func reset(cmd *cobra.Command, args []string) {
Expand Down Expand Up @@ -85,16 +103,123 @@ WARNING! This will remove:
registry.ContainerEngine().Shutdown(registry.Context())
registry.ImageEngine().Shutdown(registry.Context())

cfg := registry.PodmanConfig()
if len(runDir) > 0 {
//cfg.FlagSet.set
cfg.Runroot = runDir
}
if len(graphDir) > 0 {
cfg.Engine.StaticDir = graphDir
}

if len(givenUser) > 0 {
var u *user.User
givenUser = strings.Split(givenUser, ":")[0] // split in case provided with uid:gid
_, err := strconv.Atoi(givenUser)
if err != nil {
u, err = user.Lookup(givenUser)
if err != nil {
logrus.Error(err)
}
} else {
u, err = user.LookupId(givenUser)
if err != nil {
logrus.Error(err)
os.Exit(define.ExecErrorCodeGeneric)
}
}
uid, err := strconv.Atoi(u.Uid)
if err != nil {
logrus.Error(err)
os.Exit(define.ExecErrorCodeGeneric)
}

home, run, err := GetHomeAndRun(uid)
if err != nil {
logrus.Error(err)
os.Exit(define.ExecErrorCodeGeneric)
}
if len(runDir) == 0 {
_, err = filepath.EvalSymlinks(home)
if err != nil {
logrus.Error(err)
os.Exit(define.ExecErrorCodeGeneric)
}
if uid != 0 {
cfg.Runroot = filepath.Join(run, "containers")
}
} else {
logrus.Error("cannot specify a run-root and a user to generate a run-root from")
os.Exit(define.ExecErrorCodeGeneric)
}
if len(graphDir) == 0 {
dataDir := filepath.Join(home, ".local", "share")
cfg.Engine.StaticDir = filepath.Join(dataDir, "containers", "storage")
} else {
logrus.Error("cannot specify a graph-root and a user to generate a graph-root from")
os.Exit(define.ExecErrorCodeGeneric)
}
}

engine, err := infra.NewSystemEngine(entities.ResetMode, registry.PodmanConfig())
if err != nil {
logrus.Error(err)
os.Exit(define.ExecErrorCodeGeneric)
}
defer engine.Shutdown(registry.Context())

if err := engine.Reset(registry.Context()); err != nil {
if err := engine.Reset(registry.Context(), (len(runDir) > 0 || len(graphDir) > 0 || len(givenUser) > 0)); err != nil {
logrus.Error(err)
os.Exit(define.ExecErrorCodeGeneric)
}
os.Exit(0)
}

// GetHomeAndRun finds the home and run directories for the given uid, only works with sudo permissions
func GetHomeAndRun(uid int) (string, string, error) {
var home string
var run string
var out []byte
var cmd *exec.Cmd
u, err := user.LookupId(fmt.Sprint(uid))
if err != nil {
return "", "", err
}
envExec, err := exec.LookPath("env")
if err != nil {
return "", "", errors.New("cannot find env executable")
}
machinectl, err := exec.LookPath("machinectl")
if err != nil {
cmd = exec.Command("su", "-l", u.Username, "--command", envExec)
} else {
cmd = exec.Command(machinectl, "shell", "-q", u.Username+"@.host", envExec)
logrus.Debug("Executing env command machinectl")
}

cmd.Stderr = os.Stderr
out, err = cmd.Output()
if err != nil {
return "", "", err
}

env := strings.Split(string(out), "\n")
for _, val := range env {
if strings.Contains(val, "XDG_DATA_HOME") || strings.Contains(val, "HOME") {
home = strings.Split(val, "=")[1]
} else if strings.Contains(val, "XDG_RUNTIME_DIR") {
run = strings.Split(val, "=")[1]
}
}
if len(home) == 0 {
return "", "", errors.New("called function as root, could not find given user's home directory")
}
if len(run) == 0 {
run = "/run/user/" + string(uid)
path := filepath.Join(run, "containers")
if err := os.MkdirAll(path, 0700); err != nil {
return "", "", errors.Wrapf(err, "unable to make rootless runtime")
}
}
return strings.TrimSpace(home), strings.TrimSpace(run), nil
}
21 changes: 21 additions & 0 deletions docs/source/markdown/podman-system-reset.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,28 @@ Do not prompt for confirmation

Print usage statement

#### **--run-root**

Establishes a new run root directory and storage.conf file once the system is reset, cannot be used in conjunction with --user

#### **--graph-root**

Establishes a new graph root directory and sotrage.conf file once the system is reset, cannot be used in conjunction with --user

#### **--user**

Establishes new run and graph root directories and storage.conf file once the system is reset. the run and graph root directories are generated by retrieving rhe user's home and run directory.

## EXAMPLES
Reset the system and create a new storage.conf enerated from the given user's defaults
```
$ podman system reset --user=1000:1000
```

Reset the system and create a new storage.conf with the given run and graph root
```
$ podman system reset --run-root=/run/user/1000/containers --graph-root=/home/charliedoern/.local/share/containers
```

### Switching rootless user from VFS driver to overlay with fuse-overlayfs

Expand Down
19 changes: 18 additions & 1 deletion libpod/boltdb_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -405,12 +405,29 @@ func (s *BoltState) ValidateDBConfig(runtime *Runtime) error {
}
defer s.deferredCloseDBCon(db)

//runRootName := "storage temporary directory (runroot)"
//runRootKey := []byte(runRootName)
// Check runtime configuration
if err := checkRuntimeConfig(db, runtime); err != nil {
/* if runtime.newDB {
err = db.Update(func(tx *bolt.Tx) error {
rb, err := getRuntimeConfigBucket(tx)
if err != nil {
return err
}
dbValue := []byte(runtime.storageConfig.RunRoot)
fmt.Println("here", runtime.storageConfig.RunRoot)
if err := rb.Put(runRootKey, dbValue); err != nil {
return errors.Wrapf(err, "error updating %s in DB runtime config", runRootName)
}
return nil
})
return err
}*/
return err
}

return nil
return err
}

// SetNamespace sets the namespace that will be used for container and pod
Expand Down
5 changes: 2 additions & 3 deletions libpod/boltdb_state_internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,10 @@ func checkRuntimeConfig(db *bolt.DB, rt *Runtime) error {

for _, check := range checks {
exists, err := readOnlyValidateConfig(configBkt, check)
if err != nil {
if err != nil && (err != define.ErrDBBadConfig && !rt.newDB) {
return err
}
if !exists {
if !exists || (err != nil && rt.newDB) {
missingFields = append(missingFields, check)
}
}
Expand All @@ -187,7 +187,6 @@ func checkRuntimeConfig(db *bolt.DB, rt *Runtime) error {
if missing.runtimeValue == "" && missing.defaultValue != "" {
dbValue = []byte(missing.defaultValue)
}

if err := configBkt.Put(missing.key, dbValue); err != nil {
return errors.Wrapf(err, "error updating %s in DB runtime config", missing.name)
}
Expand Down
10 changes: 10 additions & 0 deletions libpod/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,16 @@ func WithRuntimeFlags(runtimeFlags []string) RuntimeOption {
}
}

func WithNewDB() RuntimeOption {
return func(rt *Runtime) error {
if rt.valid {
return define.ErrRuntimeFinalized
}
rt.newDB = true
return nil
}
}

// Container Creation Options

// WithMaxLogSize sets the maximum size of container logs.
Expand Down
17 changes: 15 additions & 2 deletions libpod/reset.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
)

// Reset removes all storage
func (r *Runtime) Reset(ctx context.Context) error {
func (r *Runtime) Reset(ctx context.Context, removeConf bool) error {
var timeout *uint
pods, err := r.GetAllPods()
if err != nil {
Expand Down Expand Up @@ -124,7 +124,20 @@ func (r *Runtime) Reset(ctx context.Context) error {
if storageConfPath, err := storage.DefaultConfigFile(rootless.IsRootless()); err == nil {
if _, err = os.Stat(storageConfPath); err == nil {
fmt.Printf("A storage.conf file exists at %s\n", storageConfPath)
fmt.Println("You should remove this file if you did not modify the configuration.")
if removeConf {
fmt.Println("Removing storage.conf file at", storageConfPath)

if err = os.Remove(storageConfPath); err != nil {
return err
}
// add here for rootless
}
confStr := "[storage]\ndriver = \"" + r.store.GraphDriverName() + "\"\nrunroot = \"" + r.store.RunRoot() + "\"\ngraphroot = \"" + r.store.GraphRoot() + "\""
newConf := []byte(confStr)
if err = os.WriteFile(storageConfPath, newConf, 0644); err != nil {
return err
}
fmt.Println("Wrote new storage config:", r.store, "to", storageConfPath)
}
} else {
if prevError != nil {
Expand Down
9 changes: 5 additions & 4 deletions libpod/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ type Runtime struct {
noStore bool
// secretsManager manages secrets
secretsManager *secrets.SecretsManager
// newDB indicates that we do not need to merge the db config, just create a new one
newDB bool
}

// SetXdgDirs ensures the XDG_RUNTIME_DIR env and XDG_CONFIG_HOME variables are set.
Expand Down Expand Up @@ -603,7 +605,6 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) {
return err
}
}

// If we need to refresh the state, do it now - things are guaranteed to
// be set up by now.
if doRefresh {
Expand All @@ -618,7 +619,6 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) {
return err2
}
}

// Mark the runtime as valid - ready to be used, cannot be modified
// further
runtime.valid = true
Expand All @@ -628,7 +628,6 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) {
return err
}
}

return nil
}

Expand Down Expand Up @@ -981,8 +980,10 @@ func (r *Runtime) configureStore() error {
if err != nil {
return err
}

r.store = store
if store.RunRoot() != r.storageConfig.RunRoot && store.GraphRoot() == r.storageConfig.GraphRoot {
logrus.Debug("config reset due to graph root being the default value ")
}
is.Transport.SetStore(store)

// Set up a storage service for creating container root filesystems from
Expand Down
2 changes: 1 addition & 1 deletion pkg/domain/entities/engine_system.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ import (
type SystemEngine interface {
Renumber(ctx context.Context, flags *pflag.FlagSet, config *PodmanConfig) error
Migrate(ctx context.Context, flags *pflag.FlagSet, config *PodmanConfig, options SystemMigrateOptions) error
Reset(ctx context.Context) error
Reset(ctx context.Context, removeConf bool) error
Shutdown(ctx context.Context)
}
4 changes: 4 additions & 0 deletions pkg/domain/entities/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,7 @@ type AuthReport struct {
IdentityToken string
Status string
}

type SetupReport struct {
Report []string
}
4 changes: 2 additions & 2 deletions pkg/domain/infra/abi/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,8 +326,8 @@ func sizeOfPath(path string) (int64, error) {
return size, err
}

func (se *SystemEngine) Reset(ctx context.Context) error {
return se.Libpod.Reset(ctx)
func (se *SystemEngine) Reset(ctx context.Context, removeConf bool) error {
return se.Libpod.Reset(ctx, removeConf)
}

func (se *SystemEngine) Renumber(ctx context.Context, flags *pflag.FlagSet, config *entities.PodmanConfig) error {
Expand Down
1 change: 1 addition & 0 deletions pkg/domain/infra/runtime_abi.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//go:build !remote
// +build !remote

package infra
Expand Down
Loading

0 comments on commit 249932c

Please sign in to comment.