github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/pkg/domain/infra/abi/system.go (about) 1 package abi 2 3 import ( 4 "context" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "os/exec" 9 "path/filepath" 10 "strconv" 11 "strings" 12 13 "github.com/containers/common/pkg/config" 14 "github.com/containers/podman/v2/libpod" 15 "github.com/containers/podman/v2/libpod/define" 16 "github.com/containers/podman/v2/pkg/cgroups" 17 "github.com/containers/podman/v2/pkg/domain/entities" 18 "github.com/containers/podman/v2/pkg/rootless" 19 "github.com/containers/podman/v2/pkg/util" 20 "github.com/containers/podman/v2/utils" 21 "github.com/containers/storage" 22 "github.com/pkg/errors" 23 "github.com/sirupsen/logrus" 24 "github.com/spf13/cobra" 25 "github.com/spf13/pflag" 26 ) 27 28 func (ic *ContainerEngine) Info(ctx context.Context) (*define.Info, error) { 29 info, err := ic.Libpod.Info() 30 if err != nil { 31 return nil, err 32 } 33 xdg, err := util.GetRuntimeDir() 34 if err != nil { 35 return nil, err 36 } 37 if len(xdg) == 0 { 38 // If no xdg is returned, assume root socket 39 xdg = "/run" 40 } 41 42 // Glue the socket path together 43 socketPath := filepath.Join(xdg, "podman", "podman.sock") 44 rs := define.RemoteSocket{ 45 Path: socketPath, 46 Exists: false, 47 } 48 49 // Check if the socket exists 50 if fi, err := os.Stat(socketPath); err == nil { 51 if fi.Mode()&os.ModeSocket != 0 { 52 rs.Exists = true 53 } 54 } 55 // TODO 56 // it was suggested future versions of this could perform 57 // a ping on the socket for greater confidence the socket is 58 // actually active. 59 info.Host.RemoteSocket = &rs 60 return info, err 61 } 62 63 func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command) error { 64 // do it only after podman has already re-execed and running with uid==0. 65 if os.Geteuid() == 0 { 66 ownsCgroup, err := cgroups.UserOwnsCurrentSystemdCgroup() 67 if err != nil { 68 logrus.Warnf("Failed to detect the owner for the current cgroup: %v", err) 69 } 70 if !ownsCgroup { 71 conf, err := ic.Config(context.Background()) 72 if err != nil { 73 return err 74 } 75 76 initCommand, err := ioutil.ReadFile("/proc/1/comm") 77 // On errors, default to systemd 78 runsUnderSystemd := err != nil || strings.TrimRight(string(initCommand), "\n") == "systemd" 79 80 unitName := fmt.Sprintf("podman-%d.scope", os.Getpid()) 81 if runsUnderSystemd || conf.Engine.CgroupManager == config.SystemdCgroupsManager { 82 if err := utils.RunUnderSystemdScope(os.Getpid(), "user.slice", unitName); err != nil { 83 logrus.Warnf("Failed to add podman to systemd sandbox cgroup: %v", err) 84 } 85 } 86 } 87 return nil 88 } 89 90 tmpDir, err := ic.Libpod.TmpDir() 91 if err != nil { 92 return err 93 } 94 pausePidPath, err := util.GetRootlessPauseProcessPidPathGivenDir(tmpDir) 95 if err != nil { 96 return errors.Wrapf(err, "could not get pause process pid file path") 97 } 98 99 became, ret, err := rootless.TryJoinPauseProcess(pausePidPath) 100 if err != nil { 101 return err 102 } 103 if became { 104 os.Exit(ret) 105 } 106 107 // if there is no pid file, try to join existing containers, and create a pause process. 108 ctrs, err := ic.Libpod.GetRunningContainers() 109 if err != nil { 110 logrus.Error(err.Error()) 111 os.Exit(1) 112 } 113 114 paths := []string{} 115 for _, ctr := range ctrs { 116 paths = append(paths, ctr.Config().ConmonPidFile) 117 } 118 119 became, ret, err = rootless.TryJoinFromFilePaths(pausePidPath, true, paths) 120 if err := movePauseProcessToScope(ic.Libpod); err != nil { 121 conf, err := ic.Config(context.Background()) 122 if err != nil { 123 return err 124 } 125 if conf.Engine.CgroupManager == config.SystemdCgroupsManager { 126 logrus.Warnf("Failed to add pause process to systemd sandbox cgroup: %v", err) 127 } else { 128 logrus.Debugf("Failed to add pause process to systemd sandbox cgroup: %v", err) 129 } 130 } 131 if err != nil { 132 logrus.Error(errors.Wrapf(err, "invalid internal status, try resetting the pause process with %q", os.Args[0]+" system migrate")) 133 os.Exit(1) 134 } 135 if became { 136 os.Exit(ret) 137 } 138 return nil 139 } 140 141 func movePauseProcessToScope(r *libpod.Runtime) error { 142 tmpDir, err := r.TmpDir() 143 if err != nil { 144 return err 145 } 146 pausePidPath, err := util.GetRootlessPauseProcessPidPathGivenDir(tmpDir) 147 if err != nil { 148 return errors.Wrapf(err, "could not get pause process pid file path") 149 } 150 151 data, err := ioutil.ReadFile(pausePidPath) 152 if err != nil { 153 return errors.Wrapf(err, "cannot read pause pid file") 154 } 155 pid, err := strconv.ParseUint(string(data), 10, 0) 156 if err != nil { 157 return errors.Wrapf(err, "cannot parse pid file %s", pausePidPath) 158 } 159 160 return utils.RunUnderSystemdScope(int(pid), "user.slice", "podman-pause.scope") 161 } 162 163 // checkInput can be used to verify any of the globalopt values 164 func checkInput() error { // nolint:deadcode,unused 165 return nil 166 } 167 168 // SystemPrune removes unused data from the system. Pruning pods, containers, volumes and images. 169 func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.SystemPruneOptions) (*entities.SystemPruneReport, error) { 170 var systemPruneReport = new(entities.SystemPruneReport) 171 podPruneReport, err := ic.prunePodHelper(ctx) 172 if err != nil { 173 return nil, err 174 } 175 systemPruneReport.PodPruneReport = podPruneReport 176 177 containerPruneReport, err := ic.pruneContainersHelper(nil) 178 if err != nil { 179 return nil, err 180 } 181 systemPruneReport.ContainerPruneReport = containerPruneReport 182 183 results, err := ic.Libpod.ImageRuntime().PruneImages(ctx, options.All, nil) 184 if err != nil { 185 return nil, err 186 } 187 report := entities.ImagePruneReport{ 188 Report: entities.Report{ 189 Id: results, 190 Err: nil, 191 }, 192 } 193 194 systemPruneReport.ImagePruneReport = &report 195 196 if options.Volume { 197 volumePruneReport, err := ic.pruneVolumesHelper(ctx) 198 if err != nil { 199 return nil, err 200 } 201 systemPruneReport.VolumePruneReport = volumePruneReport 202 } 203 return systemPruneReport, nil 204 } 205 206 func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.SystemDfOptions) (*entities.SystemDfReport, error) { 207 var ( 208 dfImages = []*entities.SystemDfImageReport{} 209 ) 210 211 // Compute disk-usage stats for all local images. 212 imgs, err := ic.Libpod.ImageRuntime().GetImages() 213 if err != nil { 214 return nil, err 215 } 216 217 imageStats, err := ic.Libpod.ImageRuntime().DiskUsage(ctx, imgs) 218 if err != nil { 219 return nil, err 220 } 221 222 for _, stat := range imageStats { 223 report := entities.SystemDfImageReport{ 224 Repository: stat.Repository, 225 Tag: stat.Tag, 226 ImageID: stat.ID, 227 Created: stat.Created, 228 Size: int64(stat.Size), 229 SharedSize: int64(stat.SharedSize), 230 UniqueSize: int64(stat.UniqueSize), 231 Containers: stat.Containers, 232 } 233 dfImages = append(dfImages, &report) 234 } 235 236 // Get Containers and iterate them 237 cons, err := ic.Libpod.GetAllContainers() 238 if err != nil { 239 return nil, err 240 } 241 dfContainers := make([]*entities.SystemDfContainerReport, 0, len(cons)) 242 for _, c := range cons { 243 iid, _ := c.Image() 244 state, err := c.State() 245 if err != nil { 246 return nil, errors.Wrapf(err, "Failed to get state of container %s", c.ID()) 247 } 248 conSize, err := c.RootFsSize() 249 if err != nil { 250 if errors.Cause(err) == storage.ErrContainerUnknown { 251 logrus.Error(errors.Wrapf(err, "Failed to get root file system size of container %s", c.ID())) 252 } else { 253 return nil, errors.Wrapf(err, "Failed to get root file system size of container %s", c.ID()) 254 } 255 } 256 rwsize, err := c.RWSize() 257 if err != nil { 258 if errors.Cause(err) == storage.ErrContainerUnknown { 259 logrus.Error(errors.Wrapf(err, "Failed to get read/write size of container %s", c.ID())) 260 } else { 261 return nil, errors.Wrapf(err, "Failed to get read/write size of container %s", c.ID()) 262 } 263 } 264 report := entities.SystemDfContainerReport{ 265 ContainerID: c.ID(), 266 Image: iid, 267 Command: c.Command(), 268 LocalVolumes: len(c.UserVolumes()), 269 RWSize: rwsize, 270 Size: conSize, 271 Created: c.CreatedTime(), 272 Status: state.String(), 273 Names: c.Name(), 274 } 275 dfContainers = append(dfContainers, &report) 276 } 277 278 // Get volumes and iterate them 279 vols, err := ic.Libpod.GetAllVolumes() 280 if err != nil { 281 return nil, err 282 } 283 284 running, err := ic.Libpod.GetRunningContainers() 285 if err != nil { 286 return nil, err 287 } 288 runningContainers := make([]string, 0, len(running)) 289 for _, c := range running { 290 runningContainers = append(runningContainers, c.ID()) 291 } 292 293 dfVolumes := make([]*entities.SystemDfVolumeReport, 0, len(vols)) 294 var reclaimableSize int64 295 for _, v := range vols { 296 var consInUse int 297 volSize, err := sizeOfPath(v.MountPoint()) 298 if err != nil { 299 return nil, err 300 } 301 inUse, err := v.VolumeInUse() 302 if err != nil { 303 return nil, err 304 } 305 if len(inUse) == 0 { 306 reclaimableSize += volSize 307 } 308 for _, viu := range inUse { 309 if util.StringInSlice(viu, runningContainers) { 310 consInUse++ 311 } 312 } 313 report := entities.SystemDfVolumeReport{ 314 VolumeName: v.Name(), 315 Links: consInUse, 316 Size: volSize, 317 ReclaimableSize: reclaimableSize, 318 } 319 dfVolumes = append(dfVolumes, &report) 320 } 321 return &entities.SystemDfReport{ 322 Images: dfImages, 323 Containers: dfContainers, 324 Volumes: dfVolumes, 325 }, nil 326 } 327 328 // sizeOfPath determines the file usage of a given path. it was called volumeSize in v1 329 // and now is made to be generic and take a path instead of a libpod volume 330 func sizeOfPath(path string) (int64, error) { 331 var size int64 332 err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error { 333 if err == nil && !info.IsDir() { 334 size += info.Size() 335 } 336 return err 337 }) 338 return size, err 339 } 340 341 func (se *SystemEngine) Reset(ctx context.Context) error { 342 return se.Libpod.Reset(ctx) 343 } 344 345 func (se *SystemEngine) Renumber(ctx context.Context, flags *pflag.FlagSet, config *entities.PodmanConfig) error { 346 return nil 347 } 348 349 func (se SystemEngine) Migrate(ctx context.Context, flags *pflag.FlagSet, config *entities.PodmanConfig, options entities.SystemMigrateOptions) error { 350 return nil 351 } 352 353 func (se SystemEngine) Shutdown(ctx context.Context) { 354 if err := se.Libpod.Shutdown(false); err != nil { 355 logrus.Error(err) 356 } 357 } 358 359 func unshareEnv(graphroot, runroot string) []string { 360 return append(os.Environ(), "_CONTAINERS_USERNS_CONFIGURED=done", 361 fmt.Sprintf("CONTAINERS_GRAPHROOT=%s", graphroot), 362 fmt.Sprintf("CONTAINERS_RUNROOT=%s", runroot)) 363 } 364 365 func (ic *ContainerEngine) Unshare(ctx context.Context, args []string) error { 366 cmd := exec.Command(args[0], args[1:]...) 367 cmd.Env = unshareEnv(ic.Libpod.StorageConfig().GraphRoot, ic.Libpod.StorageConfig().RunRoot) 368 cmd.Stdin = os.Stdin 369 cmd.Stdout = os.Stdout 370 cmd.Stderr = os.Stderr 371 return cmd.Run() 372 } 373 374 func (ic ContainerEngine) Version(ctx context.Context) (*entities.SystemVersionReport, error) { 375 var report entities.SystemVersionReport 376 v, err := define.GetVersion() 377 if err != nil { 378 return nil, err 379 } 380 report.Client = &v 381 return &report, err 382 }