diff options
Diffstat (limited to 'pkg/domain/infra/abi')
-rw-r--r-- | pkg/domain/infra/abi/containers.go | 280 | ||||
-rw-r--r-- | pkg/domain/infra/abi/generate.go | 60 | ||||
-rw-r--r-- | pkg/domain/infra/abi/images.go | 30 | ||||
-rw-r--r-- | pkg/domain/infra/abi/images_list.go | 10 | ||||
-rw-r--r-- | pkg/domain/infra/abi/manifest.go | 28 | ||||
-rw-r--r-- | pkg/domain/infra/abi/network.go | 2 | ||||
-rw-r--r-- | pkg/domain/infra/abi/parse/parse.go | 5 | ||||
-rw-r--r-- | pkg/domain/infra/abi/play.go | 132 | ||||
-rw-r--r-- | pkg/domain/infra/abi/play_utils.go | 16 | ||||
-rw-r--r-- | pkg/domain/infra/abi/play_utils_test.go | 38 | ||||
-rw-r--r-- | pkg/domain/infra/abi/pods.go | 70 | ||||
-rw-r--r-- | pkg/domain/infra/abi/secrets.go | 10 | ||||
-rw-r--r-- | pkg/domain/infra/abi/system.go | 18 | ||||
-rw-r--r-- | pkg/domain/infra/abi/terminal/sigproxy_commn.go (renamed from pkg/domain/infra/abi/terminal/sigproxy_linux.go) | 3 | ||||
-rw-r--r-- | pkg/domain/infra/abi/terminal/terminal_common.go (renamed from pkg/domain/infra/abi/terminal/terminal_linux.go) | 5 | ||||
-rw-r--r-- | pkg/domain/infra/abi/terminal/terminal_unsupported.go | 25 | ||||
-rw-r--r-- | pkg/domain/infra/abi/trust.go | 141 | ||||
-rw-r--r-- | pkg/domain/infra/abi/volumes.go | 2 |
18 files changed, 528 insertions, 347 deletions
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index 783224e9c..535c4a613 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -4,10 +4,8 @@ import ( "context" "errors" "fmt" - "io/ioutil" "os" "strconv" - "strings" "sync" "time" @@ -40,6 +38,7 @@ import ( // is specified. It also returns a list of the corresponding input name used to lookup each container. func getContainersAndInputByContext(all, latest bool, names []string, filters map[string][]string, runtime *libpod.Runtime) (ctrs []*libpod.Container, rawInput []string, err error) { var ctr *libpod.Container + var filteredCtrs []*libpod.Container ctrs = []*libpod.Container{} filterFuncs := make([]libpod.ContainerFilter, 0, len(filters)) @@ -58,7 +57,17 @@ func getContainersAndInputByContext(all, latest bool, names []string, filters ma } rawInput = []string{} for _, candidate := range ctrs { - rawInput = append(rawInput, candidate.ID()) + if len(names) > 0 { + for _, name := range names { + if candidate.ID() == name || candidate.Name() == name { + rawInput = append(rawInput, candidate.ID()) + filteredCtrs = append(filteredCtrs, candidate) + } + } + ctrs = filteredCtrs + } else { + rawInput = append(rawInput, candidate.ID()) + } } case all: ctrs, err = runtime.GetAllContainers() @@ -142,10 +151,10 @@ func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []stri if err != nil { return nil, err } - ctrMap := map[string]string{} + idToRawInput := map[string]string{} if len(rawInputs) == len(ctrs) { for i := range ctrs { - ctrMap[ctrs[i].ID()] = rawInputs[i] + idToRawInput[ctrs[i].ID()] = rawInputs[i] } } reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs)) @@ -158,7 +167,7 @@ func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []stri reports = append(reports, &entities.PauseUnpauseReport{ Id: c.ID(), Err: err, - RawInput: ctrMap[c.ID()], + RawInput: idToRawInput[c.ID()], }) } return reports, nil @@ -169,10 +178,10 @@ func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []st if err != nil { return nil, err } - ctrMap := map[string]string{} + idToRawInput := map[string]string{} if len(rawInputs) == len(ctrs) { for i := range ctrs { - ctrMap[ctrs[i].ID()] = rawInputs[i] + idToRawInput[ctrs[i].ID()] = rawInputs[i] } } reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs)) @@ -185,7 +194,7 @@ func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []st reports = append(reports, &entities.PauseUnpauseReport{ Id: c.ID(), Err: err, - RawInput: ctrMap[c.ID()], + RawInput: idToRawInput[c.ID()], }) } return reports, nil @@ -196,10 +205,10 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin if err != nil && !(options.Ignore && errors.Is(err, define.ErrNoSuchCtr)) { return nil, err } - ctrMap := map[string]string{} + idToRawInput := map[string]string{} if len(rawInputs) == len(ctrs) { for i := range ctrs { - ctrMap[ctrs[i].ID()] = rawInputs[i] + idToRawInput[ctrs[i].ID()] = rawInputs[i] } } errMap, err := parallelctr.ContainerOp(ctx, ctrs, func(c *libpod.Container) error { @@ -245,7 +254,7 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin if options.All { report.RawInput = ctr.ID() } else { - report.RawInput = ctrMap[ctr.ID()] + report.RawInput = idToRawInput[ctr.ID()] } report.Err = err reports = append(reports, report) @@ -275,10 +284,10 @@ func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []strin if err != nil { return nil, err } - ctrMap := map[string]string{} + idToRawInput := map[string]string{} if len(rawInputs) == len(ctrs) { for i := range ctrs { - ctrMap[ctrs[i].ID()] = rawInputs[i] + idToRawInput[ctrs[i].ID()] = rawInputs[i] } } reports := make([]*entities.KillReport, 0, len(ctrs)) @@ -291,7 +300,7 @@ func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []strin reports = append(reports, &entities.KillReport{ Id: con.ID(), Err: err, - RawInput: ctrMap[con.ID()], + RawInput: idToRawInput[con.ID()], }) } return reports, nil @@ -299,31 +308,42 @@ func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []strin func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []string, options entities.RestartOptions) ([]*entities.RestartReport, error) { var ( - ctrs []*libpod.Container - err error + ctrs []*libpod.Container + err error + rawInputs = []string{} ) if options.Running { ctrs, err = ic.Libpod.GetRunningContainers() + for _, candidate := range ctrs { + rawInputs = append(rawInputs, candidate.ID()) + } + if err != nil { return nil, err } } else { - ctrs, err = getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod) + ctrs, rawInputs, err = getContainersAndInputByContext(options.All, options.Latest, namesOrIds, options.Filters, ic.Libpod) if err != nil { return nil, err } } - + idToRawInput := map[string]string{} + if len(rawInputs) == len(ctrs) { + for i := range ctrs { + idToRawInput[ctrs[i].ID()] = rawInputs[i] + } + } reports := make([]*entities.RestartReport, 0, len(ctrs)) - for _, con := range ctrs { - timeout := con.StopTimeout() + for _, c := range ctrs { + timeout := c.StopTimeout() if options.Timeout != nil { timeout = *options.Timeout } reports = append(reports, &entities.RestartReport{ - Id: con.ID(), - Err: con.RestartWithTimeout(ctx, timeout), + Id: c.ID(), + Err: c.RestartWithTimeout(ctx, timeout), + RawInput: idToRawInput[c.ID()], }) } return reports, nil @@ -381,7 +401,16 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, } names = tmpNames - ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod) + ctrs, rawInputs, err := getContainersAndInputByContext(options.All, options.Latest, names, options.Filters, ic.Libpod) + if err != nil && !(options.Ignore && errors.Is(err, define.ErrNoSuchCtr)) { + return nil, err + } + idToRawInput := map[string]string{} + if len(rawInputs) == len(ctrs) { + for i := range ctrs { + idToRawInput[ctrs[i].ID()] = rawInputs[i] + } + } if err != nil && !(options.Ignore && errors.Is(err, define.ErrNoSuchCtr)) { // Failed to get containers. If force is specified, get the containers ID // and evict them @@ -391,7 +420,10 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, for _, ctr := range names { logrus.Debugf("Evicting container %q", ctr) - report := reports.RmReport{Id: ctr} + report := reports.RmReport{ + Id: ctr, + RawInput: idToRawInput[ctr], + } _, err := ic.Libpod.EvictContainer(ctx, ctr, options.Volumes) if err != nil { if options.Ignore && errors.Is(err, define.ErrNoSuchCtr) { @@ -461,6 +493,7 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, report := new(reports.RmReport) report.Id = ctr.ID() report.Err = err + report.RawInput = idToRawInput[ctr.ID()] rmReports = append(rmReports, report) } return rmReports, nil @@ -598,8 +631,9 @@ func (ic *ContainerEngine) ContainerExport(ctx context.Context, nameOrID string, func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds []string, options entities.CheckpointOptions) ([]*entities.CheckpointReport, error) { var ( - err error - cons []*libpod.Container + ctrs []*libpod.Container + rawInputs []string + err error ) checkOpts := libpod.ContainerCheckpointOptions{ Keep: options.Keep, @@ -616,24 +650,34 @@ func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds [ CreateImage: options.CreateImage, } + idToRawInput := map[string]string{} if options.All { running := func(c *libpod.Container) bool { state, _ := c.State() return state == define.ContainerStateRunning } - cons, err = ic.Libpod.GetContainers(running) + ctrs, err = ic.Libpod.GetContainers(running) + if err != nil { + return nil, err + } } else { - cons, err = getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod) - } - if err != nil { - return nil, err + ctrs, rawInputs, err = getContainersAndInputByContext(false, options.Latest, namesOrIds, nil, ic.Libpod) + if err != nil { + return nil, err + } + if len(rawInputs) == len(ctrs) { + for i := range ctrs { + idToRawInput[ctrs[i].ID()] = rawInputs[i] + } + } } - reports := make([]*entities.CheckpointReport, 0, len(cons)) - for _, con := range cons { - criuStatistics, runtimeCheckpointDuration, err := con.Checkpoint(ctx, checkOpts) + reports := make([]*entities.CheckpointReport, 0, len(ctrs)) + for _, c := range ctrs { + criuStatistics, runtimeCheckpointDuration, err := c.Checkpoint(ctx, checkOpts) reports = append(reports, &entities.CheckpointReport{ Err: err, - Id: con.ID(), + Id: c.ID(), + RawInput: idToRawInput[c.ID()], RuntimeDuration: runtimeCheckpointDuration, CRIUStatistics: criuStatistics, }) @@ -643,7 +687,7 @@ func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds [ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []string, options entities.RestoreOptions) ([]*entities.RestoreReport, error) { var ( - containers []*libpod.Container + ctrs []*libpod.Container checkpointImageImportErrors []error err error ) @@ -670,19 +714,21 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st }, } + idToRawInput := map[string]string{} switch { case options.Import != "": - containers, err = checkpoint.CRImportCheckpointTar(ctx, ic.Libpod, options) + ctrs, err = checkpoint.CRImportCheckpointTar(ctx, ic.Libpod, options) case options.All: - containers, err = ic.Libpod.GetContainers(filterFuncs...) + ctrs, err = ic.Libpod.GetContainers(filterFuncs...) case options.Latest: - containers, err = getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod) + ctrs, err = getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod) default: for _, nameOrID := range namesOrIds { logrus.Debugf("look up container: %q", nameOrID) - ctr, err := ic.Libpod.LookupContainer(nameOrID) + c, err := ic.Libpod.LookupContainer(nameOrID) if err == nil { - containers = append(containers, ctr) + ctrs = append(ctrs, c) + idToRawInput[c.ID()] = nameOrID } else { // If container was not found, check if this is a checkpoint image logrus.Debugf("look up image: %q", nameOrID) @@ -700,7 +746,7 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st if err != nil { return nil, err } - importedContainers, err := checkpoint.CRImportCheckpoint(ctx, ic.Libpod, options, mountPoint) + importedCtrs, err := checkpoint.CRImportCheckpoint(ctx, ic.Libpod, options, mountPoint) if err != nil { // CRImportCheckpoint is expected to import exactly one container from checkpoint image checkpointImageImportErrors = append( @@ -708,7 +754,7 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st fmt.Errorf("unable to import checkpoint from image: %q: %v", nameOrID, err), ) } else { - containers = append(containers, importedContainers[0]) + ctrs = append(ctrs, importedCtrs[0]) } } } @@ -717,12 +763,13 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st return nil, err } - reports := make([]*entities.RestoreReport, 0, len(containers)) - for _, con := range containers { - criuStatistics, runtimeRestoreDuration, err := con.Restore(ctx, restoreOptions) + reports := make([]*entities.RestoreReport, 0, len(ctrs)) + for _, c := range ctrs { + criuStatistics, runtimeRestoreDuration, err := c.Restore(ctx, restoreOptions) reports = append(reports, &entities.RestoreReport{ Err: err, - Id: con.ID(), + Id: c.ID(), + RawInput: idToRawInput[c.ID()], RuntimeDuration: runtimeRestoreDuration, CRIUStatistics: criuStatistics, }) @@ -774,7 +821,7 @@ func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrID string, // If the container is in a pod, also set to recursively start dependencies err = terminal.StartAttachCtr(ctx, ctr, options.Stdout, options.Stderr, options.Stdin, options.DetachKeys, options.SigProxy, false) if err != nil && !errors.Is(err, define.ErrDetach) { - return fmt.Errorf("error attaching to container %s: %w", ctr.ID(), err) + return fmt.Errorf("attaching to container %s: %w", ctr.ID(), err) } os.Stdout.WriteString("\n") return nil @@ -796,12 +843,12 @@ func makeExecConfig(options entities.ExecOptions, rt *libpod.Runtime) (*libpod.E storageConfig := rt.StorageConfig() runtimeConfig, err := rt.GetConfig() if err != nil { - return nil, fmt.Errorf("error retrieving Libpod configuration to build exec exit command: %w", err) + return nil, fmt.Errorf("retrieving Libpod configuration to build exec exit command: %w", err) } // TODO: Add some ability to toggle syslog exitCommandArgs, err := specgenutil.CreateExitCommandArgs(storageConfig, runtimeConfig, logrus.IsLevelEnabled(logrus.DebugLevel), false, true) if err != nil { - return nil, fmt.Errorf("error constructing exit command for exec session: %w", err) + return nil, fmt.Errorf("constructing exit command for exec session: %w", err) } execConfig.ExitCommand = exitCommandArgs @@ -810,7 +857,7 @@ func makeExecConfig(options entities.ExecOptions, rt *libpod.Runtime) (*libpod.E func checkExecPreserveFDs(options entities.ExecOptions) error { if options.PreserveFDs > 0 { - entries, err := ioutil.ReadDir("/proc/self/fd") + entries, err := os.ReadDir("/proc/self/fd") if err != nil { return err } @@ -886,48 +933,19 @@ func (ic *ContainerEngine) ContainerExecDetached(ctx context.Context, nameOrID s func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []string, options entities.ContainerStartOptions) ([]*entities.ContainerStartReport, error) { reports := []*entities.ContainerStartReport{} var exitCode = define.ExecErrorCodeGeneric - containersNamesOrIds := namesOrIds - all := options.All - if len(options.Filters) > 0 { - all = false - filterFuncs := make([]libpod.ContainerFilter, 0, len(options.Filters)) - if len(options.Filters) > 0 { - for k, v := range options.Filters { - generatedFunc, err := dfilters.GenerateContainerFilterFuncs(k, v, ic.Libpod) - if err != nil { - return nil, err - } - filterFuncs = append(filterFuncs, generatedFunc) - } - } - candidates, err := ic.Libpod.GetContainers(filterFuncs...) - if err != nil { - return nil, err - } - containersNamesOrIds = []string{} - for _, candidate := range candidates { - if options.All { - containersNamesOrIds = append(containersNamesOrIds, candidate.ID()) - continue - } - for _, nameOrID := range namesOrIds { - if nameOrID == candidate.ID() || nameOrID == candidate.Name() { - containersNamesOrIds = append(containersNamesOrIds, nameOrID) - } - } - } - } - ctrs, rawInputs, err := getContainersAndInputByContext(all, options.Latest, containersNamesOrIds, options.Filters, ic.Libpod) + ctrs, rawInputs, err := getContainersAndInputByContext(options.All, options.Latest, namesOrIds, options.Filters, ic.Libpod) if err != nil { return nil, err } + idToRawInput := map[string]string{} + if len(rawInputs) == len(ctrs) { + for i := range ctrs { + idToRawInput[ctrs[i].ID()] = rawInputs[i] + } + } // There can only be one container if attach was used for i := range ctrs { ctr := ctrs[i] - rawInput := ctr.ID() - if !options.All { - rawInput = rawInputs[i] - } ctrState, err := ctr.State() if err != nil { return nil, err @@ -941,7 +959,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri // Exit cleanly immediately reports = append(reports, &entities.ContainerStartReport{ Id: ctr.ID(), - RawInput: rawInput, + RawInput: idToRawInput[ctr.ID()], Err: nil, ExitCode: 0, }) @@ -952,7 +970,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri logrus.Debugf("Deadlock error: %v", err) reports = append(reports, &entities.ContainerStartReport{ Id: ctr.ID(), - RawInput: rawInput, + RawInput: idToRawInput[ctr.ID()], Err: err, ExitCode: define.ExitCode(err), }) @@ -962,7 +980,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri if ctrRunning { reports = append(reports, &entities.ContainerStartReport{ Id: ctr.ID(), - RawInput: rawInput, + RawInput: idToRawInput[ctr.ID()], Err: nil, ExitCode: 0, }) @@ -972,7 +990,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri if err != nil { reports = append(reports, &entities.ContainerStartReport{ Id: ctr.ID(), - RawInput: rawInput, + RawInput: idToRawInput[ctr.ID()], Err: err, ExitCode: exitCode, }) @@ -987,7 +1005,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri exitCode = ic.GetContainerExitCode(ctx, ctr) reports = append(reports, &entities.ContainerStartReport{ Id: ctr.ID(), - RawInput: rawInput, + RawInput: idToRawInput[ctr.ID()], Err: err, ExitCode: exitCode, }) @@ -1000,7 +1018,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri // If the container is in a pod, also set to recursively start dependencies report := &entities.ContainerStartReport{ Id: ctr.ID(), - RawInput: rawInput, + RawInput: idToRawInput[ctr.ID()], ExitCode: 125, } if err := ctr.Start(ctx, true); err != nil { @@ -1211,14 +1229,20 @@ func (ic *ContainerEngine) ContainerLogs(ctx context.Context, containers []strin } func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []string, options entities.ContainerCleanupOptions) ([]*entities.ContainerCleanupReport, error) { - reports := []*entities.ContainerCleanupReport{} - ctrs, err := getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod) + ctrs, rawInputs, err := getContainersAndInputByContext(options.All, options.Latest, namesOrIds, nil, ic.Libpod) if err != nil { return nil, err } + idToRawInput := map[string]string{} + if len(rawInputs) == len(ctrs) { + for i := range ctrs { + idToRawInput[ctrs[i].ID()] = rawInputs[i] + } + } + reports := []*entities.ContainerCleanupReport{} for _, ctr := range ctrs { var err error - report := entities.ContainerCleanupReport{Id: ctr.ID()} + report := entities.ContainerCleanupReport{Id: ctr.ID(), RawInput: idToRawInput[ctr.ID()]} if options.Exec != "" { if options.Remove { @@ -1259,13 +1283,19 @@ func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []st } func (ic *ContainerEngine) ContainerInit(ctx context.Context, namesOrIds []string, options entities.ContainerInitOptions) ([]*entities.ContainerInitReport, error) { - ctrs, err := getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod) + ctrs, rawInputs, err := getContainersAndInputByContext(options.All, options.Latest, namesOrIds, nil, ic.Libpod) if err != nil { return nil, err } + idToRawInput := map[string]string{} + if len(rawInputs) == len(ctrs) { + for i := range ctrs { + idToRawInput[ctrs[i].ID()] = rawInputs[i] + } + } reports := make([]*entities.ContainerInitReport, 0, len(ctrs)) for _, ctr := range ctrs { - report := entities.ContainerInitReport{Id: ctr.ID()} + report := entities.ContainerInitReport{Id: ctr.ID(), RawInput: idToRawInput[ctr.ID()]} err := ctr.Init(ctx, ctr.PodID() != "") // If we're initializing all containers, ignore invalid state errors @@ -1418,7 +1448,7 @@ func (ic *ContainerEngine) ContainerUnmount(ctx context.Context, nameOrIDs []str logrus.Debugf("Error umounting container %s, storage.ErrLayerNotMounted", ctr.ID()) continue } - report.Err = fmt.Errorf("error unmounting container %s: %w", ctr.ID(), err) + report.Err = fmt.Errorf("unmounting container %s: %w", ctr.ID(), err) } reports = append(reports, &report) } @@ -1656,31 +1686,7 @@ func (ic *ContainerEngine) ContainerClone(ctx context.Context, ctrCloneOpts enti if err == nil { n += "-clone" } - switch { - case strings.Contains(n, "-clone"): - ind := strings.Index(n, "-clone") + 6 - num, err := strconv.Atoi(n[ind:]) - if num == 0 && err != nil { // clone1 is hard to get with this logic, just check for it here. - _, err = ic.Libpod.LookupContainer(n + "1") - if err != nil { - spec.Name = n + "1" - break - } - } else { - n = n[0:ind] - } - err = nil - count := num - for err == nil { - count++ - tempN := n + strconv.Itoa(count) - _, err = ic.Libpod.LookupContainer(tempN) - } - n += strconv.Itoa(count) - spec.Name = n - default: - spec.Name = c.Name() + "-clone" - } + spec.Name = generate.CheckName(ic.Libpod, n, true) } rtSpec, spec, opts, err := generate.MakeContainer(context.Background(), ic.Libpod, spec, true, c) @@ -1708,3 +1714,27 @@ func (ic *ContainerEngine) ContainerClone(ctx context.Context, ctrCloneOpts enti return &entities.ContainerCreateReport{Id: ctr.ID()}, nil } + +// ContainerUpdate finds and updates the given container's cgroup config with the specified options +func (ic *ContainerEngine) ContainerUpdate(ctx context.Context, updateOptions *entities.ContainerUpdateOptions) (string, error) { + err := specgen.WeightDevices(updateOptions.Specgen) + if err != nil { + return "", err + } + err = specgen.FinishThrottleDevices(updateOptions.Specgen) + if err != nil { + return "", err + } + ctrs, err := getContainersByContext(false, false, []string{updateOptions.NameOrID}, ic.Libpod) + if err != nil { + return "", err + } + if len(ctrs) != 1 { + return "", fmt.Errorf("container not found") + } + + if err = ctrs[0].Update(updateOptions.Specgen.ResourceLimits); err != nil { + return "", err + } + return ctrs[0].ID(), nil +} diff --git a/pkg/domain/infra/abi/generate.go b/pkg/domain/infra/abi/generate.go index 31885ce54..f588f591a 100644 --- a/pkg/domain/infra/abi/generate.go +++ b/pkg/domain/infra/abi/generate.go @@ -3,6 +3,7 @@ package abi import ( "bytes" "context" + "encoding/json" "fmt" "strings" @@ -10,6 +11,8 @@ import ( "github.com/containers/podman/v4/libpod/define" "github.com/containers/podman/v4/pkg/domain/entities" k8sAPI "github.com/containers/podman/v4/pkg/k8s.io/api/core/v1" + "github.com/containers/podman/v4/pkg/specgen" + generateUtils "github.com/containers/podman/v4/pkg/specgen/generate" "github.com/containers/podman/v4/pkg/systemd/generate" "github.com/ghodss/yaml" ) @@ -41,6 +44,63 @@ func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string, return &entities.GenerateSystemdReport{Units: units}, nil } +func (ic *ContainerEngine) GenerateSpec(ctx context.Context, opts *entities.GenerateSpecOptions) (*entities.GenerateSpecReport, error) { + var spec *specgen.SpecGenerator + var pspec *specgen.PodSpecGenerator + var err error + if _, err := ic.Libpod.LookupContainer(opts.ID); err == nil { + spec = &specgen.SpecGenerator{} + _, _, err = generateUtils.ConfigToSpec(ic.Libpod, spec, opts.ID) + if err != nil { + return nil, err + } + } else if p, err := ic.Libpod.LookupPod(opts.ID); err == nil { + pspec = &specgen.PodSpecGenerator{} + pspec.Name = p.Name() + _, err := generateUtils.PodConfigToSpec(ic.Libpod, pspec, &entities.ContainerCreateOptions{}, opts.ID) + if err != nil { + return nil, err + } + } + + if pspec == nil && spec == nil { + return nil, fmt.Errorf("could not find a pod or container with the id %s", opts.ID) + } + + // rename if we are looking to consume the output and make a new entity + if opts.Name { + if spec != nil { + spec.Name = generateUtils.CheckName(ic.Libpod, spec.Name, true) + } else { + pspec.Name = generateUtils.CheckName(ic.Libpod, pspec.Name, false) + } + } + + j := []byte{} + if spec != nil { + j, err = json.MarshalIndent(spec, "", " ") + if err != nil { + return nil, err + } + } else if pspec != nil { + j, err = json.MarshalIndent(pspec, "", " ") + if err != nil { + return nil, err + } + } + + // compact output + if opts.Compact { + compacted := &bytes.Buffer{} + err := json.Compact(compacted, j) + if err != nil { + return nil, err + } + return &entities.GenerateSpecReport{Data: compacted.Bytes()}, nil + } + return &entities.GenerateSpecReport{Data: j}, nil // regular output +} + func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string, options entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) { var ( pods []*libpod.Pod diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go index ff42b0367..6934de60e 100644 --- a/pkg/domain/infra/abi/images.go +++ b/pkg/domain/infra/abi/images.go @@ -18,6 +18,7 @@ import ( "github.com/containers/common/libimage" "github.com/containers/common/pkg/config" + "github.com/containers/common/pkg/ssh" "github.com/containers/image/v5/docker" "github.com/containers/image/v5/docker/reference" "github.com/containers/image/v5/manifest" @@ -236,8 +237,9 @@ func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entiti pullOptions.Variant = options.Variant pullOptions.SignaturePolicyPath = options.SignaturePolicy pullOptions.InsecureSkipTLSVerify = options.SkipTLSVerify + pullOptions.Writer = options.Writer - if !options.Quiet { + if !options.Quiet && pullOptions.Writer == nil { pullOptions.Writer = os.Stderr } @@ -304,6 +306,9 @@ func (ir *ImageEngine) Push(ctx context.Context, source string, destination stri pushOptions.ManifestMIMEType = manifestType pushOptions.RemoveSignatures = options.RemoveSignatures pushOptions.SignBy = options.SignBy + pushOptions.SignPassphrase = options.SignPassphrase + pushOptions.SignBySigstorePrivateKeyFile = options.SignBySigstorePrivateKeyFile + pushOptions.SignSigstorePrivateKeyPassphrase = options.SignSigstorePrivateKeyPassphrase pushOptions.InsecureSkipTLSVerify = options.SkipTLSVerify pushOptions.Writer = options.Writer @@ -562,6 +567,7 @@ func (ir *ImageEngine) Remove(ctx context.Context, images []string, opts entitie libimageOptions.Force = opts.Force libimageOptions.Ignore = opts.Ignore libimageOptions.LookupManifest = opts.LookupManifest + libimageOptions.NoPrune = opts.NoPrune if !opts.All { libimageOptions.Filters = append(libimageOptions.Filters, "intermediate=false") } @@ -578,7 +584,7 @@ func (ir *ImageEngine) Remove(ctx context.Context, images []string, opts entitie rmErrors = libimageErrors - return + return report, rmErrors } // Shutdown Libpod engine @@ -591,7 +597,7 @@ func (ir *ImageEngine) Shutdown(_ context.Context) { func (ir *ImageEngine) Sign(ctx context.Context, names []string, options entities.SignOptions) (*entities.SignReport, error) { mech, err := signature.NewGPGSigningMechanism() if err != nil { - return nil, fmt.Errorf("error initializing GPG: %w", err) + return nil, fmt.Errorf("initializing GPG: %w", err) } defer mech.Close() if err := mech.SupportsSigning(); err != nil { @@ -605,11 +611,11 @@ func (ir *ImageEngine) Sign(ctx context.Context, names []string, options entitie err = func() error { srcRef, err := alltransports.ParseImageName(signimage) if err != nil { - return fmt.Errorf("error parsing image name: %w", err) + return fmt.Errorf("parsing image name: %w", err) } rawSource, err := srcRef.NewImageSource(ctx, sc) if err != nil { - return fmt.Errorf("error getting image source: %w", err) + return fmt.Errorf("getting image source: %w", err) } defer func() { if err = rawSource.Close(); err != nil { @@ -618,7 +624,7 @@ func (ir *ImageEngine) Sign(ctx context.Context, names []string, options entitie }() topManifestBlob, manifestType, err := rawSource.GetManifest(ctx, nil) if err != nil { - return fmt.Errorf("error getting manifest blob: %w", err) + return fmt.Errorf("getting manifest blob: %w", err) } dockerReference := rawSource.Reference().DockerReference() if dockerReference == nil { @@ -652,7 +658,7 @@ func (ir *ImageEngine) Sign(ctx context.Context, names []string, options entitie } list, err := manifest.ListFromBlob(topManifestBlob, manifestType) if err != nil { - return fmt.Errorf("error parsing manifest list %q: %w", string(topManifestBlob), err) + return fmt.Errorf("parsing manifest list %q: %w", string(topManifestBlob), err) } instanceDigests := list.Instances() for _, instanceDigest := range instanceDigests { @@ -662,13 +668,13 @@ func (ir *ImageEngine) Sign(ctx context.Context, names []string, options entitie return err } if err = putSignature(man, mech, sigStoreDir, instanceDigest, dockerReference, options); err != nil { - return fmt.Errorf("error storing signature for %s, %v: %w", dockerReference.String(), instanceDigest, err) + return fmt.Errorf("storing signature for %s, %v: %w", dockerReference.String(), instanceDigest, err) } } return nil } if err = putSignature(topManifestBlob, mech, sigStoreDir, manifestDigest, dockerReference, options); err != nil { - return fmt.Errorf("error storing signature for %s, %v: %w", dockerReference.String(), manifestDigest, err) + return fmt.Errorf("storing signature for %s, %v: %w", dockerReference.String(), manifestDigest, err) } return nil }() @@ -679,8 +685,8 @@ func (ir *ImageEngine) Sign(ctx context.Context, names []string, options entitie return nil, nil } -func (ir *ImageEngine) Scp(ctx context.Context, src, dst string, parentFlags []string, quiet bool) error { - rep, source, dest, flags, err := domainUtils.ExecuteTransfer(src, dst, parentFlags, quiet) +func (ir *ImageEngine) Scp(ctx context.Context, src, dst string, parentFlags []string, quiet bool, sshMode ssh.EngineMode) error { + rep, source, dest, flags, err := domainUtils.ExecuteTransfer(src, dst, parentFlags, quiet, sshMode) if err != nil { return err } @@ -863,7 +869,7 @@ func execTransferPodman(execUser *user.User, command []string, needToTag bool) ( func getSigFilename(sigStoreDirPath string) (string, error) { sigFileSuffix := 1 - sigFiles, err := ioutil.ReadDir(sigStoreDirPath) + sigFiles, err := os.ReadDir(sigStoreDirPath) if err != nil { return "", err } diff --git a/pkg/domain/infra/abi/images_list.go b/pkg/domain/infra/abi/images_list.go index 96e99fbf0..4788ecef9 100644 --- a/pkg/domain/infra/abi/images_list.go +++ b/pkg/domain/infra/abi/images_list.go @@ -32,7 +32,7 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions) } isDangling, err := img.IsDangling(ctx) if err != nil { - return nil, fmt.Errorf("error checking if image %q is dangling: %w", img.ID(), err) + return nil, fmt.Errorf("checking if image %q is dangling: %w", img.ID(), err) } e := entities.ImageSummary{ @@ -49,18 +49,18 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions) } e.Labels, err = img.Labels(ctx) if err != nil { - return nil, fmt.Errorf("error retrieving label for image %q: you may need to remove the image to resolve the error: %w", img.ID(), err) + return nil, fmt.Errorf("retrieving label for image %q: you may need to remove the image to resolve the error: %w", img.ID(), err) } ctnrs, err := img.Containers() if err != nil { - return nil, fmt.Errorf("error retrieving containers for image %q: you may need to remove the image to resolve the error: %w", img.ID(), err) + return nil, fmt.Errorf("retrieving containers for image %q: you may need to remove the image to resolve the error: %w", img.ID(), err) } e.Containers = len(ctnrs) sz, err := img.Size() if err != nil { - return nil, fmt.Errorf("error retrieving size of image %q: you may need to remove the image to resolve the error: %w", img.ID(), err) + return nil, fmt.Errorf("retrieving size of image %q: you may need to remove the image to resolve the error: %w", img.ID(), err) } e.Size = sz // This is good enough for now, but has to be @@ -69,7 +69,7 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions) parent, err := img.Parent(ctx) if err != nil { - return nil, fmt.Errorf("error retrieving parent of image %q: you may need to remove the image to resolve the error: %w", img.ID(), err) + return nil, fmt.Errorf("retrieving parent of image %q: you may need to remove the image to resolve the error: %w", img.ID(), err) } if parent != nil { e.ParentId = parent.ID() diff --git a/pkg/domain/infra/abi/manifest.go b/pkg/domain/infra/abi/manifest.go index b135b05ba..ac3eedbe8 100644 --- a/pkg/domain/infra/abi/manifest.go +++ b/pkg/domain/infra/abi/manifest.go @@ -32,7 +32,15 @@ func (ir *ImageEngine) ManifestCreate(ctx context.Context, name string, images [ manifestList, err := ir.Libpod.LibimageRuntime().CreateManifestList(name) if err != nil { - return "", err + if errors.Is(err, storage.ErrDuplicateName) && opts.Amend { + amendList, amendErr := ir.Libpod.LibimageRuntime().LookupManifestList(name) + if amendErr != nil { + return "", err + } + manifestList = amendList + } else { + return "", err + } } addOptions := &libimage.ManifestListAddOptions{All: opts.All} @@ -87,7 +95,7 @@ func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte var b bytes.Buffer if err := json.Indent(&b, rawSchema2List, "", " "); err != nil { - return nil, fmt.Errorf("error rendering manifest %s for display: %w", name, err) + return nil, fmt.Errorf("rendering manifest %s for display: %w", name, err) } return b.Bytes(), nil } @@ -150,7 +158,7 @@ func (ir *ImageEngine) remoteManifestInspect(ctx context.Context, name string) ( logrus.Warnf("The manifest type %s is not a manifest list but a single image.", manType) schema2Manifest, err := manifest.Schema2FromManifest(result) if err != nil { - return nil, fmt.Errorf("error parsing manifest blob %q as a %q: %w", string(result), manType, err) + return nil, fmt.Errorf("parsing manifest blob %q as a %q: %w", string(result), manType, err) } if result, err = schema2Manifest.Serialize(); err != nil { return nil, err @@ -158,7 +166,7 @@ func (ir *ImageEngine) remoteManifestInspect(ctx context.Context, name string) ( default: listBlob, err := manifest.ListFromBlob(result, manType) if err != nil { - return nil, fmt.Errorf("error parsing manifest blob %q as a %q: %w", string(result), manType, err) + return nil, fmt.Errorf("parsing manifest blob %q as a %q: %w", string(result), manType, err) } list, err := listBlob.ConvertToMIMEType(manifest.DockerV2ListMediaType) if err != nil { @@ -170,7 +178,7 @@ func (ir *ImageEngine) remoteManifestInspect(ctx context.Context, name string) ( } if err = json.Indent(&b, result, "", " "); err != nil { - return nil, fmt.Errorf("error rendering manifest %s for display: %w", name, err) + return nil, fmt.Errorf("rendering manifest %s for display: %w", name, err) } return b.Bytes(), nil } @@ -293,7 +301,7 @@ func (ir *ImageEngine) ManifestRm(ctx context.Context, names []string) (report * func (ir *ImageEngine) ManifestPush(ctx context.Context, name, destination string, opts entities.ImagePushOptions) (string, error) { manifestList, err := ir.Libpod.LibimageRuntime().LookupManifestList(name) if err != nil { - return "", fmt.Errorf("error retrieving local image from image name %s: %w", name, err) + return "", fmt.Errorf("retrieving local image from image name %s: %w", name, err) } var manifestType string @@ -317,7 +325,11 @@ func (ir *ImageEngine) ManifestPush(ctx context.Context, name, destination strin pushOptions.ManifestMIMEType = manifestType pushOptions.RemoveSignatures = opts.RemoveSignatures pushOptions.SignBy = opts.SignBy + pushOptions.SignPassphrase = opts.SignPassphrase + pushOptions.SignBySigstorePrivateKeyFile = opts.SignBySigstorePrivateKeyFile + pushOptions.SignSigstorePrivateKeyPassphrase = opts.SignSigstorePrivateKeyPassphrase pushOptions.InsecureSkipTLSVerify = opts.SkipTLSVerify + pushOptions.Writer = opts.Writer compressionFormat := opts.CompressionFormat if compressionFormat == "" { @@ -338,7 +350,7 @@ func (ir *ImageEngine) ManifestPush(ctx context.Context, name, destination strin if opts.All { pushOptions.ImageListSelection = cp.CopyAllImages } - if !opts.Quiet { + if !opts.Quiet && pushOptions.Writer == nil { pushOptions.Writer = os.Stderr } @@ -350,7 +362,7 @@ func (ir *ImageEngine) ManifestPush(ctx context.Context, name, destination strin if opts.Rm { rmOpts := &libimage.RemoveImagesOptions{LookupManifest: true} if _, rmErrors := ir.Libpod.LibimageRuntime().RemoveImages(ctx, []string{manifestList.ID()}, rmOpts); len(rmErrors) > 0 { - return "", fmt.Errorf("error removing manifest after push: %w", rmErrors[0]) + return "", fmt.Errorf("removing manifest after push: %w", rmErrors[0]) } } diff --git a/pkg/domain/infra/abi/network.go b/pkg/domain/infra/abi/network.go index 2428abfe9..a29b6818f 100644 --- a/pkg/domain/infra/abi/network.go +++ b/pkg/domain/infra/abi/network.go @@ -61,7 +61,7 @@ func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []stri errs = append(errs, fmt.Errorf("network %s: %w", name, err)) continue } else { - return nil, nil, fmt.Errorf("error inspecting network %s: %w", name, err) + return nil, nil, fmt.Errorf("inspecting network %s: %w", name, err) } } networks = append(networks, net) diff --git a/pkg/domain/infra/abi/parse/parse.go b/pkg/domain/infra/abi/parse/parse.go index 19699589b..fb2876bb2 100644 --- a/pkg/domain/infra/abi/parse/parse.go +++ b/pkg/domain/infra/abi/parse/parse.go @@ -86,8 +86,11 @@ func VolumeOptions(opts map[string]string) ([]libpod.VolumeCreateOption, error) if err != nil { return nil, fmt.Errorf("cannot convert Timeout %s to an integer: %w", splitO[1], err) } + if intTimeout < 0 { + return nil, fmt.Errorf("volume timeout cannot be negative (got %d)", intTimeout) + } logrus.Debugf("Removing timeout from options and adding WithTimeout for Timeout %d", intTimeout) - libpodOptions = append(libpodOptions, libpod.WithVolumeDriverTimeout(intTimeout)) + libpodOptions = append(libpodOptions, libpod.WithVolumeDriverTimeout(uint(intTimeout))) default: finalVal = append(finalVal, o) } diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index 3f2fd5f92..d447b4d00 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -16,6 +16,7 @@ import ( "github.com/containers/common/libimage" nettypes "github.com/containers/common/libnetwork/types" "github.com/containers/common/pkg/config" + "github.com/containers/common/pkg/secrets" "github.com/containers/image/v5/types" "github.com/containers/podman/v4/libpod" "github.com/containers/podman/v4/libpod/define" @@ -27,13 +28,19 @@ import ( "github.com/containers/podman/v4/pkg/specgen/generate" "github.com/containers/podman/v4/pkg/specgen/generate/kube" "github.com/containers/podman/v4/pkg/specgenutil" + "github.com/containers/podman/v4/pkg/systemd/notifyproxy" "github.com/containers/podman/v4/pkg/util" + "github.com/coreos/go-systemd/v22/daemon" "github.com/ghodss/yaml" "github.com/opencontainers/go-digest" "github.com/sirupsen/logrus" yamlv3 "gopkg.in/yaml.v3" ) +// sdNotifyAnnotation allows for configuring service-global and +// container-specific sd-notify modes. +const sdNotifyAnnotation = "io.containers.sdnotify" + // createServiceContainer creates a container that can later on // be associated with the pods of a K8s yaml. It will be started along with // the first pod. @@ -73,7 +80,12 @@ func (ic *ContainerEngine) createServiceContainer(ctx context.Context, name stri return nil, fmt.Errorf("creating runtime spec for service container: %w", err) } opts = append(opts, libpod.WithIsService()) - opts = append(opts, libpod.WithSdNotifyMode(define.SdNotifyModeConmon)) + + // Set the sd-notify mode to "ignore". Podman is responsible for + // sending the notify messages when all containers are ready. + // The mode for individual containers or entire pods can be configured + // via the `sdNotifyAnnotation` annotation in the K8s YAML. + opts = append(opts, libpod.WithSdNotifyMode(define.SdNotifyModeIgnore)) // Create a new libpod container based on the spec. ctr, err := ic.Libpod.NewContainer(ctx, runtimeSpec, spec, false, opts...) @@ -96,6 +108,10 @@ func k8sName(content []byte, suffix string) string { } func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, options entities.PlayKubeOptions) (_ *entities.PlayKubeReport, finalErr error) { + if options.ServiceContainer && options.Start == types.OptionalBoolFalse { // Sanity check to be future proof + return nil, fmt.Errorf("running a service container requires starting the pod(s)") + } + report := &entities.PlayKubeReport{} validKinds := 0 @@ -121,6 +137,8 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, options var configMaps []v1.ConfigMap + ranContainers := false + var serviceContainer *libpod.Container // create pod on each document if it is a pod or deployment // any other kube kind will be skipped for _, document := range documentList { @@ -130,8 +148,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, options } // TODO: create constants for the various "kinds" of yaml files. - var serviceContainer *libpod.Container - if options.ServiceContainer && (kind == "Pod" || kind == "Deployment") { + if options.ServiceContainer && serviceContainer == nil && (kind == "Pod" || kind == "Deployment") { ctr, err := ic.createServiceContainer(ctx, k8sName(content, "service"), options) if err != nil { return nil, err @@ -178,6 +195,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, options report.Pods = append(report.Pods, r.Pods...) validKinds++ + ranContainers = true case "Deployment": var deploymentYAML v1apps.Deployment @@ -192,6 +210,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, options report.Pods = append(report.Pods, r.Pods...) validKinds++ + ranContainers = true case "PersistentVolumeClaim": var pvcYAML v1.PersistentVolumeClaim @@ -239,6 +258,20 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, options return nil, fmt.Errorf("YAML document does not contain any supported kube kind") } + if options.ServiceContainer && ranContainers { + // We can consider the service to be up and running now. + // Send the sd-notify messages pointing systemd to the + // service container. + data, err := serviceContainer.Inspect(false) + if err != nil { + return nil, err + } + message := fmt.Sprintf("MAINPID=%d\n%s", data.State.ConmonPid, daemon.SdNotifyReady) + if err := notifyproxy.SendMessage("", message); err != nil { + return nil, err + } + } + return report, nil } @@ -266,7 +299,7 @@ func (ic *ContainerEngine) playKubeDeployment(ctx context.Context, deploymentYAM podName := fmt.Sprintf("%s-pod-%d", deploymentName, i) podReport, err := ic.playKubePod(ctx, podName, &podSpec, options, ipIndex, deploymentYAML.Annotations, configMaps, serviceContainer) if err != nil { - return nil, fmt.Errorf("error encountered while bringing up pod %s: %w", podName, err) + return nil, fmt.Errorf("encountered while bringing up pod %s: %w", podName, err) } report.Pods = append(report.Pods, podReport.Pods...) } @@ -280,6 +313,11 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY report entities.PlayKubeReport ) + mainSdNotifyMode, err := getSdNotifyMode(annotations, "") + if err != nil { + return nil, err + } + // Create the secret manager before hand secretsManager, err := ic.Libpod.SecretsManager() if err != nil { @@ -318,6 +356,11 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY if options.Userns == "" { options.Userns = "host" + if podYAML.Spec.HostUsers != nil && !*podYAML.Spec.HostUsers { + options.Userns = "auto" + } + } else if podYAML.Spec.HostUsers != nil { + logrus.Info("overriding the user namespace mode in the pod spec") } // Validate the userns modes supported. @@ -399,7 +442,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY } // Go through the volumes and create a podman volume for all volumes that have been - // defined by a configmap + // defined by a configmap or secret for _, v := range volumes { if (v.Type == kube.KubeVolumeTypeConfigMap || v.Type == kube.KubeVolumeTypeSecret) && !v.Optional { vol, err := ic.Libpod.NewVolume(ctx, libpod.WithVolumeName(v.Source)) @@ -562,6 +605,9 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY initContainers = append(initContainers, ctr) } + + var sdNotifyProxies []*notifyproxy.NotifyProxy // containers' sd-notify proxies + for _, container := range podYAML.Spec.Containers { // Error out if the same name is used for more than one container if _, ok := ctrNames[container.Name]; ok { @@ -606,11 +652,39 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY if err != nil { return nil, err } - opts = append(opts, libpod.WithSdNotifyMode(define.SdNotifyModeIgnore)) + + sdNotifyMode := mainSdNotifyMode + ctrNotifyMode, err := getSdNotifyMode(annotations, container.Name) + if err != nil { + return nil, err + } + if ctrNotifyMode != "" { + sdNotifyMode = ctrNotifyMode + } + if sdNotifyMode == "" { // Default to "ignore" + sdNotifyMode = define.SdNotifyModeIgnore + } + + opts = append(opts, libpod.WithSdNotifyMode(sdNotifyMode)) + + var proxy *notifyproxy.NotifyProxy + // Create a notify proxy for the container. + if sdNotifyMode != "" && sdNotifyMode != define.SdNotifyModeIgnore { + proxy, err = notifyproxy.New("") + if err != nil { + return nil, err + } + sdNotifyProxies = append(sdNotifyProxies, proxy) + opts = append(opts, libpod.WithSdNotifySocket(proxy.SocketPath())) + } + ctr, err := generate.ExecuteCreate(ctx, ic.Libpod, rtSpec, spec, false, opts...) if err != nil { return nil, err } + if proxy != nil { + proxy.AddContainer(ctr) + } containers = append(containers, ctr) } @@ -621,9 +695,16 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY return nil, err } for id, err := range podStartErrors { - playKubePod.ContainerErrors = append(playKubePod.ContainerErrors, fmt.Errorf("error starting container %s: %w", id, err).Error()) + playKubePod.ContainerErrors = append(playKubePod.ContainerErrors, fmt.Errorf("starting container %s: %w", id, err).Error()) fmt.Println(playKubePod.ContainerErrors) } + + // Wait for each proxy to receive a READY message. + for _, proxy := range sdNotifyProxies { + if err := proxy.WaitAndClose(); err != nil { + return nil, err + } + } } playKubePod.ID = pod.ID() @@ -703,21 +784,26 @@ func (ic *ContainerEngine) getImageAndLabelInfo(ctx context.Context, cwd string, } // Handle kube annotations - for k, v := range annotations { - switch k { - // Auto update annotation without container name will apply to - // all containers within the pod - case autoupdate.Label, autoupdate.AuthfileLabel: - labels[k] = v - // Auto update annotation with container name will apply only - // to the specified container - case fmt.Sprintf("%s/%s", autoupdate.Label, container.Name), - fmt.Sprintf("%s/%s", autoupdate.AuthfileLabel, container.Name): - prefixAndCtr := strings.Split(k, "/") - labels[prefixAndCtr[0]] = v + setLabel := func(label string) { + var result string + ctrSpecific := fmt.Sprintf("%s/%s", label, container.Name) + for k, v := range annotations { + switch k { + case label: + result = v + case ctrSpecific: + labels[label] = v + return + } + } + if result != "" { + labels[label] = result } } + setLabel(autoupdate.Label) + setLabel(autoupdate.AuthfileLabel) + return pulledImage, labels, nil } @@ -1025,7 +1111,13 @@ func (ic *ContainerEngine) playKubeSecret(secret *v1.Secret) (*entities.SecretCr if secret.Immutable != nil && *secret.Immutable { meta["immutable"] = "true" } - secretID, err := secretsManager.Store(secret.Name, data, "file", opts, meta) + + storeOpts := secrets.StoreOptions{ + DriverOpts: opts, + Metadata: meta, + } + + secretID, err := secretsManager.Store(secret.Name, data, "file", storeOpts) if err != nil { return nil, err } diff --git a/pkg/domain/infra/abi/play_utils.go b/pkg/domain/infra/abi/play_utils.go new file mode 100644 index 000000000..482a158e6 --- /dev/null +++ b/pkg/domain/infra/abi/play_utils.go @@ -0,0 +1,16 @@ +package abi + +import "github.com/containers/podman/v4/libpod/define" + +// getSdNotifyMode returns the `sdNotifyAnnotation/$name` for the specified +// name. If name is empty, it'll only look for `sdNotifyAnnotation`. +func getSdNotifyMode(annotations map[string]string, name string) (string, error) { + var mode string + switch len(name) { + case 0: + mode = annotations[sdNotifyAnnotation] + default: + mode = annotations[sdNotifyAnnotation+"/"+name] + } + return mode, define.ValidateSdNotifyMode(mode) +} diff --git a/pkg/domain/infra/abi/play_utils_test.go b/pkg/domain/infra/abi/play_utils_test.go new file mode 100644 index 000000000..80a9fe543 --- /dev/null +++ b/pkg/domain/infra/abi/play_utils_test.go @@ -0,0 +1,38 @@ +package abi + +import ( + "testing" + + "github.com/containers/podman/v4/libpod/define" + "github.com/stretchr/testify/require" +) + +func TestGetSdNotifyMode(t *testing.T) { + tests := []struct { + key, value, name, result string + mustError bool + }{ + {sdNotifyAnnotation, define.SdNotifyModeConmon, "", define.SdNotifyModeConmon, false}, + {sdNotifyAnnotation + "/container-a", define.SdNotifyModeContainer, "container-a", define.SdNotifyModeContainer, false}, + {sdNotifyAnnotation + "/container-b", define.SdNotifyModeIgnore, "container-b", define.SdNotifyModeIgnore, false}, + {sdNotifyAnnotation + "/container-c", "", "container-c", "", false}, + {sdNotifyAnnotation + "-/wrong-key", "xxx", "wrong-key", "", false}, + {sdNotifyAnnotation + "/container-error", "invalid", "container-error", "", true}, + } + + annotations := make(map[string]string) + // Populate the annotations + for _, test := range tests { + annotations[test.key] = test.value + } + // Run the tests + for _, test := range tests { + result, err := getSdNotifyMode(annotations, test.name) + if test.mustError { + require.Error(t, err, "%v", test) + continue + } + require.NoError(t, err, "%v", test) + require.Equal(t, test.result, result, "%v", test) + } +} diff --git a/pkg/domain/infra/abi/pods.go b/pkg/domain/infra/abi/pods.go index 03c8082c4..45a47b46e 100644 --- a/pkg/domain/infra/abi/pods.go +++ b/pkg/domain/infra/abi/pods.go @@ -77,7 +77,7 @@ func (ic *ContainerEngine) PodKill(ctx context.Context, namesOrIds []string, opt } if len(conErrs) > 0 { for id, err := range conErrs { - report.Errs = append(report.Errs, fmt.Errorf("error killing container %s: %w", id, err)) + report.Errs = append(report.Errs, fmt.Errorf("killing container %s: %w", id, err)) } reports = append(reports, &report) continue @@ -143,7 +143,7 @@ func (ic *ContainerEngine) PodPause(ctx context.Context, namesOrIds []string, op } if len(errs) > 0 { for id, v := range errs { - report.Errs = append(report.Errs, fmt.Errorf("error pausing container %s: %w", id, v)) + report.Errs = append(report.Errs, fmt.Errorf("pausing container %s: %w", id, v)) } reports = append(reports, &report) continue @@ -177,7 +177,7 @@ func (ic *ContainerEngine) PodUnpause(ctx context.Context, namesOrIds []string, } if len(errs) > 0 { for id, v := range errs { - report.Errs = append(report.Errs, fmt.Errorf("error unpausing container %s: %w", id, v)) + report.Errs = append(report.Errs, fmt.Errorf("unpausing container %s: %w", id, v)) } reports = append(reports, &report) continue @@ -203,7 +203,7 @@ func (ic *ContainerEngine) PodStop(ctx context.Context, namesOrIds []string, opt } if len(errs) > 0 { for id, v := range errs { - report.Errs = append(report.Errs, fmt.Errorf("error stopping container %s: %w", id, v)) + report.Errs = append(report.Errs, fmt.Errorf("stopping container %s: %w", id, v)) } reports = append(reports, &report) continue @@ -229,7 +229,7 @@ func (ic *ContainerEngine) PodRestart(ctx context.Context, namesOrIds []string, } if len(errs) > 0 { for id, v := range errs { - report.Errs = append(report.Errs, fmt.Errorf("error restarting container %s: %w", id, v)) + report.Errs = append(report.Errs, fmt.Errorf("restarting container %s: %w", id, v)) } reports = append(reports, &report) continue @@ -256,7 +256,7 @@ func (ic *ContainerEngine) PodStart(ctx context.Context, namesOrIds []string, op } if len(errs) > 0 { for id, v := range errs { - report.Errs = append(report.Errs, fmt.Errorf("error starting container %s: %w", id, v)) + report.Errs = append(report.Errs, fmt.Errorf("starting container %s: %w", id, v)) } reports = append(reports, &report) continue @@ -505,23 +505,49 @@ func (ic *ContainerEngine) PodPs(ctx context.Context, options entities.PodPSOpti return reports, nil } -func (ic *ContainerEngine) PodInspect(ctx context.Context, options entities.PodInspectOptions) (*entities.PodInspectReport, error) { - var ( - pod *libpod.Pod - err error - ) - // Look up the pod. +func (ic *ContainerEngine) PodInspect(ctx context.Context, nameOrIDs []string, options entities.InspectOptions) ([]*entities.PodInspectReport, []error, error) { if options.Latest { - pod, err = ic.Libpod.GetLatestPod() - } else { - pod, err = ic.Libpod.LookupPod(options.NameOrID) - } - if err != nil { - return nil, fmt.Errorf("unable to look up requested container: %w", err) + pod, err := ic.Libpod.GetLatestPod() + if err != nil { + return nil, nil, err + } + inspect, err := pod.Inspect() + if err != nil { + return nil, nil, err + } + + return []*entities.PodInspectReport{ + { + InspectPodData: inspect, + }, + }, nil, nil } - inspect, err := pod.Inspect() - if err != nil { - return nil, err + + var errs []error + podReport := make([]*entities.PodInspectReport, 0, len(nameOrIDs)) + for _, name := range nameOrIDs { + pod, err := ic.Libpod.LookupPod(name) + if err != nil { + // ErrNoSuchPod is non-fatal, other errors will be + // treated as fatal. + if errors.Is(err, define.ErrNoSuchPod) { + errs = append(errs, fmt.Errorf("no such pod %s", name)) + continue + } + return nil, nil, err + } + + inspect, err := pod.Inspect() + if err != nil { + // ErrNoSuchPod is non-fatal, other errors will be + // treated as fatal. + if errors.Is(err, define.ErrNoSuchPod) { + errs = append(errs, fmt.Errorf("no such pod %s", name)) + continue + } + return nil, nil, err + } + podReport = append(podReport, &entities.PodInspectReport{InspectPodData: inspect}) } - return &entities.PodInspectReport{InspectPodData: inspect}, nil + return podReport, errs, nil } diff --git a/pkg/domain/infra/abi/secrets.go b/pkg/domain/infra/abi/secrets.go index e82fa4fdd..47159d65a 100644 --- a/pkg/domain/infra/abi/secrets.go +++ b/pkg/domain/infra/abi/secrets.go @@ -8,6 +8,7 @@ import ( "path/filepath" "strings" + "github.com/containers/common/pkg/secrets" "github.com/containers/podman/v4/pkg/domain/entities" "github.com/containers/podman/v4/pkg/domain/utils" ) @@ -42,10 +43,15 @@ func (ic *ContainerEngine) SecretCreate(ctx context.Context, name string, reader } } - secretID, err := manager.Store(name, data, options.Driver, options.DriverOpts, nil) + storeOpts := secrets.StoreOptions{ + DriverOpts: options.DriverOpts, + } + + secretID, err := manager.Store(name, data, options.Driver, storeOpts) if err != nil { return nil, err } + return &entities.SecretCreateReport{ ID: secretID, }, nil @@ -65,7 +71,7 @@ func (ic *ContainerEngine) SecretInspect(ctx context.Context, nameOrIDs []string errs = append(errs, err) continue } else { - return nil, nil, fmt.Errorf("error inspecting secret %s: %w", nameOrID, err) + return nil, nil, fmt.Errorf("inspecting secret %s: %w", nameOrID, err) } } report := &entities.SecretInfoReport{ diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go index 3389abd88..da903df9e 100644 --- a/pkg/domain/infra/abi/system.go +++ b/pkg/domain/infra/abi/system.go @@ -11,7 +11,6 @@ import ( "github.com/containers/common/pkg/cgroups" "github.com/containers/common/pkg/config" - cutil "github.com/containers/common/pkg/util" "github.com/containers/podman/v4/libpod/define" "github.com/containers/podman/v4/pkg/domain/entities" "github.com/containers/podman/v4/pkg/domain/entities/reports" @@ -321,19 +320,9 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System return nil, err } - running, err := ic.Libpod.GetRunningContainers() - if err != nil { - return nil, err - } - runningContainers := make([]string, 0, len(running)) - for _, c := range running { - runningContainers = append(runningContainers, c.ID()) - } - dfVolumes := make([]*entities.SystemDfVolumeReport, 0, len(vols)) for _, v := range vols { var reclaimableSize uint64 - var consInUse int mountPoint, err := v.MountPoint() if err != nil { return nil, err @@ -355,14 +344,9 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System if len(inUse) == 0 { reclaimableSize = volSize } - for _, viu := range inUse { - if cutil.StringInSlice(viu, runningContainers) { - consInUse++ - } - } report := entities.SystemDfVolumeReport{ VolumeName: v.Name(), - Links: consInUse, + Links: len(inUse), Size: int64(volSize), ReclaimableSize: int64(reclaimableSize), } diff --git a/pkg/domain/infra/abi/terminal/sigproxy_linux.go b/pkg/domain/infra/abi/terminal/sigproxy_commn.go index 16d345f06..3a0132ef3 100644 --- a/pkg/domain/infra/abi/terminal/sigproxy_linux.go +++ b/pkg/domain/infra/abi/terminal/sigproxy_commn.go @@ -1,3 +1,6 @@ +//go:build linux || freebsd +// +build linux freebsd + package terminal import ( diff --git a/pkg/domain/infra/abi/terminal/terminal_linux.go b/pkg/domain/infra/abi/terminal/terminal_common.go index 222590871..d00595908 100644 --- a/pkg/domain/infra/abi/terminal/terminal_linux.go +++ b/pkg/domain/infra/abi/terminal/terminal_common.go @@ -1,3 +1,6 @@ +//go:build linux || freebsd +// +build linux freebsd + package terminal import ( @@ -103,7 +106,7 @@ func StartAttachCtr(ctx context.Context, ctr *libpod.Container, stdout, stderr, err = <-attachChan if err != nil { - return fmt.Errorf("error attaching to container %s: %w", ctr.ID(), err) + return fmt.Errorf("attaching to container %s: %w", ctr.ID(), err) } return nil diff --git a/pkg/domain/infra/abi/terminal/terminal_unsupported.go b/pkg/domain/infra/abi/terminal/terminal_unsupported.go new file mode 100644 index 000000000..21ed6c8d4 --- /dev/null +++ b/pkg/domain/infra/abi/terminal/terminal_unsupported.go @@ -0,0 +1,25 @@ +//go:build !linux && !freebsd +// +build !linux,!freebsd + +package terminal + +import ( + "context" + "errors" + "os" + + "github.com/containers/podman/v4/libpod" + "github.com/containers/podman/v4/libpod/define" +) + +// ExecAttachCtr execs and attaches to a container +func ExecAttachCtr(ctx context.Context, ctr *libpod.Container, execConfig *libpod.ExecConfig, streams *define.AttachStreams) (int, error) { + return -1, errors.New("not implemented ExecAttachCtr") +} + +// StartAttachCtr starts and (if required) attaches to a container +// if you change the signature of this function from os.File to io.Writer, it will trigger a downstream +// error. we may need to just lint disable this one. +func StartAttachCtr(ctx context.Context, ctr *libpod.Container, stdout, stderr, stdin *os.File, detachKeys string, sigProxy bool, startContainer bool) error { //nolint: interfacer + return errors.New("not implemented StartAttachCtr") +} diff --git a/pkg/domain/infra/abi/trust.go b/pkg/domain/infra/abi/trust.go index 0e3d8fad9..c58ddff06 100644 --- a/pkg/domain/infra/abi/trust.go +++ b/pkg/domain/infra/abi/trust.go @@ -2,16 +2,11 @@ package abi import ( "context" - "encoding/json" - "errors" "fmt" "io/ioutil" - "os" - "strings" "github.com/containers/podman/v4/pkg/domain/entities" "github.com/containers/podman/v4/pkg/trust" - "github.com/sirupsen/logrus" ) func (ir *ImageEngine) ShowTrust(ctx context.Context, args []string, options entities.ShowTrustOptions) (*entities.ShowTrustReport, error) { @@ -34,11 +29,7 @@ func (ir *ImageEngine) ShowTrust(ctx context.Context, args []string, options ent if len(options.RegistryPath) > 0 { report.SystemRegistriesDirPath = options.RegistryPath } - policyContentStruct, err := trust.GetPolicy(policyPath) - if err != nil { - return nil, fmt.Errorf("could not read trust policies: %w", err) - } - report.Policies, err = getPolicyShowOutput(policyContentStruct, report.SystemRegistriesDirPath) + report.Policies, err = trust.PolicyDescription(policyPath, report.SystemRegistriesDirPath) if err != nil { return nil, fmt.Errorf("could not show trust policies: %w", err) } @@ -46,133 +37,19 @@ func (ir *ImageEngine) ShowTrust(ctx context.Context, args []string, options ent } func (ir *ImageEngine) SetTrust(ctx context.Context, args []string, options entities.SetTrustOptions) error { - var ( - policyContentStruct trust.PolicyContent - newReposContent []trust.RepoContent - ) - trustType := options.Type - if trustType == "accept" { - trustType = "insecureAcceptAnything" - } - - pubkeysfile := options.PubKeysFile - if len(pubkeysfile) == 0 && trustType == "signedBy" { - return errors.New("at least one public key must be defined for type 'signedBy'") + if len(args) != 1 { + return fmt.Errorf("SetTrust called with unexpected %d args", len(args)) } + scope := args[0] policyPath := trust.DefaultPolicyPath(ir.Libpod.SystemContext()) if len(options.PolicyPath) > 0 { policyPath = options.PolicyPath } - _, err := os.Stat(policyPath) - if !os.IsNotExist(err) { - policyContent, err := ioutil.ReadFile(policyPath) - if err != nil { - return err - } - if err := json.Unmarshal(policyContent, &policyContentStruct); err != nil { - return errors.New("could not read trust policies") - } - } - if len(pubkeysfile) != 0 { - for _, filepath := range pubkeysfile { - newReposContent = append(newReposContent, trust.RepoContent{Type: trustType, KeyType: "GPGKeys", KeyPath: filepath}) - } - } else { - newReposContent = append(newReposContent, trust.RepoContent{Type: trustType}) - } - if args[0] == "default" { - policyContentStruct.Default = newReposContent - } else { - if len(policyContentStruct.Default) == 0 { - return errors.New("default trust policy must be set") - } - registryExists := false - for transport, transportval := range policyContentStruct.Transports { - _, registryExists = transportval[args[0]] - if registryExists { - policyContentStruct.Transports[transport][args[0]] = newReposContent - break - } - } - if !registryExists { - if policyContentStruct.Transports == nil { - policyContentStruct.Transports = make(map[string]trust.RepoMap) - } - if policyContentStruct.Transports["docker"] == nil { - policyContentStruct.Transports["docker"] = make(map[string][]trust.RepoContent) - } - policyContentStruct.Transports["docker"][args[0]] = append(policyContentStruct.Transports["docker"][args[0]], newReposContent...) - } - } - - data, err := json.MarshalIndent(policyContentStruct, "", " ") - if err != nil { - return fmt.Errorf("error setting trust policy: %w", err) - } - return ioutil.WriteFile(policyPath, data, 0644) -} - -func getPolicyShowOutput(policyContentStruct trust.PolicyContent, systemRegistriesDirPath string) ([]*trust.Policy, error) { - var output []*trust.Policy - - registryConfigs, err := trust.LoadAndMergeConfig(systemRegistriesDirPath) - if err != nil { - return nil, err - } - - if len(policyContentStruct.Default) > 0 { - defaultPolicyStruct := trust.Policy{ - Transport: "all", - Name: "* (default)", - RepoName: "default", - Type: trustTypeDescription(policyContentStruct.Default[0].Type), - } - output = append(output, &defaultPolicyStruct) - } - for transport, transval := range policyContentStruct.Transports { - if transport == "docker" { - transport = "repository" - } - for repo, repoval := range transval { - tempTrustShowOutput := trust.Policy{ - Name: repo, - RepoName: repo, - Transport: transport, - Type: trustTypeDescription(repoval[0].Type), - } - // TODO - keyarr is not used and I don't know its intent; commenting out for now for someone to fix later - // keyarr := []string{} - uids := []string{} - for _, repoele := range repoval { - if len(repoele.KeyPath) > 0 { - // keyarr = append(keyarr, repoele.KeyPath) - uids = append(uids, trust.GetGPGIdFromKeyPath(repoele.KeyPath)...) - } - if len(repoele.KeyData) > 0 { - // keyarr = append(keyarr, string(repoele.KeyData)) - uids = append(uids, trust.GetGPGIdFromKeyData(repoele.KeyData)...) - } - } - tempTrustShowOutput.GPGId = strings.Join(uids, ", ") - - registryNamespace := trust.HaveMatchRegistry(repo, registryConfigs) - if registryNamespace != nil { - tempTrustShowOutput.SignatureStore = registryNamespace.SigStore - } - output = append(output, &tempTrustShowOutput) - } - } - return output, nil -} - -var typeDescription = map[string]string{"insecureAcceptAnything": "accept", "signedBy": "signed", "reject": "reject"} - -func trustTypeDescription(trustType string) string { - trustDescription, exist := typeDescription[trustType] - if !exist { - logrus.Warnf("Invalid trust type %s", trustType) - } - return trustDescription + return trust.AddPolicyEntries(policyPath, trust.AddPolicyEntriesInput{ + Scope: scope, + Type: options.Type, + PubKeyFiles: options.PubKeysFile, + }) } diff --git a/pkg/domain/infra/abi/volumes.go b/pkg/domain/infra/abi/volumes.go index 5e95a0551..bdfd4d5aa 100644 --- a/pkg/domain/infra/abi/volumes.go +++ b/pkg/domain/infra/abi/volumes.go @@ -96,7 +96,7 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin errs = append(errs, fmt.Errorf("no such volume %s", v)) continue } else { - return nil, nil, fmt.Errorf("error inspecting volume %s: %w", v, err) + return nil, nil, fmt.Errorf("inspecting volume %s: %w", v, err) } } vols = append(vols, vol) |