From 3ff1583814b4e69d2d85ee2b1d342d0d5974b9de Mon Sep 17 00:00:00 2001
From: Brent Baude <bbaude@redhat.com>
Date: Fri, 27 Mar 2020 11:06:16 -0500
Subject: podmanv2 commit

add commit of a container to a container-image

Signed-off-by: Brent Baude <bbaude@redhat.com>
---
 pkg/domain/entities/containers.go       | 17 ++++++++++++
 pkg/domain/entities/engine_container.go |  1 +
 pkg/domain/infra/abi/containers.go      | 48 +++++++++++++++++++++++++++++++++
 pkg/domain/infra/tunnel/containers.go   | 38 ++++++++++++++++++++++++++
 4 files changed, 104 insertions(+)

(limited to 'pkg')

diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index fbc0247ab..3389e4db5 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -1,6 +1,7 @@
 package entities
 
 import (
+	"io"
 	"time"
 
 	"github.com/containers/libpod/libpod/define"
@@ -106,3 +107,19 @@ type ContainerInspectOptions struct {
 type ContainerInspectReport struct {
 	*define.InspectContainerData
 }
+
+type CommitOptions struct {
+	Author         string
+	Changes        []string
+	Format         string
+	ImageName      string
+	IncludeVolumes bool
+	Message        string
+	Pause          bool
+	Quiet          bool
+	Writer         io.Writer
+}
+
+type CommitReport struct {
+	Id string
+}
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index fceed1003..28be8b225 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -5,6 +5,7 @@ import (
 )
 
 type ContainerEngine interface {
+	ContainerCommit(ctx context.Context, nameOrId string, options CommitOptions) (*CommitReport, error)
 	ContainerExists(ctx context.Context, nameOrId string) (*BoolReport, error)
 	ContainerInspect(ctx context.Context, namesOrIds []string, options ContainerInspectOptions) ([]*ContainerInspectReport, error)
 	ContainerKill(ctx context.Context, namesOrIds []string, options KillOptions) ([]*KillReport, error)
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 3965c5f75..d25af24c5 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -7,8 +7,11 @@ import (
 	"io/ioutil"
 	"strings"
 
+	"github.com/containers/buildah"
+	"github.com/containers/image/v5/manifest"
 	"github.com/containers/libpod/libpod"
 	"github.com/containers/libpod/libpod/define"
+	"github.com/containers/libpod/libpod/image"
 	"github.com/containers/libpod/pkg/adapter/shortcuts"
 	"github.com/containers/libpod/pkg/domain/entities"
 	"github.com/containers/libpod/pkg/signal"
@@ -277,3 +280,48 @@ func (ic *ContainerEngine) ContainerTop(ctx context.Context, options entities.To
 	report.Value, err = container.Top(options.Descriptors)
 	return report, err
 }
+
+func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrId string, options entities.CommitOptions) (*entities.CommitReport, error) {
+	var (
+		mimeType string
+	)
+	ctr, err := ic.Libpod.LookupContainer(nameOrId)
+	if err != nil {
+		return nil, err
+	}
+	rtc, err := ic.Libpod.GetConfig()
+	if err != nil {
+		return nil, err
+	}
+	switch options.Format {
+	case "oci":
+		mimeType = buildah.OCIv1ImageManifest
+		if len(options.Message) > 0 {
+			return nil, errors.Errorf("messages are only compatible with the docker image format (-f docker)")
+		}
+	case "docker":
+		mimeType = manifest.DockerV2Schema2MediaType
+	default:
+		return nil, errors.Errorf("unrecognized image format %q", options.Format)
+	}
+	sc := image.GetSystemContext(rtc.Engine.SignaturePolicyPath, "", false)
+	coptions := buildah.CommitOptions{
+		SignaturePolicyPath:   rtc.Engine.SignaturePolicyPath,
+		ReportWriter:          options.Writer,
+		SystemContext:         sc,
+		PreferredManifestType: mimeType,
+	}
+	opts := libpod.ContainerCommitOptions{
+		CommitOptions:  coptions,
+		Pause:          options.Pause,
+		IncludeVolumes: options.IncludeVolumes,
+		Message:        options.Message,
+		Changes:        options.Changes,
+		Author:         options.Author,
+	}
+	newImage, err := ctr.Commit(ctx, options.ImageName, opts)
+	if err != nil {
+		return nil, err
+	}
+	return &entities.CommitReport{Id: newImage.ID()}, nil
+}
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index 3db38ea5c..3c8be90dc 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -3,6 +3,8 @@ package tunnel
 import (
 	"context"
 
+	"github.com/containers/image/v5/docker/reference"
+
 	"github.com/containers/libpod/pkg/bindings/containers"
 	"github.com/containers/libpod/pkg/domain/entities"
 	"github.com/pkg/errors"
@@ -172,3 +174,39 @@ func (ic *ContainerEngine) ContainerTop(ctx context.Context, options entities.To
 	}
 	return &entities.StringSliceReport{Value: topOutput}, nil
 }
+
+func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrId string, options entities.CommitOptions) (*entities.CommitReport, error) {
+	var (
+		repo string
+		tag  string = "latest"
+	)
+	if len(options.ImageName) > 0 {
+		ref, err := reference.Parse(options.ImageName)
+		if err != nil {
+			return nil, err
+		}
+		if t, ok := ref.(reference.Tagged); ok {
+			tag = t.Tag()
+		}
+		if r, ok := ref.(reference.Named); ok {
+			repo = r.Name()
+		}
+		if len(repo) < 1 {
+			return nil, errors.Errorf("invalid image name %q", options.ImageName)
+		}
+	}
+	commitOpts := containers.CommitOptions{
+		Author:  &options.Author,
+		Changes: options.Changes,
+		Comment: &options.Message,
+		Format:  &options.Format,
+		Pause:   &options.Pause,
+		Repo:    &repo,
+		Tag:     &tag,
+	}
+	response, err := containers.Commit(ic.ClientCxt, nameOrId, commitOpts)
+	if err != nil {
+		return nil, err
+	}
+	return &entities.CommitReport{Id: response.ID}, nil
+}
-- 
cgit v1.2.3-54-g00ecf