Add an option to specify a Create date for images

Add CommitOption option that to allow a caller to specify a creation
timestamp to use in images.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>

Closes: #141
Approved by: rhatdan
This commit is contained in:
Nalin Dahyabhai 2017-06-06 14:11:46 -04:00 committed by Atomic Bot
parent af5512ab74
commit 4a05d8643d
6 changed files with 45 additions and 8 deletions

View File

@ -3,6 +3,7 @@ package main
import (
"os"
"strings"
"time"
"github.com/containers/image/storage"
"github.com/containers/image/transports/alltransports"
@ -15,7 +16,7 @@ import (
var (
commitFlags = []cli.Flag{
cli.BoolFlag{
Name: "disable-compression",
Name: "disable-compression, D",
Usage: "don't compress layers",
},
cli.StringFlag{
@ -26,6 +27,11 @@ var (
Name: "format, f",
Usage: "`format` of the image manifest and metadata",
},
cli.StringFlag{
Name: "reference-time",
Usage: "set the timestamp on the image to match the named `file`",
Hidden: true,
},
cli.BoolFlag{
Name: "quiet, q",
Usage: "don't output progress information when writing images",
@ -73,6 +79,15 @@ func commitCmd(c *cli.Context) error {
if c.IsSet("format") {
format = c.String("format")
}
timestamp := time.Now().UTC()
if c.IsSet("reference-time") {
referenceFile := c.String("reference-time")
finfo, err := os.Stat(referenceFile)
if err != nil {
return errors.Wrapf(err, "error reading timestamp of file %q", referenceFile)
}
timestamp = finfo.ModTime().UTC()
}
if strings.HasPrefix(strings.ToLower(format), "oci") {
format = buildah.OCIv1ImageManifest
} else if strings.HasPrefix(strings.ToLower(format), "docker") {
@ -103,6 +118,7 @@ func commitCmd(c *cli.Context) error {
PreferredManifestType: format,
Compression: compress,
SignaturePolicyPath: signaturePolicy,
HistoryTimestamp: &timestamp,
}
if !quiet {
options.ReportWriter = os.Stderr

View File

@ -3,6 +3,7 @@ package buildah
import (
"bytes"
"io"
"time"
"github.com/Sirupsen/logrus"
cp "github.com/containers/image/copy"
@ -50,6 +51,9 @@ type CommitOptions struct {
// ReportWriter is an io.Writer which will be used to log the writing
// of the new image.
ReportWriter io.Writer
// HistoryTimestamp is the timestamp used when creating new items in the
// image's history. If unset, the current time will be used.
HistoryTimestamp *time.Time
}
// shallowCopy copies the most recent layer, the configuration, and the manifest from one image to another.
@ -220,7 +224,7 @@ func (b *Builder) Commit(dest types.ImageReference, options CommitOptions) error
// Check if we're keeping everything in local storage. If so, we can take certain shortcuts.
_, destIsStorage := dest.Transport().(storage.StoreTransport)
exporting := !destIsStorage
src, err := b.makeContainerImageRef(options.PreferredManifestType, exporting, options.Compression)
src, err := b.makeContainerImageRef(options.PreferredManifestType, exporting, options.Compression, options.HistoryTimestamp)
if err != nil {
return errors.Wrapf(err, "error recomputing layer digests and building metadata")
}

View File

@ -227,9 +227,16 @@ func (b *Builder) fixupConfig() {
b.Docker.Parent = docker.ID(digest.NewDigestFromHex(digest.Canonical.String(), b.FromImageID))
}
}
now := time.Now().UTC()
if b.Docker.Created.IsZero() {
b.Docker.Created = now
}
if b.FromImage != "" {
b.Docker.Config.Image = b.FromImage
}
if b.OCIv1.Created.IsZero() {
b.OCIv1.Created = now
}
if b.OS() == "" {
b.SetOS(runtime.GOOS)
}

View File

@ -295,6 +295,7 @@ return 1
--signature-policy
--format
-f
--reference-time
"
local all_options="$options_with_args $boolean_options"

View File

@ -33,6 +33,11 @@ Control the format for the image manifest and configuration data. Recognized
formats include *oci* (OCI image-spec v1.0, the default) and *docker* (version
2, using schema format 2 for the manifest).
**--reference-time**
Sets the creation date in the image to match the last-modified time of the
specified file. This option is mainly present for use in buildah's self-tests.
## EXAMPLE
buildah commit containerID

View File

@ -460,7 +460,7 @@ func (i *containerImageSource) GetBlob(blob types.BlobInfo) (reader io.ReadClose
return ioutils.NewReadCloserWrapper(layerFile, closer), size, nil
}
func (b *Builder) makeImageRef(manifestType string, exporting, addHistory bool, compress archive.Compression, names []string, layerID string) (types.ImageReference, error) {
func (b *Builder) makeImageRef(manifestType string, exporting, addHistory bool, compress archive.Compression, names []string, layerID string, historyTimestamp *time.Time) (types.ImageReference, error) {
var name reference.Named
if len(names) > 0 {
if parsed, err := reference.ParseNamed(names[0]); err == nil {
@ -478,6 +478,10 @@ func (b *Builder) makeImageRef(manifestType string, exporting, addHistory bool,
if err != nil {
return nil, errors.Wrapf(err, "error encoding docker-format image configuration")
}
created := time.Now().UTC()
if historyTimestamp != nil {
created = historyTimestamp.UTC()
}
ref := &containerImageRef{
store: b.store,
compression: compress,
@ -487,7 +491,7 @@ func (b *Builder) makeImageRef(manifestType string, exporting, addHistory bool,
addHistory: addHistory,
oconfig: oconfig,
dconfig: dconfig,
created: time.Now().UTC(),
created: created,
createdBy: b.CreatedBy(),
annotations: b.Annotations(),
preferredManifestType: manifestType,
@ -496,7 +500,7 @@ func (b *Builder) makeImageRef(manifestType string, exporting, addHistory bool,
return ref, nil
}
func (b *Builder) makeContainerImageRef(manifestType string, exporting bool, compress archive.Compression) (types.ImageReference, error) {
func (b *Builder) makeContainerImageRef(manifestType string, exporting bool, compress archive.Compression, historyTimestamp *time.Time) (types.ImageReference, error) {
if manifestType == "" {
manifestType = OCIv1ImageManifest
}
@ -504,9 +508,9 @@ func (b *Builder) makeContainerImageRef(manifestType string, exporting bool, com
if err != nil {
return nil, errors.Wrapf(err, "error locating container %q", b.ContainerID)
}
return b.makeImageRef(manifestType, exporting, true, compress, container.Names, container.LayerID)
return b.makeImageRef(manifestType, exporting, true, compress, container.Names, container.LayerID, historyTimestamp)
}
func (b *Builder) makeImageImageRef(compress archive.Compression, names []string, layerID string) (types.ImageReference, error) {
return b.makeImageRef(manifest.GuessMIMEType(b.Manifest), true, false, compress, names, layerID)
func (b *Builder) makeImageImageRef(compress archive.Compression, names []string, layerID string, historyTimestamp *time.Time) (types.ImageReference, error) {
return b.makeImageRef(manifest.GuessMIMEType(b.Manifest), true, false, compress, names, layerID, historyTimestamp)
}