github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/pkg/domain/infra/abi/containers.go (about) 1 // +build ABISupport 2 3 package abi 4 5 import ( 6 "context" 7 "fmt" 8 "io/ioutil" 9 "os" 10 "strconv" 11 "strings" 12 "sync" 13 14 "github.com/containers/buildah" 15 "github.com/containers/common/pkg/config" 16 "github.com/containers/image/v5/manifest" 17 "github.com/containers/libpod/libpod" 18 "github.com/containers/libpod/libpod/define" 19 "github.com/containers/libpod/libpod/events" 20 "github.com/containers/libpod/libpod/image" 21 "github.com/containers/libpod/libpod/logs" 22 "github.com/containers/libpod/pkg/checkpoint" 23 "github.com/containers/libpod/pkg/domain/entities" 24 "github.com/containers/libpod/pkg/domain/infra/abi/terminal" 25 "github.com/containers/libpod/pkg/ps" 26 "github.com/containers/libpod/pkg/rootless" 27 "github.com/containers/libpod/pkg/signal" 28 "github.com/containers/libpod/pkg/specgen" 29 "github.com/containers/libpod/pkg/specgen/generate" 30 "github.com/containers/storage" 31 "github.com/pkg/errors" 32 "github.com/sirupsen/logrus" 33 ) 34 35 // getContainersByContext gets pods whether all, latest, or a slice of names/ids 36 // is specified. 37 func getContainersByContext(all, latest bool, names []string, runtime *libpod.Runtime) (ctrs []*libpod.Container, err error) { 38 var ctr *libpod.Container 39 ctrs = []*libpod.Container{} 40 41 switch { 42 case all: 43 ctrs, err = runtime.GetAllContainers() 44 case latest: 45 ctr, err = runtime.GetLatestContainer() 46 ctrs = append(ctrs, ctr) 47 default: 48 for _, n := range names { 49 ctr, e := runtime.LookupContainer(n) 50 if e != nil { 51 // Log all errors here, so callers don't need to. 52 logrus.Debugf("Error looking up container %q: %v", n, e) 53 if err == nil { 54 err = e 55 } 56 } else { 57 ctrs = append(ctrs, ctr) 58 } 59 } 60 } 61 return 62 } 63 64 // TODO: Should return *entities.ContainerExistsReport, error 65 func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrId string) (*entities.BoolReport, error) { 66 _, err := ic.Libpod.LookupContainer(nameOrId) 67 if err != nil && errors.Cause(err) != define.ErrNoSuchCtr { 68 return nil, err 69 } 70 return &entities.BoolReport{Value: err == nil}, nil 71 } 72 73 func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []string, options entities.WaitOptions) ([]entities.WaitReport, error) { 74 var ( 75 responses []entities.WaitReport 76 ) 77 ctrs, err := getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod) 78 if err != nil { 79 return nil, err 80 } 81 for _, c := range ctrs { 82 response := entities.WaitReport{Id: c.ID()} 83 exitCode, err := c.WaitForConditionWithInterval(options.Interval, options.Condition) 84 if err != nil { 85 response.Error = err 86 } else { 87 response.ExitCode = exitCode 88 } 89 responses = append(responses, response) 90 } 91 return responses, nil 92 } 93 94 func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) { 95 var ( 96 ctrs []*libpod.Container 97 err error 98 report []*entities.PauseUnpauseReport 99 ) 100 if options.All { 101 ctrs, err = ic.Libpod.GetAllContainers() 102 } else { 103 ctrs, err = getContainersByContext(false, false, namesOrIds, ic.Libpod) 104 } 105 if err != nil { 106 return nil, err 107 } 108 for _, c := range ctrs { 109 err := c.Pause() 110 report = append(report, &entities.PauseUnpauseReport{Id: c.ID(), Err: err}) 111 } 112 return report, nil 113 } 114 115 func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) { 116 var ( 117 ctrs []*libpod.Container 118 err error 119 report []*entities.PauseUnpauseReport 120 ) 121 if options.All { 122 ctrs, err = ic.Libpod.GetAllContainers() 123 } else { 124 ctrs, err = getContainersByContext(false, false, namesOrIds, ic.Libpod) 125 } 126 if err != nil { 127 return nil, err 128 } 129 for _, c := range ctrs { 130 err := c.Unpause() 131 report = append(report, &entities.PauseUnpauseReport{Id: c.ID(), Err: err}) 132 } 133 return report, nil 134 } 135 func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []string, options entities.StopOptions) ([]*entities.StopReport, error) { 136 var ( 137 reports []*entities.StopReport 138 ) 139 names := namesOrIds 140 for _, cidFile := range options.CIDFiles { 141 content, err := ioutil.ReadFile(cidFile) 142 if err != nil { 143 return nil, errors.Wrap(err, "error reading CIDFile") 144 } 145 id := strings.Split(string(content), "\n")[0] 146 names = append(names, id) 147 } 148 ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod) 149 if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) { 150 return nil, err 151 } 152 for _, con := range ctrs { 153 report := entities.StopReport{Id: con.ID()} 154 err = con.StopWithTimeout(options.Timeout) 155 if err != nil { 156 // These first two are considered non-fatal under the right conditions 157 if errors.Cause(err) == define.ErrCtrStopped { 158 logrus.Debugf("Container %s is already stopped", con.ID()) 159 reports = append(reports, &report) 160 continue 161 162 } else if options.All && errors.Cause(err) == define.ErrCtrStateInvalid { 163 logrus.Debugf("Container %s is not running, could not stop", con.ID()) 164 reports = append(reports, &report) 165 continue 166 } 167 report.Err = err 168 reports = append(reports, &report) 169 continue 170 } 171 reports = append(reports, &report) 172 } 173 return reports, nil 174 } 175 176 func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) { 177 var ( 178 reports []*entities.KillReport 179 ) 180 sig, err := signal.ParseSignalNameOrNumber(options.Signal) 181 if err != nil { 182 return nil, err 183 } 184 ctrs, err := getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod) 185 if err != nil { 186 return nil, err 187 } 188 for _, con := range ctrs { 189 reports = append(reports, &entities.KillReport{ 190 Id: con.ID(), 191 Err: con.Kill(uint(sig)), 192 }) 193 } 194 return reports, nil 195 } 196 func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []string, options entities.RestartOptions) ([]*entities.RestartReport, error) { 197 var ( 198 reports []*entities.RestartReport 199 ) 200 ctrs, err := getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod) 201 if err != nil { 202 return nil, err 203 } 204 for _, con := range ctrs { 205 timeout := con.StopTimeout() 206 if options.Timeout != nil { 207 timeout = *options.Timeout 208 } 209 reports = append(reports, &entities.RestartReport{ 210 Id: con.ID(), 211 Err: con.RestartWithTimeout(ctx, timeout), 212 }) 213 } 214 return reports, nil 215 } 216 217 func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, options entities.RmOptions) ([]*entities.RmReport, error) { 218 var ( 219 reports []*entities.RmReport 220 ) 221 if options.Storage { 222 for _, ctr := range namesOrIds { 223 report := entities.RmReport{Id: ctr} 224 if err := ic.Libpod.RemoveStorageContainer(ctr, options.Force); err != nil { 225 report.Err = err 226 } 227 reports = append(reports, &report) 228 } 229 return reports, nil 230 } 231 232 names := namesOrIds 233 for _, cidFile := range options.CIDFiles { 234 content, err := ioutil.ReadFile(cidFile) 235 if err != nil { 236 return nil, errors.Wrap(err, "error reading CIDFile") 237 } 238 id := strings.Split(string(content), "\n")[0] 239 names = append(names, id) 240 } 241 242 ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod) 243 if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) { 244 // Failed to get containers. If force is specified, get the containers ID 245 // and evict them 246 if !options.Force { 247 return nil, err 248 } 249 250 for _, ctr := range namesOrIds { 251 logrus.Debugf("Evicting container %q", ctr) 252 report := entities.RmReport{Id: ctr} 253 id, err := ic.Libpod.EvictContainer(ctx, ctr, options.Volumes) 254 if err != nil { 255 if options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr { 256 logrus.Debugf("Ignoring error (--allow-missing): %v", err) 257 reports = append(reports, &report) 258 continue 259 } 260 report.Err = errors.Wrapf(err, "Failed to evict container: %q", id) 261 reports = append(reports, &report) 262 continue 263 } 264 reports = append(reports, &report) 265 } 266 return reports, nil 267 } 268 269 for _, c := range ctrs { 270 report := entities.RmReport{Id: c.ID()} 271 err := ic.Libpod.RemoveContainer(ctx, c, options.Force, options.Volumes) 272 if err != nil { 273 if options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr { 274 logrus.Debugf("Ignoring error (--allow-missing): %v", err) 275 reports = append(reports, &report) 276 continue 277 } 278 logrus.Debugf("Failed to remove container %s: %s", c.ID(), err.Error()) 279 report.Err = err 280 reports = append(reports, &report) 281 continue 282 } 283 reports = append(reports, &report) 284 } 285 return reports, nil 286 } 287 288 func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]*entities.ContainerInspectReport, error) { 289 var reports []*entities.ContainerInspectReport 290 ctrs, err := getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod) 291 if err != nil { 292 return nil, err 293 } 294 for _, c := range ctrs { 295 data, err := c.Inspect(options.Size) 296 if err != nil { 297 return nil, err 298 } 299 reports = append(reports, &entities.ContainerInspectReport{InspectContainerData: data}) 300 } 301 return reports, nil 302 } 303 304 func (ic *ContainerEngine) ContainerTop(ctx context.Context, options entities.TopOptions) (*entities.StringSliceReport, error) { 305 var ( 306 container *libpod.Container 307 err error 308 ) 309 310 // Look up the container. 311 if options.Latest { 312 container, err = ic.Libpod.GetLatestContainer() 313 } else { 314 container, err = ic.Libpod.LookupContainer(options.NameOrID) 315 } 316 if err != nil { 317 return nil, errors.Wrap(err, "unable to lookup requested container") 318 } 319 320 // Run Top. 321 report := &entities.StringSliceReport{} 322 report.Value, err = container.Top(options.Descriptors) 323 return report, err 324 } 325 326 func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrId string, options entities.CommitOptions) (*entities.CommitReport, error) { 327 var ( 328 mimeType string 329 ) 330 ctr, err := ic.Libpod.LookupContainer(nameOrId) 331 if err != nil { 332 return nil, err 333 } 334 rtc, err := ic.Libpod.GetConfig() 335 if err != nil { 336 return nil, err 337 } 338 switch options.Format { 339 case "oci": 340 mimeType = buildah.OCIv1ImageManifest 341 if len(options.Message) > 0 { 342 return nil, errors.Errorf("messages are only compatible with the docker image format (-f docker)") 343 } 344 case "docker": 345 mimeType = manifest.DockerV2Schema2MediaType 346 default: 347 return nil, errors.Errorf("unrecognized image format %q", options.Format) 348 } 349 sc := image.GetSystemContext(rtc.Engine.SignaturePolicyPath, "", false) 350 coptions := buildah.CommitOptions{ 351 SignaturePolicyPath: rtc.Engine.SignaturePolicyPath, 352 ReportWriter: options.Writer, 353 SystemContext: sc, 354 PreferredManifestType: mimeType, 355 } 356 opts := libpod.ContainerCommitOptions{ 357 CommitOptions: coptions, 358 Pause: options.Pause, 359 IncludeVolumes: options.IncludeVolumes, 360 Message: options.Message, 361 Changes: options.Changes, 362 Author: options.Author, 363 } 364 newImage, err := ctr.Commit(ctx, options.ImageName, opts) 365 if err != nil { 366 return nil, err 367 } 368 return &entities.CommitReport{Id: newImage.ID()}, nil 369 } 370 371 func (ic *ContainerEngine) ContainerExport(ctx context.Context, nameOrId string, options entities.ContainerExportOptions) error { 372 ctr, err := ic.Libpod.LookupContainer(nameOrId) 373 if err != nil { 374 return err 375 } 376 return ctr.Export(options.Output) 377 } 378 379 func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds []string, options entities.CheckpointOptions) ([]*entities.CheckpointReport, error) { 380 var ( 381 err error 382 cons []*libpod.Container 383 reports []*entities.CheckpointReport 384 ) 385 checkOpts := libpod.ContainerCheckpointOptions{ 386 Keep: options.Keep, 387 TCPEstablished: options.TCPEstablished, 388 TargetFile: options.Export, 389 IgnoreRootfs: options.IgnoreRootFS, 390 } 391 392 if options.All { 393 running := func(c *libpod.Container) bool { 394 state, _ := c.State() 395 return state == define.ContainerStateRunning 396 } 397 cons, err = ic.Libpod.GetContainers(running) 398 } else { 399 cons, err = getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod) 400 } 401 if err != nil { 402 return nil, err 403 } 404 for _, con := range cons { 405 err = con.Checkpoint(ctx, checkOpts) 406 reports = append(reports, &entities.CheckpointReport{ 407 Err: err, 408 Id: con.ID(), 409 }) 410 } 411 return reports, nil 412 } 413 414 func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []string, options entities.RestoreOptions) ([]*entities.RestoreReport, error) { 415 var ( 416 cons []*libpod.Container 417 err error 418 filterFuncs []libpod.ContainerFilter 419 reports []*entities.RestoreReport 420 ) 421 422 restoreOptions := libpod.ContainerCheckpointOptions{ 423 Keep: options.Keep, 424 TCPEstablished: options.TCPEstablished, 425 TargetFile: options.Import, 426 Name: options.Name, 427 IgnoreRootfs: options.IgnoreRootFS, 428 IgnoreStaticIP: options.IgnoreStaticIP, 429 IgnoreStaticMAC: options.IgnoreStaticMAC, 430 } 431 432 filterFuncs = append(filterFuncs, func(c *libpod.Container) bool { 433 state, _ := c.State() 434 return state == define.ContainerStateExited 435 }) 436 437 switch { 438 case options.Import != "": 439 cons, err = checkpoint.CRImportCheckpoint(ctx, ic.Libpod, options.Import, options.Name) 440 case options.All: 441 cons, err = ic.Libpod.GetContainers(filterFuncs...) 442 default: 443 cons, err = getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod) 444 } 445 if err != nil { 446 return nil, err 447 } 448 for _, con := range cons { 449 err := con.Restore(ctx, restoreOptions) 450 reports = append(reports, &entities.RestoreReport{ 451 Err: err, 452 Id: con.ID(), 453 }) 454 } 455 return reports, nil 456 } 457 458 func (ic *ContainerEngine) ContainerCreate(ctx context.Context, s *specgen.SpecGenerator) (*entities.ContainerCreateReport, error) { 459 if err := generate.CompleteSpec(ctx, ic.Libpod, s); err != nil { 460 return nil, err 461 } 462 ctr, err := generate.MakeContainer(ic.Libpod, s) 463 if err != nil { 464 return nil, err 465 } 466 return &entities.ContainerCreateReport{Id: ctr.ID()}, nil 467 } 468 469 func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrId string, options entities.AttachOptions) error { 470 ctrs, err := getContainersByContext(false, options.Latest, []string{nameOrId}, ic.Libpod) 471 if err != nil { 472 return err 473 } 474 ctr := ctrs[0] 475 conState, err := ctr.State() 476 if err != nil { 477 return errors.Wrapf(err, "unable to determine state of %s", ctr.ID()) 478 } 479 if conState != define.ContainerStateRunning { 480 return errors.Errorf("you can only attach to running containers") 481 } 482 483 // If the container is in a pod, also set to recursively start dependencies 484 if err := terminal.StartAttachCtr(ctx, ctr, options.Stdin, options.Stderr, options.Stdin, options.DetachKeys, options.SigProxy, false, ctr.PodID() != ""); err != nil && errors.Cause(err) != define.ErrDetach { 485 return errors.Wrapf(err, "error attaching to container %s", ctr.ID()) 486 } 487 return nil 488 } 489 490 func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrId string, options entities.ExecOptions) (int, error) { 491 ec := define.ExecErrorCodeGeneric 492 if options.PreserveFDs > 0 { 493 entries, err := ioutil.ReadDir("/proc/self/fd") 494 if err != nil { 495 return ec, errors.Wrapf(err, "unable to read /proc/self/fd") 496 } 497 498 m := make(map[int]bool) 499 for _, e := range entries { 500 i, err := strconv.Atoi(e.Name()) 501 if err != nil { 502 return ec, errors.Wrapf(err, "cannot parse %s in /proc/self/fd", e.Name()) 503 } 504 m[i] = true 505 } 506 507 for i := 3; i < 3+int(options.PreserveFDs); i++ { 508 if _, found := m[i]; !found { 509 return ec, errors.New("invalid --preserve-fds=N specified. Not enough FDs available") 510 } 511 } 512 } 513 ctrs, err := getContainersByContext(false, options.Latest, []string{nameOrId}, ic.Libpod) 514 if err != nil { 515 return ec, err 516 } 517 ctr := ctrs[0] 518 ec, err = terminal.ExecAttachCtr(ctx, ctr, options.Tty, options.Privileged, options.Envs, options.Cmd, options.User, options.WorkDir, &options.Streams, options.PreserveFDs, options.DetachKeys) 519 return define.TranslateExecErrorToExitCode(ec, err), err 520 } 521 522 func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []string, options entities.ContainerStartOptions) ([]*entities.ContainerStartReport, error) { 523 var reports []*entities.ContainerStartReport 524 var exitCode = define.ExecErrorCodeGeneric 525 ctrs, err := getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod) 526 if err != nil { 527 return nil, err 528 } 529 // There can only be one container if attach was used 530 for _, ctr := range ctrs { 531 ctrState, err := ctr.State() 532 if err != nil { 533 return nil, err 534 } 535 ctrRunning := ctrState == define.ContainerStateRunning 536 537 if options.Attach { 538 err = terminal.StartAttachCtr(ctx, ctr, options.Stdout, options.Stderr, options.Stdin, options.DetachKeys, options.SigProxy, !ctrRunning, ctr.PodID() != "") 539 if errors.Cause(err) == define.ErrDetach { 540 // User manually detached 541 // Exit cleanly immediately 542 reports = append(reports, &entities.ContainerStartReport{ 543 Id: ctr.ID(), 544 Err: nil, 545 ExitCode: 0, 546 }) 547 return reports, nil 548 } 549 550 if errors.Cause(err) == define.ErrWillDeadlock { 551 logrus.Debugf("Deadlock error: %v", err) 552 reports = append(reports, &entities.ContainerStartReport{ 553 Id: ctr.ID(), 554 Err: err, 555 ExitCode: define.ExitCode(err), 556 }) 557 return reports, errors.Errorf("attempting to start container %s would cause a deadlock; please run 'podman system renumber' to resolve", ctr.ID()) 558 } 559 560 if ctrRunning { 561 reports = append(reports, &entities.ContainerStartReport{ 562 Id: ctr.ID(), 563 Err: nil, 564 ExitCode: 0, 565 }) 566 return reports, err 567 } 568 569 if err != nil { 570 reports = append(reports, &entities.ContainerStartReport{ 571 Id: ctr.ID(), 572 Err: err, 573 ExitCode: exitCode, 574 }) 575 return reports, errors.Wrapf(err, "unable to start container %s", ctr.ID()) 576 } 577 578 if ecode, err := ctr.Wait(); err != nil { 579 if errors.Cause(err) == define.ErrNoSuchCtr { 580 // Check events 581 event, err := ic.Libpod.GetLastContainerEvent(ctr.ID(), events.Exited) 582 if err != nil { 583 logrus.Errorf("Cannot get exit code: %v", err) 584 exitCode = define.ExecErrorCodeNotFound 585 } else { 586 exitCode = event.ContainerExitCode 587 } 588 } 589 } else { 590 exitCode = int(ecode) 591 } 592 reports = append(reports, &entities.ContainerStartReport{ 593 Id: ctr.ID(), 594 Err: err, 595 ExitCode: exitCode, 596 }) 597 return reports, nil 598 } // end attach 599 600 // Start the container if it's not running already. 601 if !ctrRunning { 602 // Handle non-attach start 603 // If the container is in a pod, also set to recursively start dependencies 604 report := &entities.ContainerStartReport{ 605 Id: ctr.ID(), 606 ExitCode: 125, 607 } 608 if err := ctr.Start(ctx, ctr.PodID() != ""); err != nil { 609 // if lastError != nil { 610 // fmt.Fprintln(os.Stderr, lastError) 611 // } 612 report.Err = err 613 if errors.Cause(err) == define.ErrWillDeadlock { 614 report.Err = errors.Wrapf(err, "please run 'podman system renumber' to resolve deadlocks") 615 reports = append(reports, report) 616 continue 617 } 618 report.Err = errors.Wrapf(err, "unable to start container %q", ctr.ID()) 619 reports = append(reports, report) 620 continue 621 } 622 report.ExitCode = 0 623 reports = append(reports, report) 624 } 625 } 626 return reports, nil 627 } 628 629 func (ic *ContainerEngine) ContainerList(ctx context.Context, options entities.ContainerListOptions) ([]entities.ListContainer, error) { 630 return ps.GetContainerLists(ic.Libpod, options) 631 } 632 633 // ContainerDiff provides changes to given container 634 func (ic *ContainerEngine) ContainerDiff(ctx context.Context, nameOrId string, opts entities.DiffOptions) (*entities.DiffReport, error) { 635 if opts.Latest { 636 ctnr, err := ic.Libpod.GetLatestContainer() 637 if err != nil { 638 return nil, errors.Wrap(err, "unable to get latest container") 639 } 640 nameOrId = ctnr.ID() 641 } 642 changes, err := ic.Libpod.GetDiff("", nameOrId) 643 return &entities.DiffReport{Changes: changes}, err 644 } 645 646 func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.ContainerRunOptions) (*entities.ContainerRunReport, error) { 647 var ( 648 joinPod bool 649 ) 650 if err := generate.CompleteSpec(ctx, ic.Libpod, opts.Spec); err != nil { 651 return nil, err 652 } 653 ctr, err := generate.MakeContainer(ic.Libpod, opts.Spec) 654 if err != nil { 655 return nil, err 656 } 657 658 if len(ctr.PodID()) > 0 { 659 joinPod = true 660 } 661 report := entities.ContainerRunReport{Id: ctr.ID()} 662 663 if logrus.GetLevel() == logrus.DebugLevel { 664 cgroupPath, err := ctr.CGroupPath() 665 if err == nil { 666 logrus.Debugf("container %q has CgroupParent %q", ctr.ID(), cgroupPath) 667 } 668 } 669 if opts.Detach { 670 // if the container was created as part of a pod, also start its dependencies, if any. 671 if err := ctr.Start(ctx, joinPod); err != nil { 672 // This means the command did not exist 673 report.ExitCode = define.ExitCode(err) 674 return &report, err 675 } 676 677 return &report, nil 678 } 679 680 // if the container was created as part of a pod, also start its dependencies, if any. 681 if err := terminal.StartAttachCtr(ctx, ctr, opts.OutputStream, opts.ErrorStream, opts.InputStream, opts.DetachKeys, opts.SigProxy, true, joinPod); err != nil { 682 // We've manually detached from the container 683 // Do not perform cleanup, or wait for container exit code 684 // Just exit immediately 685 if errors.Cause(err) == define.ErrDetach { 686 report.ExitCode = 0 687 return &report, nil 688 } 689 if opts.Rm { 690 if deleteError := ic.Libpod.RemoveContainer(ctx, ctr, true, false); deleteError != nil { 691 logrus.Debugf("unable to remove container %s after failing to start and attach to it", ctr.ID()) 692 } 693 } 694 if errors.Cause(err) == define.ErrWillDeadlock { 695 logrus.Debugf("Deadlock error on %q: %v", ctr.ID(), err) 696 report.ExitCode = define.ExitCode(err) 697 return &report, errors.Errorf("attempting to start container %s would cause a deadlock; please run 'podman system renumber' to resolve", ctr.ID()) 698 } 699 report.ExitCode = define.ExitCode(err) 700 return &report, err 701 } 702 703 if ecode, err := ctr.Wait(); err != nil { 704 if errors.Cause(err) == define.ErrNoSuchCtr { 705 // Check events 706 event, err := ic.Libpod.GetLastContainerEvent(ctr.ID(), events.Exited) 707 if err != nil { 708 logrus.Errorf("Cannot get exit code: %v", err) 709 report.ExitCode = define.ExecErrorCodeNotFound 710 } else { 711 report.ExitCode = event.ContainerExitCode 712 } 713 } 714 } else { 715 report.ExitCode = int(ecode) 716 } 717 return &report, nil 718 } 719 720 func (ic *ContainerEngine) ContainerLogs(ctx context.Context, containers []string, options entities.ContainerLogsOptions) error { 721 if options.Writer == nil { 722 return errors.New("no io.Writer set for container logs") 723 } 724 725 var wg sync.WaitGroup 726 727 ctrs, err := getContainersByContext(false, options.Latest, containers, ic.Libpod) 728 if err != nil { 729 return err 730 } 731 732 logOpts := &logs.LogOptions{ 733 Multi: len(ctrs) > 1, 734 Details: options.Details, 735 Follow: options.Follow, 736 Since: options.Since, 737 Tail: options.Tail, 738 Timestamps: options.Timestamps, 739 UseName: options.Names, 740 WaitGroup: &wg, 741 } 742 743 chSize := len(ctrs) * int(options.Tail) 744 if chSize <= 0 { 745 chSize = 1 746 } 747 logChannel := make(chan *logs.LogLine, chSize) 748 749 if err := ic.Libpod.Log(ctrs, logOpts, logChannel); err != nil { 750 return err 751 } 752 753 go func() { 754 wg.Wait() 755 close(logChannel) 756 }() 757 758 for line := range logChannel { 759 fmt.Fprintln(options.Writer, line.String(logOpts)) 760 } 761 762 return nil 763 } 764 765 func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []string, options entities.ContainerCleanupOptions) ([]*entities.ContainerCleanupReport, error) { 766 var reports []*entities.ContainerCleanupReport 767 ctrs, err := getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod) 768 if err != nil { 769 return nil, err 770 } 771 for _, ctr := range ctrs { 772 var err error 773 report := entities.ContainerCleanupReport{Id: ctr.ID()} 774 if options.Remove { 775 err = ic.Libpod.RemoveContainer(ctx, ctr, false, true) 776 if err != nil { 777 report.RmErr = errors.Wrapf(err, "failed to cleanup and remove container %v", ctr.ID()) 778 } 779 } else { 780 err := ctr.Cleanup(ctx) 781 if err != nil { 782 report.CleanErr = errors.Wrapf(err, "failed to cleanup container %v", ctr.ID()) 783 } 784 } 785 786 if options.RemoveImage { 787 _, imageName := ctr.Image() 788 ctrImage, err := ic.Libpod.ImageRuntime().NewFromLocal(imageName) 789 if err != nil { 790 report.RmiErr = err 791 reports = append(reports, &report) 792 continue 793 } 794 _, err = ic.Libpod.RemoveImage(ctx, ctrImage, false) 795 report.RmiErr = err 796 } 797 reports = append(reports, &report) 798 } 799 return reports, nil 800 } 801 802 func (ic *ContainerEngine) ContainerInit(ctx context.Context, namesOrIds []string, options entities.ContainerInitOptions) ([]*entities.ContainerInitReport, error) { 803 var reports []*entities.ContainerInitReport 804 ctrs, err := getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod) 805 if err != nil { 806 return nil, err 807 } 808 for _, ctr := range ctrs { 809 report := entities.ContainerInitReport{Id: ctr.ID()} 810 report.Err = ctr.Init(ctx) 811 reports = append(reports, &report) 812 } 813 return reports, nil 814 } 815 816 func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIds []string, options entities.ContainerMountOptions) ([]*entities.ContainerMountReport, error) { 817 if os.Geteuid() != 0 { 818 if driver := ic.Libpod.StorageConfig().GraphDriverName; driver != "vfs" { 819 // Do not allow to mount a graphdriver that is not vfs if we are creating the userns as part 820 // of the mount command. 821 return nil, fmt.Errorf("cannot mount using driver %s in rootless mode", driver) 822 } 823 824 became, ret, err := rootless.BecomeRootInUserNS("") 825 if err != nil { 826 return nil, err 827 } 828 if became { 829 os.Exit(ret) 830 } 831 } 832 var reports []*entities.ContainerMountReport 833 ctrs, err := getContainersByContext(options.All, options.Latest, nameOrIds, ic.Libpod) 834 if err != nil { 835 return nil, err 836 } 837 for _, ctr := range ctrs { 838 report := entities.ContainerMountReport{Id: ctr.ID()} 839 report.Path, report.Err = ctr.Mount() 840 reports = append(reports, &report) 841 } 842 if len(reports) > 0 { 843 return reports, nil 844 } 845 846 // No containers were passed, so we send back what is mounted 847 ctrs, err = getContainersByContext(true, false, []string{}, ic.Libpod) 848 if err != nil { 849 return nil, err 850 } 851 for _, ctr := range ctrs { 852 mounted, path, err := ctr.Mounted() 853 if err != nil { 854 return nil, err 855 } 856 857 if mounted { 858 reports = append(reports, &entities.ContainerMountReport{ 859 Id: ctr.ID(), 860 Name: ctr.Name(), 861 Path: path, 862 }) 863 } 864 } 865 return reports, nil 866 } 867 868 func (ic *ContainerEngine) ContainerUnmount(ctx context.Context, nameOrIds []string, options entities.ContainerUnmountOptions) ([]*entities.ContainerUnmountReport, error) { 869 var reports []*entities.ContainerUnmountReport 870 ctrs, err := getContainersByContext(options.All, options.Latest, nameOrIds, ic.Libpod) 871 if err != nil { 872 return nil, err 873 } 874 for _, ctr := range ctrs { 875 state, err := ctr.State() 876 if err != nil { 877 logrus.Debugf("Error umounting container %s state: %s", ctr.ID(), err.Error()) 878 continue 879 } 880 if state == define.ContainerStateRunning { 881 logrus.Debugf("Error umounting container %s, is running", ctr.ID()) 882 continue 883 } 884 885 report := entities.ContainerUnmountReport{Id: ctr.ID()} 886 if err := ctr.Unmount(options.Force); err != nil { 887 if options.All && errors.Cause(err) == storage.ErrLayerNotMounted { 888 logrus.Debugf("Error umounting container %s, storage.ErrLayerNotMounted", ctr.ID()) 889 continue 890 } 891 report.Err = errors.Wrapf(err, "error unmounting container %s", ctr.ID()) 892 } 893 reports = append(reports, &report) 894 } 895 return reports, nil 896 } 897 898 // GetConfig returns a copy of the configuration used by the runtime 899 func (ic *ContainerEngine) Config(_ context.Context) (*config.Config, error) { 900 return ic.Libpod.GetConfig() 901 }