diff options
Diffstat (limited to 'pkg/domain')
-rw-r--r-- | pkg/domain/entities/containers.go | 9 | ||||
-rw-r--r-- | pkg/domain/entities/images.go | 15 | ||||
-rw-r--r-- | pkg/domain/entities/machine.go | 22 | ||||
-rw-r--r-- | pkg/domain/entities/play.go | 5 | ||||
-rw-r--r-- | pkg/domain/filters/containers.go | 9 | ||||
-rw-r--r-- | pkg/domain/filters/pods.go | 3 | ||||
-rw-r--r-- | pkg/domain/filters/volumes.go | 5 | ||||
-rw-r--r-- | pkg/domain/infra/abi/containers.go | 66 | ||||
-rw-r--r-- | pkg/domain/infra/abi/images.go | 3 | ||||
-rw-r--r-- | pkg/domain/infra/abi/manifest.go | 3 | ||||
-rw-r--r-- | pkg/domain/infra/abi/play.go | 80 | ||||
-rw-r--r-- | pkg/domain/infra/abi/secrets.go | 2 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/containers.go | 48 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/images.go | 2 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/manifest.go | 10 |
15 files changed, 236 insertions, 46 deletions
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go index 934a7cbdc..df793034b 100644 --- a/pkg/domain/entities/containers.go +++ b/pkg/domain/entities/containers.go @@ -71,12 +71,15 @@ type StringSliceReport struct { } type PauseUnPauseOptions struct { - All bool + Filters map[string][]string + All bool + Latest bool } type PauseUnpauseReport struct { - Err error - Id string //nolint:revive,stylecheck + Err error + Id string //nolint:revive,stylecheck + RawInput string } type StopOptions struct { diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go index da317cfad..b8b346005 100644 --- a/pkg/domain/entities/images.go +++ b/pkg/domain/entities/images.go @@ -1,6 +1,7 @@ package entities import ( + "io" "net/url" "time" @@ -192,8 +193,7 @@ type ImagePushOptions struct { // image. Default is manifest type of source, with fallbacks. // Ignored for remote calls. Format string - // Quiet can be specified to suppress pull progress when pulling. Ignored - // for remote calls. + // Quiet can be specified to suppress push progress when pushing. Quiet bool // Rm indicates whether to remove the manifest list if push succeeds Rm bool @@ -211,6 +211,17 @@ type ImagePushOptions struct { Progress chan types.ProgressProperties // CompressionFormat is the format to use for the compression of the blobs CompressionFormat string + // Writer is used to display copy information including progress bars. + Writer io.Writer +} + +// ImagePushReport is the response from pushing an image. +// Currently only used in the remote API. +type ImagePushReport struct { + // Stream used to provide push progress + Stream string `json:"stream,omitempty"` + // Error contains text of errors from pushing + Error string `json:"error,omitempty"` } // ImageSearchOptions are the arguments for searching images. diff --git a/pkg/domain/entities/machine.go b/pkg/domain/entities/machine.go index 6ba53dbd1..4fd0413c9 100644 --- a/pkg/domain/entities/machine.go +++ b/pkg/domain/entities/machine.go @@ -1,5 +1,7 @@ package entities +import "github.com/containers/podman/v4/libpod/define" + type ListReporter struct { Name string Default bool @@ -16,3 +18,23 @@ type ListReporter struct { RemoteUsername string IdentityPath string } + +// MachineInfo contains info on the machine host and version info +type MachineInfo struct { + Host *MachineHostInfo `json:"Host"` + Version define.Version `json:"Version"` +} + +// MachineHostInfo contains info on the machine host +type MachineHostInfo struct { + Arch string `json:"Arch"` + CurrentMachine string `json:"CurrentMachine"` + DefaultMachine string `json:"DefaultMachine"` + EventsDir string `json:"EventsDir"` + MachineConfigDir string `json:"MachineConfigDir"` + MachineImageDir string `json:"MachineImageDir"` + MachineState string `json:"MachineState"` + NumberOfMachines int `json:"NumberOfMachines"` + OS string `json:"OS"` + VMType string `json:"VMType"` +} diff --git a/pkg/domain/entities/play.go b/pkg/domain/entities/play.go index 35a5d8a4a..5bb438d7d 100644 --- a/pkg/domain/entities/play.go +++ b/pkg/domain/entities/play.go @@ -88,6 +88,7 @@ type PlayKubeReport struct { // Volumes - volumes created by play kube. Volumes []PlayKubeVolume PlayKubeTeardown + Secrets []PlaySecret } type KubePlayReport = PlayKubeReport @@ -100,3 +101,7 @@ type PlayKubeTeardown struct { StopReport []*PodStopReport RmReport []*PodRmReport } + +type PlaySecret struct { + CreateReport *SecretCreateReport +} diff --git a/pkg/domain/filters/containers.go b/pkg/domain/filters/containers.go index f88a165e7..de62b6582 100644 --- a/pkg/domain/filters/containers.go +++ b/pkg/domain/filters/containers.go @@ -7,6 +7,7 @@ import ( "strings" "time" + "github.com/containers/common/pkg/filters" cutil "github.com/containers/common/pkg/util" "github.com/containers/podman/v4/libpod" "github.com/containers/podman/v4/libpod/define" @@ -24,7 +25,7 @@ func GenerateContainerFilterFuncs(filter string, filterValues []string, r *libpo case "label": // we have to match that all given labels exits on that container return func(c *libpod.Container) bool { - return util.MatchLabelFilters(filterValues, c.Labels()) + return filters.MatchLabelFilters(filterValues, c.Labels()) }, nil case "name": // we only have to match one name @@ -299,7 +300,11 @@ func GeneratePruneContainerFilterFuncs(filter string, filterValues []string, r * switch filter { case "label": return func(c *libpod.Container) bool { - return util.MatchLabelFilters(filterValues, c.Labels()) + return filters.MatchLabelFilters(filterValues, c.Labels()) + }, nil + case "label!": + return func(c *libpod.Container) bool { + return !filters.MatchLabelFilters(filterValues, c.Labels()) }, nil case "until": return prepareUntilFilterFunc(filterValues) diff --git a/pkg/domain/filters/pods.go b/pkg/domain/filters/pods.go index 78b97db64..7b0944292 100644 --- a/pkg/domain/filters/pods.go +++ b/pkg/domain/filters/pods.go @@ -6,6 +6,7 @@ import ( "strconv" "strings" + "github.com/containers/common/pkg/filters" cutil "github.com/containers/common/pkg/util" "github.com/containers/podman/v4/libpod" "github.com/containers/podman/v4/libpod/define" @@ -115,7 +116,7 @@ func GeneratePodFilterFunc(filter string, filterValues []string, r *libpod.Runti case "label": return func(p *libpod.Pod) bool { labels := p.Labels() - return util.MatchLabelFilters(filterValues, labels) + return filters.MatchLabelFilters(filterValues, labels) }, nil case "until": return func(p *libpod.Pod) bool { diff --git a/pkg/domain/filters/volumes.go b/pkg/domain/filters/volumes.go index 7c5047225..9cec39fbb 100644 --- a/pkg/domain/filters/volumes.go +++ b/pkg/domain/filters/volumes.go @@ -6,6 +6,7 @@ import ( "regexp" "strings" + pruneFilters "github.com/containers/common/pkg/filters" "github.com/containers/podman/v4/libpod" "github.com/containers/podman/v4/pkg/util" ) @@ -36,7 +37,7 @@ func GenerateVolumeFilters(filters url.Values) ([]libpod.VolumeFilter, error) { case "label": filter := val vf = append(vf, func(v *libpod.Volume) bool { - return util.MatchLabelFilters([]string{filter}, v.Labels()) + return pruneFilters.MatchLabelFilters([]string{filter}, v.Labels()) }) case "opt": filterArray := strings.SplitN(val, "=", 2) @@ -100,7 +101,7 @@ func GeneratePruneVolumeFilters(filters url.Values) ([]libpod.VolumeFilter, erro switch filter { case "label": vf = append(vf, func(v *libpod.Volume) bool { - return util.MatchLabelFilters([]string{filterVal}, v.Labels()) + return pruneFilters.MatchLabelFilters([]string{filterVal}, v.Labels()) }) case "until": f, err := createUntilFilterVolumeFunction(filterVal) diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index 04eb85504..783224e9c 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -62,6 +62,11 @@ func getContainersAndInputByContext(all, latest bool, names []string, filters ma } case all: ctrs, err = runtime.GetAllContainers() + if err == nil { + for _, ctr := range ctrs { + rawInput = append(rawInput, ctr.ID()) + } + } case latest: ctr, err = runtime.GetLatestContainer() if err == nil { @@ -133,37 +138,57 @@ func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []strin } func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) { - ctrs, err := getContainersByContext(options.All, false, namesOrIds, ic.Libpod) + ctrs, rawInputs, err := getContainersAndInputByContext(options.All, options.Latest, namesOrIds, options.Filters, ic.Libpod) if err != nil { return nil, err } - report := make([]*entities.PauseUnpauseReport, 0, len(ctrs)) + ctrMap := map[string]string{} + if len(rawInputs) == len(ctrs) { + for i := range ctrs { + ctrMap[ctrs[i].ID()] = rawInputs[i] + } + } + reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs)) for _, c := range ctrs { err := c.Pause() if err != nil && options.All && errors.Is(err, define.ErrCtrStateInvalid) { logrus.Debugf("Container %s is not running", c.ID()) continue } - report = append(report, &entities.PauseUnpauseReport{Id: c.ID(), Err: err}) + reports = append(reports, &entities.PauseUnpauseReport{ + Id: c.ID(), + Err: err, + RawInput: ctrMap[c.ID()], + }) } - return report, nil + return reports, nil } func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) { - ctrs, err := getContainersByContext(options.All, false, namesOrIds, ic.Libpod) + ctrs, rawInputs, err := getContainersAndInputByContext(options.All, options.Latest, namesOrIds, options.Filters, ic.Libpod) if err != nil { return nil, err } - report := make([]*entities.PauseUnpauseReport, 0, len(ctrs)) + ctrMap := map[string]string{} + if len(rawInputs) == len(ctrs) { + for i := range ctrs { + ctrMap[ctrs[i].ID()] = rawInputs[i] + } + } + reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs)) for _, c := range ctrs { err := c.Unpause() if err != nil && options.All && errors.Is(err, define.ErrCtrStateInvalid) { logrus.Debugf("Container %s is not paused", c.ID()) continue } - report = append(report, &entities.PauseUnpauseReport{Id: c.ID(), Err: err}) + reports = append(reports, &entities.PauseUnpauseReport{ + Id: c.ID(), + Err: err, + RawInput: ctrMap[c.ID()], + }) } - return report, nil + return reports, nil } func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []string, options entities.StopOptions) ([]*entities.StopReport, error) { names := namesOrIds @@ -235,6 +260,7 @@ func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities. if err != nil { return nil, err } + filterFuncs = append(filterFuncs, generatedFunc) } return ic.Libpod.PruneContainers(filterFuncs) @@ -1035,6 +1061,15 @@ func (ic *ContainerEngine) Diff(ctx context.Context, namesOrIDs []string, opts e } func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.ContainerRunOptions) (*entities.ContainerRunReport, error) { + removeContainer := func(ctr *libpod.Container, force bool) error { + var timeout *uint + if err := ic.Libpod.RemoveContainer(ctx, ctr, force, true, timeout); err != nil { + logrus.Debugf("unable to remove container %s after failing to start and attach to it: %v", ctr.ID(), err) + return err + } + return nil + } + warn, err := generate.CompleteSpec(ctx, ic.Libpod, opts.Spec) if err != nil { return nil, err @@ -1055,6 +1090,8 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta if opts.CIDFile != "" { if err := util.CreateCidFile(opts.CIDFile, ctr.ID()); err != nil { + // If you fail to create CIDFile then remove the container + _ = removeContainer(ctr, true) return nil, err } } @@ -1072,6 +1109,11 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta if err := ctr.Start(ctx, true); err != nil { // This means the command did not exist report.ExitCode = define.ExitCode(err) + if opts.Rm { + if rmErr := removeContainer(ctr, true); rmErr != nil && !errors.Is(rmErr, define.ErrNoSuchCtr) { + logrus.Errorf("Container %s failed to be removed", ctr.ID()) + } + } return &report, err } @@ -1088,10 +1130,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta return &report, nil } if opts.Rm { - var timeout *uint - if deleteError := ic.Libpod.RemoveContainer(ctx, ctr, true, false, timeout); deleteError != nil { - logrus.Debugf("unable to remove container %s after failing to start and attach to it", ctr.ID()) - } + _ = removeContainer(ctr, true) } if errors.Is(err, define.ErrWillDeadlock) { logrus.Debugf("Deadlock error on %q: %v", ctr.ID(), err) @@ -1103,8 +1142,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta } report.ExitCode = ic.GetContainerExitCode(ctx, ctr) if opts.Rm && !ctr.ShouldRestart(ctx) { - var timeout *uint - if err := ic.Libpod.RemoveContainer(ctx, ctr, false, true, timeout); err != nil { + if err := removeContainer(ctr, false); err != nil { if errors.Is(err, define.ErrNoSuchCtr) || errors.Is(err, define.ErrCtrRemoved) { logrus.Infof("Container %s was already removed, skipping --rm", ctr.ID()) diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go index 38008c7b9..ff42b0367 100644 --- a/pkg/domain/infra/abi/images.go +++ b/pkg/domain/infra/abi/images.go @@ -305,6 +305,7 @@ func (ir *ImageEngine) Push(ctx context.Context, source string, destination stri pushOptions.RemoveSignatures = options.RemoveSignatures pushOptions.SignBy = options.SignBy pushOptions.InsecureSkipTLSVerify = options.SkipTLSVerify + pushOptions.Writer = options.Writer compressionFormat := options.CompressionFormat if compressionFormat == "" { @@ -322,7 +323,7 @@ func (ir *ImageEngine) Push(ctx context.Context, source string, destination stri pushOptions.CompressionFormat = &algo } - if !options.Quiet { + if !options.Quiet && pushOptions.Writer == nil { pushOptions.Writer = os.Stderr } diff --git a/pkg/domain/infra/abi/manifest.go b/pkg/domain/infra/abi/manifest.go index d20744d76..bdc3d9513 100644 --- a/pkg/domain/infra/abi/manifest.go +++ b/pkg/domain/infra/abi/manifest.go @@ -331,7 +331,8 @@ func (ir *ImageEngine) ManifestPush(ctx context.Context, name, destination strin } if opts.Rm { - if _, rmErrors := ir.Libpod.LibimageRuntime().RemoveImages(ctx, []string{manifestList.ID()}, nil); len(rmErrors) > 0 { + 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]) } } diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index 8b47eff53..3f2fd5f92 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -84,15 +84,15 @@ func (ic *ContainerEngine) createServiceContainer(ctx context.Context, name stri return ctr, nil } -// Creates the name for a service container based on the provided content of a -// K8s yaml file. -func serviceContainerName(content []byte) string { +// Creates the name for a k8s entity based on the provided content of a +// K8s yaml file and a given suffix. +func k8sName(content []byte, suffix string) string { // The name of the service container is the first 12 // characters of the yaml file's hash followed by the // '-service' suffix to guarantee a predictable and // discoverable name. hash := digest.FromBytes(content).Encoded() - return hash[0:12] + "-service" + return hash[0:12] + "-" + suffix } func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, options entities.PlayKubeOptions) (_ *entities.PlayKubeReport, finalErr error) { @@ -132,7 +132,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") { - ctr, err := ic.createServiceContainer(ctx, serviceContainerName(content), options) + ctr, err := ic.createServiceContainer(ctx, k8sName(content, "service"), options) if err != nil { return nil, err } @@ -213,6 +213,19 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, options return nil, fmt.Errorf("unable to read YAML as Kube ConfigMap: %w", err) } configMaps = append(configMaps, configMap) + case "Secret": + var secret v1.Secret + + if err := yaml.Unmarshal(document, &secret); err != nil { + return nil, fmt.Errorf("unable to read YAML as kube secret: %w", err) + } + + r, err := ic.playKubeSecret(&secret) + if err != nil { + return nil, err + } + report.Secrets = append(report.Secrets, entities.PlaySecret{CreateReport: r}) + validKinds++ default: logrus.Infof("Kube kind %s not supported", kind) continue @@ -380,7 +393,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY configMaps = append(configMaps, cm) } - volumes, err := kube.InitializeVolumes(podYAML.Spec.Volumes, configMaps) + volumes, err := kube.InitializeVolumes(podYAML.Spec.Volumes, configMaps, secretsManager) if err != nil { return nil, err } @@ -388,7 +401,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 for _, v := range volumes { - if v.Type == kube.KubeVolumeTypeConfigMap && !v.Optional { + if (v.Type == kube.KubeVolumeTypeConfigMap || v.Type == kube.KubeVolumeTypeSecret) && !v.Optional { vol, err := ic.Libpod.NewVolume(ctx, libpod.WithVolumeName(v.Source)) if err != nil { if errors.Is(err, define.ErrVolumeExists) { @@ -583,6 +596,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY UserNSIsHost: p.Userns.IsHost(), Volumes: volumes, } + specGen, err := kube.ToSpecGen(ctx, &specgenOpts) if err != nil { return nil, err @@ -968,3 +982,55 @@ func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, body io.Reader, _ e return reports, nil } + +// playKubeSecret allows users to create and store a kubernetes secret as a podman secret +func (ic *ContainerEngine) playKubeSecret(secret *v1.Secret) (*entities.SecretCreateReport, error) { + r := &entities.SecretCreateReport{} + + // Create the secret manager before hand + secretsManager, err := ic.Libpod.SecretsManager() + if err != nil { + return nil, err + } + + data, err := yaml.Marshal(secret) + if err != nil { + return nil, err + } + + secretsPath := ic.Libpod.GetSecretsStorageDir() + opts := make(map[string]string) + opts["path"] = filepath.Join(secretsPath, "filedriver") + // maybe k8sName(data)... + // using this does not allow the user to use the name given to the secret + // but keeping secret.Name as the ID can lead to a collision. + + s, err := secretsManager.Lookup(secret.Name) + if err == nil { + if val, ok := s.Metadata["immutable"]; ok { + if val == "true" { + return nil, fmt.Errorf("cannot remove colliding secret as it is set to immutable") + } + } + _, err = secretsManager.Delete(s.Name) + if err != nil { + return nil, err + } + } + + // now we have either removed the old secret w/ the same name or + // the name was not taken. Either way, we can now store. + + meta := make(map[string]string) + if secret.Immutable != nil && *secret.Immutable { + meta["immutable"] = "true" + } + secretID, err := secretsManager.Store(secret.Name, data, "file", opts, meta) + if err != nil { + return nil, err + } + + r.ID = secretID + + return r, nil +} diff --git a/pkg/domain/infra/abi/secrets.go b/pkg/domain/infra/abi/secrets.go index 7321ef715..e82fa4fdd 100644 --- a/pkg/domain/infra/abi/secrets.go +++ b/pkg/domain/infra/abi/secrets.go @@ -42,7 +42,7 @@ func (ic *ContainerEngine) SecretCreate(ctx context.Context, name string, reader } } - secretID, err := manager.Store(name, data, options.Driver, options.DriverOpts) + secretID, err := manager.Store(name, data, options.Driver, options.DriverOpts, nil) if err != nil { return nil, err } diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index fcabff7c4..98c73c51a 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -57,10 +57,14 @@ func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []strin } func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) { - ctrs, err := getContainersByContext(ic.ClientCtx, options.All, false, namesOrIds) + ctrs, rawInputs, err := getContainersAndInputByContext(ic.ClientCtx, options.All, false, namesOrIds, options.Filters) if err != nil { return nil, err } + ctrMap := map[string]string{} + for i := range ctrs { + ctrMap[ctrs[i].ID] = rawInputs[i] + } reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs)) for _, c := range ctrs { err := containers.Pause(ic.ClientCtx, c.ID, nil) @@ -68,24 +72,36 @@ func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []stri logrus.Debugf("Container %s is not running", c.ID) continue } - reports = append(reports, &entities.PauseUnpauseReport{Id: c.ID, Err: err}) + reports = append(reports, &entities.PauseUnpauseReport{ + Id: c.ID, + Err: err, + RawInput: ctrMap[c.ID], + }) } return reports, nil } func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) { - reports := []*entities.PauseUnpauseReport{} - ctrs, err := getContainersByContext(ic.ClientCtx, options.All, false, namesOrIds) + ctrs, rawInputs, err := getContainersAndInputByContext(ic.ClientCtx, options.All, false, namesOrIds, options.Filters) if err != nil { return nil, err } + ctrMap := map[string]string{} + for i := range ctrs { + ctrMap[ctrs[i].ID] = rawInputs[i] + } + reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs)) for _, c := range ctrs { err := containers.Unpause(ic.ClientCtx, c.ID, nil) if err != nil && options.All && strings.Contains(err.Error(), define.ErrCtrStateInvalid.Error()) { logrus.Debugf("Container %s is not paused", c.ID) continue } - reports = append(reports, &entities.PauseUnpauseReport{Id: c.ID, Err: err}) + reports = append(reports, &entities.PauseUnpauseReport{ + Id: c.ID, + Err: err, + RawInput: ctrMap[c.ID], + }) } return reports, nil } @@ -771,8 +787,17 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta for _, w := range con.Warnings { fmt.Fprintf(os.Stderr, "%s\n", w) } + removeContainer := func(id string, force bool) error { + removeOptions := new(containers.RemoveOptions).WithVolumes(true).WithForce(force) + reports, err := containers.Remove(ic.ClientCtx, id, removeOptions) + logIfRmError(id, err, reports) + return err + } + if opts.CIDFile != "" { if err := util.CreateCidFile(opts.CIDFile, con.ID); err != nil { + // If you fail to create CIDFile then remove the container + _ = removeContainer(con.ID, true) return nil, err } } @@ -784,6 +809,11 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta err := containers.Start(ic.ClientCtx, con.ID, new(containers.StartOptions).WithRecursive(true)) if err != nil { report.ExitCode = define.ExitCode(err) + if opts.Rm { + if rmErr := removeContainer(con.ID, true); rmErr != nil && !errors.Is(rmErr, define.ErrNoSuchCtr) { + logrus.Errorf("Container %s failed to be removed", con.ID) + } + } } return &report, err } @@ -796,10 +826,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta report.ExitCode = define.ExitCode(err) if opts.Rm { - reports, rmErr := containers.Remove(ic.ClientCtx, con.ID, new(containers.RemoveOptions).WithForce(false).WithVolumes(true)) - if rmErr != nil || reports[0].Err != nil { - logrus.Debugf("unable to remove container %s after failing to start and attach to it", con.ID) - } + _ = removeContainer(con.ID, false) } return &report, err } @@ -815,8 +842,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta } if !shouldRestart { - reports, err := containers.Remove(ic.ClientCtx, con.ID, new(containers.RemoveOptions).WithForce(false).WithVolumes(true)) - logIfRmError(con.ID, err, reports) + _ = removeContainer(con.ID, false) } }() } diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go index 18f750dcc..9ad408850 100644 --- a/pkg/domain/infra/tunnel/images.go +++ b/pkg/domain/infra/tunnel/images.go @@ -240,7 +240,7 @@ func (ir *ImageEngine) Import(ctx context.Context, opts entities.ImageImportOpti func (ir *ImageEngine) Push(ctx context.Context, source string, destination string, opts entities.ImagePushOptions) error { options := new(images.PushOptions) - options.WithAll(opts.All).WithCompress(opts.Compress).WithUsername(opts.Username).WithPassword(opts.Password).WithAuthfile(opts.Authfile).WithFormat(opts.Format).WithRemoveSignatures(opts.RemoveSignatures) + options.WithAll(opts.All).WithCompress(opts.Compress).WithUsername(opts.Username).WithPassword(opts.Password).WithAuthfile(opts.Authfile).WithFormat(opts.Format).WithRemoveSignatures(opts.RemoveSignatures).WithQuiet(opts.Quiet) if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined { if s == types.OptionalBoolTrue { diff --git a/pkg/domain/infra/tunnel/manifest.go b/pkg/domain/infra/tunnel/manifest.go index d2554f198..4a3148fac 100644 --- a/pkg/domain/infra/tunnel/manifest.go +++ b/pkg/domain/infra/tunnel/manifest.go @@ -110,5 +110,15 @@ func (ir *ImageEngine) ManifestPush(ctx context.Context, name, destination strin } } digest, err := manifests.Push(ir.ClientCtx, name, destination, options) + if err != nil { + return "", fmt.Errorf("error adding to manifest list %s: %w", name, err) + } + + if opts.Rm { + if _, rmErrors := ir.Remove(ctx, []string{name}, entities.ImageRemoveOptions{LookupManifest: true}); len(rmErrors) > 0 { + return "", fmt.Errorf("error removing manifest after push: %w", rmErrors[0]) + } + } + return digest, err } |