github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/pkg/domain/infra/abi/system.go (about)

     1  // +build ABISupport
     2  
     3  package abi
     4  
     5  import (
     6  	"context"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"net"
    10  	"os"
    11  	"strconv"
    12  	"strings"
    13  	"syscall"
    14  
    15  	"github.com/containers/common/pkg/config"
    16  	"github.com/containers/libpod/libpod/define"
    17  	api "github.com/containers/libpod/pkg/api/server"
    18  	"github.com/containers/libpod/pkg/cgroups"
    19  	"github.com/containers/libpod/pkg/domain/entities"
    20  	"github.com/containers/libpod/pkg/rootless"
    21  	"github.com/containers/libpod/pkg/util"
    22  	iopodman "github.com/containers/libpod/pkg/varlink"
    23  	iopodmanAPI "github.com/containers/libpod/pkg/varlinkapi"
    24  	"github.com/containers/libpod/utils"
    25  	"github.com/containers/libpod/version"
    26  	"github.com/pkg/errors"
    27  	"github.com/sirupsen/logrus"
    28  	"github.com/spf13/cobra"
    29  	"github.com/varlink/go/varlink"
    30  )
    31  
    32  func (ic *ContainerEngine) Info(ctx context.Context) (*define.Info, error) {
    33  	return ic.Libpod.Info()
    34  }
    35  
    36  func (ic *ContainerEngine) RestService(_ context.Context, opts entities.ServiceOptions) error {
    37  	var (
    38  		listener net.Listener
    39  		err      error
    40  	)
    41  
    42  	if opts.URI != "" {
    43  		fields := strings.Split(opts.URI, ":")
    44  		if len(fields) == 1 {
    45  			return errors.Errorf("%s is an invalid socket destination", opts.URI)
    46  		}
    47  		address := strings.Join(fields[1:], ":")
    48  		listener, err = net.Listen(fields[0], address)
    49  		if err != nil {
    50  			return errors.Wrapf(err, "unable to create socket %s", opts.URI)
    51  		}
    52  	}
    53  
    54  	server, err := api.NewServerWithSettings(ic.Libpod, opts.Timeout, &listener)
    55  	if err != nil {
    56  		return err
    57  	}
    58  	defer func() {
    59  		if err := server.Shutdown(); err != nil {
    60  			logrus.Warnf("Error when stopping API service: %s", err)
    61  		}
    62  	}()
    63  
    64  	err = server.Serve()
    65  	_ = listener.Close()
    66  	return err
    67  }
    68  
    69  func (ic *ContainerEngine) VarlinkService(_ context.Context, opts entities.ServiceOptions) error {
    70  	var varlinkInterfaces = []*iopodman.VarlinkInterface{
    71  		iopodmanAPI.New(opts.Command, ic.Libpod),
    72  	}
    73  
    74  	service, err := varlink.NewService(
    75  		"Atomic",
    76  		"podman",
    77  		version.Version,
    78  		"https://github.com/containers/libpod",
    79  	)
    80  	if err != nil {
    81  		return errors.Wrapf(err, "unable to create new varlink service")
    82  	}
    83  
    84  	for _, i := range varlinkInterfaces {
    85  		if err := service.RegisterInterface(i); err != nil {
    86  			return errors.Errorf("unable to register varlink interface %v", i)
    87  		}
    88  	}
    89  
    90  	// Run the varlink server at the given address
    91  	if err = service.Listen(opts.URI, opts.Timeout); err != nil {
    92  		switch err.(type) {
    93  		case varlink.ServiceTimeoutError:
    94  			logrus.Infof("varlink service expired (use --timeout to increase session time beyond %s ms, 0 means never timeout)", opts.Timeout.String())
    95  			return nil
    96  		default:
    97  			return errors.Wrapf(err, "unable to start varlink service")
    98  		}
    99  	}
   100  	return nil
   101  }
   102  
   103  func (ic *ContainerEngine) SetupRootless(cmd *cobra.Command) error {
   104  	// do it only after podman has already re-execed and running with uid==0.
   105  	if os.Geteuid() == 0 {
   106  		ownsCgroup, err := cgroups.UserOwnsCurrentSystemdCgroup()
   107  		if err != nil {
   108  			logrus.Warnf("Failed to detect the owner for the current cgroup: %v", err)
   109  		}
   110  		if !ownsCgroup {
   111  			conf, err := ic.Config(context.Background())
   112  			if err != nil {
   113  				return err
   114  			}
   115  			unitName := fmt.Sprintf("podman-%d.scope", os.Getpid())
   116  			if err := utils.RunUnderSystemdScope(os.Getpid(), "user.slice", unitName); err != nil {
   117  				if conf.Engine.CgroupManager == config.SystemdCgroupsManager {
   118  					logrus.Warnf("Failed to add podman to systemd sandbox cgroup: %v", err)
   119  				} else {
   120  					logrus.Debugf("Failed to add podman to systemd sandbox cgroup: %v", err)
   121  				}
   122  			}
   123  		}
   124  	}
   125  
   126  	if !executeCommandInUserNS(cmd) {
   127  		return nil
   128  	}
   129  
   130  	pausePidPath, err := util.GetRootlessPauseProcessPidPath()
   131  	if err != nil {
   132  		return errors.Wrapf(err, "could not get pause process pid file path")
   133  	}
   134  
   135  	became, ret, err := rootless.TryJoinPauseProcess(pausePidPath)
   136  	if err != nil {
   137  		return err
   138  	}
   139  	if became {
   140  		os.Exit(ret)
   141  	}
   142  
   143  	// if there is no pid file, try to join existing containers, and create a pause process.
   144  	ctrs, err := ic.Libpod.GetRunningContainers()
   145  	if err != nil {
   146  		logrus.WithError(err).Fatal("")
   147  	}
   148  
   149  	paths := []string{}
   150  	for _, ctr := range ctrs {
   151  		paths = append(paths, ctr.Config().ConmonPidFile)
   152  	}
   153  
   154  	became, ret, err = rootless.TryJoinFromFilePaths(pausePidPath, true, paths)
   155  	if err := movePauseProcessToScope(); err != nil {
   156  		conf, err := ic.Config(context.Background())
   157  		if err != nil {
   158  			return err
   159  		}
   160  		if conf.Engine.CgroupManager == config.SystemdCgroupsManager {
   161  			logrus.Warnf("Failed to add pause process to systemd sandbox cgroup: %v", err)
   162  		} else {
   163  			logrus.Debugf("Failed to add pause process to systemd sandbox cgroup: %v", err)
   164  		}
   165  	}
   166  	if err != nil {
   167  		logrus.WithError(err).Fatal("")
   168  	}
   169  	if became {
   170  		os.Exit(ret)
   171  	}
   172  	return nil
   173  }
   174  
   175  // Most podman commands when run in rootless mode, need to be executed in the
   176  // users usernamespace.  This function is updated with a  list of commands that
   177  // should NOT be run within the user namespace.
   178  func executeCommandInUserNS(cmd *cobra.Command) bool {
   179  	return os.Geteuid() == 0
   180  	// if os.Geteuid() == 0 {
   181  	// 	return false
   182  	// }
   183  	// switch cmd {
   184  	// case _migrateCommand,
   185  	// 	_mountCommand,
   186  	// 	_renumberCommand,
   187  	// 	_searchCommand,
   188  	// 	_versionCommand:
   189  	// 	return false
   190  	// }
   191  	// return true
   192  }
   193  
   194  func movePauseProcessToScope() error {
   195  	pausePidPath, err := util.GetRootlessPauseProcessPidPath()
   196  	if err != nil {
   197  		return errors.Wrapf(err, "could not get pause process pid file path")
   198  	}
   199  
   200  	data, err := ioutil.ReadFile(pausePidPath)
   201  	if err != nil {
   202  		return errors.Wrapf(err, "cannot read pause pid file")
   203  	}
   204  	pid, err := strconv.ParseUint(string(data), 10, 0)
   205  	if err != nil {
   206  		return errors.Wrapf(err, "cannot parse pid file %s", pausePidPath)
   207  	}
   208  
   209  	return utils.RunUnderSystemdScope(int(pid), "user.slice", "podman-pause.scope")
   210  }
   211  
   212  func setRLimits() error { // nolint:deadcode,unused
   213  	rlimits := new(syscall.Rlimit)
   214  	rlimits.Cur = 1048576
   215  	rlimits.Max = 1048576
   216  	if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, rlimits); err != nil {
   217  		if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, rlimits); err != nil {
   218  			return errors.Wrapf(err, "error getting rlimits")
   219  		}
   220  		rlimits.Cur = rlimits.Max
   221  		if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, rlimits); err != nil {
   222  			return errors.Wrapf(err, "error setting new rlimits")
   223  		}
   224  	}
   225  	return nil
   226  }
   227  
   228  func setUMask() { // nolint:deadcode,unused
   229  	// Be sure we can create directories with 0755 mode.
   230  	syscall.Umask(0022)
   231  }
   232  
   233  // checkInput can be used to verify any of the globalopt values
   234  func checkInput() error { // nolint:deadcode,unused
   235  	return nil
   236  }
   237  
   238  // func getCNIPluginsDir() string {
   239  // 	if rootless.IsRootless() {
   240  // 		return ""
   241  // 	}
   242  //
   243  // 	return registry.PodmanOptions.Network.CNIPluginDirs[0]
   244  // }