build, commit: set the OCI ...created annotation on OCI images
When building or committing an image in OCI format, default to setting the org.opencontainers.image.created annotation to the value used in the image's config blob for the image's creation date. The behavior can be controlled using the new --created-annotation flag. Add --annotation and --unsetannotation flags to `buildah commit` which mimic the same flags for `buildah build`. Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
This commit is contained in:
parent
e6375b3c28
commit
5968d82047
|
@ -66,6 +66,9 @@ type commitInputOptions struct {
|
|||
encryptLayers []int
|
||||
unsetenvs []string
|
||||
addFile []string
|
||||
unsetAnnotation []string
|
||||
annotation []string
|
||||
createdAnnotation bool
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
@ -187,6 +190,11 @@ func commitListFlagSet(cmd *cobra.Command, opts *commitInputOptions) {
|
|||
|
||||
flags.StringSliceVar(&opts.unsetenvs, "unsetenv", nil, "unset env from final image")
|
||||
_ = cmd.RegisterFlagCompletionFunc("unsetenv", completion.AutocompleteNone)
|
||||
flags.StringSliceVar(&opts.unsetAnnotation, "unsetannotation", nil, "unset annotation when inheriting annotations from base image")
|
||||
_ = cmd.RegisterFlagCompletionFunc("unsetannotation", completion.AutocompleteNone)
|
||||
flags.StringArrayVar(&opts.annotation, "annotation", []string{}, "set metadata for an image (default [])")
|
||||
_ = cmd.RegisterFlagCompletionFunc("annotation", completion.AutocompleteNone)
|
||||
flags.BoolVar(&opts.createdAnnotation, "created-annotation", true, `set an "org.opencontainers.image.created" annotation in the image`)
|
||||
}
|
||||
|
||||
func commitCmd(c *cobra.Command, args []string, iopts commitInputOptions) error {
|
||||
|
@ -311,6 +319,9 @@ func commitCmd(c *cobra.Command, args []string, iopts commitInputOptions) error
|
|||
OverrideChanges: iopts.changes,
|
||||
OverrideConfig: overrideConfig,
|
||||
ExtraImageContent: addFiles,
|
||||
UnsetAnnotations: iopts.unsetAnnotation,
|
||||
Annotations: iopts.annotation,
|
||||
CreatedAnnotation: types.NewOptionalBool(iopts.createdAnnotation),
|
||||
}
|
||||
exclusiveFlags := 0
|
||||
if c.Flag("reference-time").Changed {
|
||||
|
|
15
commit.go
15
commit.go
|
@ -104,7 +104,8 @@ type CommitOptions struct {
|
|||
OmitLayerHistoryEntry bool
|
||||
// OmitTimestamp forces epoch 0 as created timestamp to allow for
|
||||
// deterministic, content-addressable builds.
|
||||
// Deprecated use HistoryTimestamp instead.
|
||||
// Deprecated: use HistoryTimestamp or SourceDateEpoch (possibly with
|
||||
// RewriteTimestamp) instead.
|
||||
OmitTimestamp bool
|
||||
// SignBy is the fingerprint of a GPG key to use for signing the image.
|
||||
SignBy string
|
||||
|
@ -130,7 +131,8 @@ type CommitOptions struct {
|
|||
// contents of a rootfs.
|
||||
ConfidentialWorkloadOptions ConfidentialWorkloadOptions
|
||||
// UnsetEnvs is a list of environments to not add to final image.
|
||||
// Deprecated: use UnsetEnv() before committing instead.
|
||||
// Deprecated: use UnsetEnv() before committing, or set OverrideChanges
|
||||
// instead.
|
||||
UnsetEnvs []string
|
||||
// OverrideConfig is an optional Schema2Config which can override parts
|
||||
// of the working container's configuration for the image that is being
|
||||
|
@ -167,6 +169,15 @@ type CommitOptions struct {
|
|||
// corresponding members in the Builder object, in the committed image
|
||||
// is not guaranteed.
|
||||
PrependedLinkedLayers, AppendedLinkedLayers []LinkedLayer
|
||||
// UnsetAnnotations is a list of annotations (names only) to withhold
|
||||
// from the image.
|
||||
UnsetAnnotations []string
|
||||
// Annotations is a list of annotations (in the form "key=value") to
|
||||
// add to the image.
|
||||
Annotations []string
|
||||
// CreatedAnnotation controls whether or not an "org.opencontainers.image.created"
|
||||
// annotation is present in the output image.
|
||||
CreatedAnnotation types.OptionalBool
|
||||
}
|
||||
|
||||
// LinkedLayer combines a history entry with the location of either a directory
|
||||
|
|
|
@ -49,7 +49,8 @@ type CommonBuildOptions struct {
|
|||
CPUSetMems string
|
||||
// HTTPProxy determines whether *_proxy env vars from the build host are passed into the container.
|
||||
HTTPProxy bool
|
||||
// IdentityLabel if set ensures that default `io.buildah.version` label is not applied to build image.
|
||||
// IdentityLabel if set controls whether or not a `io.buildah.version` label is added to the built image.
|
||||
// Setting this to false does not clear the label if it would be inherited from the base image.
|
||||
IdentityLabel types.OptionalBool
|
||||
// Memory is the upper limit (in bytes) on how much memory running containers can use.
|
||||
Memory int64
|
||||
|
@ -414,4 +415,7 @@ type BuildOptions struct {
|
|||
CompatLayerOmissions types.OptionalBool
|
||||
// NoPivotRoot inhibits the usage of pivot_root when setting up the rootfs
|
||||
NoPivotRoot bool
|
||||
// CreatedAnnotation controls whether or not an "org.opencontainers.image.created"
|
||||
// annotation is present in the output image.
|
||||
CreatedAnnotation types.OptionalBool
|
||||
}
|
||||
|
|
|
@ -297,6 +297,16 @@ If you have four memory nodes on your system (0-3), use `--cpuset-mems=0,1`
|
|||
then processes in your container will only use memory from the first
|
||||
two memory nodes.
|
||||
|
||||
**--created-annotation**
|
||||
|
||||
Add an image *annotation* (see also **--annotation**) to the image metadata
|
||||
setting "org.opencontainers.image.created" to the current time, or to the
|
||||
datestamp specified to the **--source-date-epoch** or **--timestamp** flag,
|
||||
if either was used. If *false*, no such annotation will be present in the
|
||||
written image.
|
||||
|
||||
Note: this information is not present in Docker image formats, so it is discarded when writing images in Docker formats.
|
||||
|
||||
**--creds** *creds*
|
||||
|
||||
The [username[:password]] to use to authenticate with the registry if required.
|
||||
|
@ -508,6 +518,8 @@ than once, attempting to use this option will trigger an error.
|
|||
**--inherit-annotations** *bool-value*
|
||||
|
||||
Inherit the annotations from the base image or base stages. (default true).
|
||||
Use cases which set this flag to *false* may need to do the same for the
|
||||
**--created-annotation** flag.
|
||||
|
||||
**--inherit-labels** *bool-value*
|
||||
|
||||
|
|
|
@ -29,6 +29,13 @@ will be used. The new file will be owned by UID 0, GID 0, have 0644
|
|||
permissions, and be given the timestamp specified to the **--timestamp** option
|
||||
if it is specified. This option can be specified multiple times.
|
||||
|
||||
**--annotation** *annotation[=value]*
|
||||
|
||||
Add an image *annotation* (e.g. annotation=*value*) to the image metadata. Can be used multiple times.
|
||||
If *annotation* is named, but neither `=` nor a `value` is provided, then the *annotation* is set to an empty value.
|
||||
|
||||
Note: this information is not present in Docker image formats, so it is discarded when writing images in Docker formats.
|
||||
|
||||
**--authfile** *path*
|
||||
|
||||
Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json. See containers-auth.json(5) for more information. This file is created using `buildah login`.
|
||||
|
@ -55,6 +62,16 @@ Read a JSON-encoded version of an image configuration object from the specified
|
|||
file, and merge the values from it with the configuration of the image being
|
||||
committed.
|
||||
|
||||
**--created-annotation**
|
||||
|
||||
Add an image *annotation* (see also **--annotation**) to the image metadata
|
||||
setting "org.opencontainers.image.created" to the current time, or to the
|
||||
datestamp specified to the **--source-date-epoch** or **--timestamp** flag,
|
||||
if either was used. If *false*, no such annotation will be present in the
|
||||
written image.
|
||||
|
||||
Note: this information is not present in Docker image formats, so it is discarded when writing images in Docker formats.
|
||||
|
||||
**--creds** *creds*
|
||||
|
||||
The [username[:password]] to use to authenticate with the registry if required.
|
||||
|
@ -350,6 +367,10 @@ not affect the timestamps of layer contents.
|
|||
|
||||
Require HTTPS and verification of certificates when talking to container registries (defaults to true). TLS verification cannot be used when talking to an insecure registry.
|
||||
|
||||
**--unsetannotation** *annotation*
|
||||
|
||||
Unset the image annotation, causing the annotation not to be inherited from the base image.
|
||||
|
||||
**--unsetenv** *env*
|
||||
|
||||
Unset environment variables from the final image.
|
||||
|
|
25
image.go
25
image.go
|
@ -104,6 +104,9 @@ type containerImageRef struct {
|
|||
extraImageContent map[string]string
|
||||
compatSetParent types.OptionalBool
|
||||
layerExclusions []copier.ConditionalRemovePath
|
||||
unsetAnnotations []string
|
||||
setAnnotations []string
|
||||
createdAnnotation types.OptionalBool
|
||||
}
|
||||
|
||||
type blobLayerInfo struct {
|
||||
|
@ -590,6 +593,23 @@ func (i *containerImageRef) newOCIManifestBuilder() (manifestBuilder, error) {
|
|||
}
|
||||
|
||||
// Return partial manifest. The Layers lists will be populated later.
|
||||
annotations := make(map[string]string)
|
||||
maps.Copy(annotations, i.annotations)
|
||||
switch i.createdAnnotation {
|
||||
case types.OptionalBoolFalse:
|
||||
delete(annotations, v1.AnnotationCreated)
|
||||
default:
|
||||
fallthrough
|
||||
case types.OptionalBoolTrue, types.OptionalBoolUndefined:
|
||||
annotations[v1.AnnotationCreated] = created.UTC().Format(time.RFC3339Nano)
|
||||
}
|
||||
for _, k := range i.unsetAnnotations {
|
||||
delete(annotations, k)
|
||||
}
|
||||
for _, kv := range i.setAnnotations {
|
||||
k, v, _ := strings.Cut(kv, "=")
|
||||
annotations[k] = v
|
||||
}
|
||||
return &ociManifestBuilder{
|
||||
i: i,
|
||||
// The default layer media type assumes no compression.
|
||||
|
@ -604,7 +624,7 @@ func (i *containerImageRef) newOCIManifestBuilder() (manifestBuilder, error) {
|
|||
MediaType: v1.MediaTypeImageConfig,
|
||||
},
|
||||
Layers: []v1.Descriptor{},
|
||||
Annotations: i.annotations,
|
||||
Annotations: annotations,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
@ -1525,6 +1545,8 @@ func (b *Builder) makeContainerImageRef(options CommitOptions) (*containerImageR
|
|||
layerLatestModTime: layerLatestModTime,
|
||||
historyComment: b.HistoryComment(),
|
||||
annotations: b.Annotations(),
|
||||
setAnnotations: slices.Clone(options.Annotations),
|
||||
unsetAnnotations: slices.Clone(options.UnsetAnnotations),
|
||||
preferredManifestType: manifestType,
|
||||
squash: options.Squash,
|
||||
confidentialWorkload: options.ConfidentialWorkloadOptions,
|
||||
|
@ -1543,6 +1565,7 @@ func (b *Builder) makeContainerImageRef(options CommitOptions) (*containerImageR
|
|||
extraImageContent: maps.Clone(options.ExtraImageContent),
|
||||
compatSetParent: options.CompatSetParent,
|
||||
layerExclusions: layerExclusions,
|
||||
createdAnnotation: options.CreatedAnnotation,
|
||||
}
|
||||
if ref.created != nil {
|
||||
for i := range ref.preEmptyLayers {
|
||||
|
|
|
@ -171,6 +171,7 @@ type Executor struct {
|
|||
noPivotRoot bool
|
||||
sourceDateEpoch *time.Time
|
||||
rewriteTimestamp bool
|
||||
createdAnnotation types.OptionalBool
|
||||
}
|
||||
|
||||
type imageTypeAndHistoryAndDiffIDs struct {
|
||||
|
@ -342,6 +343,7 @@ func newExecutor(logger *logrus.Logger, logPrefix string, store storage.Store, o
|
|||
noPivotRoot: options.NoPivotRoot,
|
||||
sourceDateEpoch: options.SourceDateEpoch,
|
||||
rewriteTimestamp: options.RewriteTimestamp,
|
||||
createdAnnotation: options.CreatedAnnotation,
|
||||
}
|
||||
// sort unsetAnnotations because we will later write these
|
||||
// values to the history of the image therefore we want to
|
||||
|
|
|
@ -2505,6 +2505,9 @@ func (s *StageExecutor) commit(ctx context.Context, createdBy string, emptyLayer
|
|||
SourceDateEpoch: s.executor.sourceDateEpoch,
|
||||
RewriteTimestamp: s.executor.rewriteTimestamp,
|
||||
CompatLayerOmissions: s.executor.compatLayerOmissions,
|
||||
UnsetAnnotations: s.executor.unsetAnnotations,
|
||||
Annotations: s.executor.annotations,
|
||||
CreatedAnnotation: s.executor.createdAnnotation,
|
||||
}
|
||||
if finalInstruction {
|
||||
options.ConfidentialWorkloadOptions = s.executor.confidentialWorkload
|
||||
|
|
|
@ -378,6 +378,7 @@ func GenBuildOptions(c *cobra.Command, inputArgs []string, iopts BuildOptions) (
|
|||
Compression: compression,
|
||||
ConfigureNetwork: networkPolicy,
|
||||
ContextDirectory: contextDir,
|
||||
CreatedAnnotation: types.NewOptionalBool(iopts.CreatedAnnotation),
|
||||
Devices: iopts.Devices,
|
||||
DropCapabilities: iopts.CapDrop,
|
||||
Err: stderr,
|
||||
|
|
|
@ -127,6 +127,7 @@ type BudResults struct {
|
|||
CompatVolumes bool
|
||||
SourceDateEpoch string
|
||||
RewriteTimestamp bool
|
||||
CreatedAnnotation bool
|
||||
}
|
||||
|
||||
// FromAndBugResults represents the results for common flags
|
||||
|
@ -240,6 +241,7 @@ func GetBudFlags(flags *BudResults) pflag.FlagSet {
|
|||
fs.BoolVar(&flags.InheritLabels, "inherit-labels", true, "inherit the labels from the base image or base stages.")
|
||||
fs.BoolVar(&flags.InheritAnnotations, "inherit-annotations", true, "inherit the annotations from the base image or base stages.")
|
||||
fs.StringArrayVar(&flags.CPPFlags, "cpp-flag", []string{}, "set additional flag to pass to C preprocessor (cpp)")
|
||||
fs.BoolVar(&flags.CreatedAnnotation, "created-annotation", true, `set an "org.opencontainers.image.created" annotation in the image`)
|
||||
fs.StringVar(&flags.Creds, "creds", "", "use `[username[:password]]` for accessing the registry")
|
||||
fs.StringVarP(&flags.CWOptions, "cw", "", "", "confidential workload `options`")
|
||||
fs.BoolVarP(&flags.DisableCompression, "disable-compression", "D", true, "don't compress layers by default")
|
||||
|
@ -326,7 +328,7 @@ newer: only pull base and SBOM scanner images when newer images exist on the r
|
|||
fs.String("variant", "", "override the `variant` of the specified image")
|
||||
fs.StringSliceVar(&flags.UnsetEnvs, "unsetenv", nil, "unset environment variable from final image")
|
||||
fs.StringSliceVar(&flags.UnsetLabels, "unsetlabel", nil, "unset label when inheriting labels from base image")
|
||||
fs.StringSliceVar(&flags.UnsetAnnotations, "unsetannotation", nil, "unset annotation when inheriting annotation from base image")
|
||||
fs.StringSliceVar(&flags.UnsetAnnotations, "unsetannotation", nil, "unset annotation when inheriting annotations from base image")
|
||||
return fs
|
||||
}
|
||||
|
||||
|
|
|
@ -161,7 +161,7 @@ _EOF
|
|||
assert "$output" != "$not_want_output" "expected some annotations to be set in base image $base"
|
||||
|
||||
## Since we are inheriting no annotations, built image should not contain any annotations.
|
||||
run_buildah build $WITH_POLICY_JSON --inherit-annotations=false -t $target --from $base $BUDFILES/base-with-labels
|
||||
run_buildah build $WITH_POLICY_JSON --inherit-annotations=false --created-annotation=false -t $target --from $base $BUDFILES/base-with-labels
|
||||
|
||||
# no annotations should be inherited from base image
|
||||
want_output='map[]'
|
||||
|
@ -169,7 +169,7 @@ _EOF
|
|||
expect_output "$want_output"
|
||||
|
||||
## Build again but set a new annotation and don't inherit annotations from base image
|
||||
run_buildah build $WITH_POLICY_JSON --inherit-annotations=false --annotation hello=world -t $target --from $base $BUDFILES/base-with-labels
|
||||
run_buildah build $WITH_POLICY_JSON --inherit-annotations=false --created-annotation=false --annotation hello=world -t $target --from $base $BUDFILES/base-with-labels
|
||||
|
||||
# no annotations should be inherited from base image
|
||||
want_output='map["hello":"world"]'
|
||||
|
@ -177,13 +177,13 @@ _EOF
|
|||
expect_output "$want_output"
|
||||
|
||||
## Try similar thing with another Containerfile
|
||||
run_buildah build $WITH_POLICY_JSON --inherit-annotations=false -t $target -f $BUDFILES/base-with-labels/Containerfile2
|
||||
run_buildah build $WITH_POLICY_JSON --inherit-annotations=false --created-annotation=false -t $target -f $BUDFILES/base-with-labels/Containerfile2
|
||||
# no annotations should be inherited from base image
|
||||
want_output='map[]'
|
||||
run_buildah inspect --format '{{printf "%q" .ImageAnnotations}}' $target
|
||||
expect_output "$want_output"
|
||||
|
||||
run_buildah build $WITH_POLICY_JSON --inherit-annotations=false --annotation hello=world -t $target -f $BUDFILES/base-with-labels/Containerfile2
|
||||
run_buildah build $WITH_POLICY_JSON --inherit-annotations=false --created-annotation=false --annotation hello=world -t $target -f $BUDFILES/base-with-labels/Containerfile2
|
||||
# no annotations should be inherited from base image
|
||||
want_output='map["hello":"world"]'
|
||||
run_buildah inspect --format '{{printf "%q" .ImageAnnotations}}' $target
|
||||
|
@ -212,7 +212,7 @@ _EOF
|
|||
cmp ${TEST_SCRATCH_DIR}/iid1 ${TEST_SCRATCH_DIR}/iid2
|
||||
|
||||
## Since we are inheriting no annotations, this should not use previous image present in the cache.
|
||||
run_buildah build $WITH_POLICY_JSON --layers --inherit-annotations=false -t $target --from $base $BUDFILES/base-with-labels
|
||||
run_buildah build $WITH_POLICY_JSON --layers --inherit-annotations=false --created-annotation=false -t $target --from $base $BUDFILES/base-with-labels
|
||||
## should not contain `Using Cache`
|
||||
assert "$output" !~ "Using cache"
|
||||
|
||||
|
@ -222,7 +222,7 @@ _EOF
|
|||
expect_output "$want_output"
|
||||
|
||||
## Build again but set a new annotation and don't inherit annotations from base image
|
||||
run_buildah build $WITH_POLICY_JSON --layers --inherit-annotations=false --annotation hello=world -t $target --from $base $BUDFILES/base-with-labels
|
||||
run_buildah build $WITH_POLICY_JSON --layers --inherit-annotations=false --created-annotation=false --annotation hello=world -t $target --from $base $BUDFILES/base-with-labels
|
||||
|
||||
# no annotations should be inherited from base image
|
||||
want_output='map["hello":"world"]'
|
||||
|
@ -240,7 +240,7 @@ _EOF
|
|||
cmp ${TEST_SCRATCH_DIR}/iid1 ${TEST_SCRATCH_DIR}/iid2
|
||||
|
||||
## Since we are inheriting no annotations, this should not use previous image present in the cache.
|
||||
run_buildah build $WITH_POLICY_JSON --layers --inherit-annotations=false -t $target -f $BUDFILES/base-with-labels/Containerfile2
|
||||
run_buildah build $WITH_POLICY_JSON --layers --inherit-annotations=false --created-annotation=false -t $target -f $BUDFILES/base-with-labels/Containerfile2
|
||||
## but this time since 1st instruction is cached it should still use cache for some part, only annotations should not be there
|
||||
expect_output --substring " Using cache"
|
||||
|
||||
|
@ -250,7 +250,7 @@ _EOF
|
|||
expect_output "$want_output"
|
||||
|
||||
## Build again but set a new annotation and don't inherit annotations from base image
|
||||
run_buildah build $WITH_POLICY_JSON --layers --inherit-annotations=false --annotation hello=world -t $target -f $BUDFILES/base-with-labels/Containerfile2
|
||||
run_buildah build $WITH_POLICY_JSON --layers --inherit-annotations=false --created-annotation=false --annotation hello=world -t $target -f $BUDFILES/base-with-labels/Containerfile2
|
||||
## but this time since 1st instruction is cached it should still use cache for some part, only last instruction will be changed since we are adding
|
||||
## annotations to it
|
||||
expect_output --substring " Using cache"
|
||||
|
@ -2837,7 +2837,7 @@ _EOF
|
|||
assert "$output" != "$not_want_output" "expected some annotations to be set in base image $base"
|
||||
|
||||
annotations=$(buildah inspect --format '{{ range $key, $value := .ImageAnnotations }}{{ $key }} {{end}}' $base)
|
||||
annotationflags="--annotation hello=world"
|
||||
annotationflags="--annotation hello=world --unsetannotation=org.opencontainers.image.created"
|
||||
for annotation in $annotations; do
|
||||
if test $annotation != io.buildah.version ; then
|
||||
annotationflags="$annotationflags --unsetannotation $annotation"
|
||||
|
@ -2875,7 +2875,7 @@ _EOF
|
|||
cmp ${TEST_SCRATCH_DIR}/iid1 ${TEST_SCRATCH_DIR}/iid2
|
||||
|
||||
annotations=$(buildah inspect --format '{{ range $key, $value := .ImageAnnotations }}{{ $key }} {{end}}' $base)
|
||||
annotationflags="--annotation hello=world"
|
||||
annotationflags="--annotation hello=world --unsetannotation=org.opencontainers.image.created"
|
||||
for annotation in $annotations; do
|
||||
if test $annotation != io.buildah.version ; then
|
||||
annotationflags="$annotationflags --unsetannotation $annotation"
|
||||
|
@ -2908,7 +2908,7 @@ _EOF
|
|||
assert "$output" != "$not_want_output" "expected some annotations to be set in base image $base"
|
||||
|
||||
annotations=$(buildah inspect --format '{{ range $key, $value := .ImageAnnotations }}{{ $key }} {{end}}' $base)
|
||||
annotationflags="--annotation hello=world"
|
||||
annotationflags="--annotation hello=world --created-annotation=false"
|
||||
for annotation in $annotations; do
|
||||
if test $annotation != io.buildah.version ; then
|
||||
annotationflags="$annotationflags --unsetannotation $annotation"
|
||||
|
@ -8079,3 +8079,41 @@ EOF
|
|||
assert $hostname = sandbox "expected the hostname to be the static value 'sandbox'"
|
||||
done
|
||||
}
|
||||
|
||||
@test "bud-sets-created-annotation" {
|
||||
_prefetch busybox
|
||||
mkdir ${TEST_SCRATCH_DIR}/buildcontext
|
||||
cat > ${TEST_SCRATCH_DIR}/buildcontext/Dockerfile << _EOF
|
||||
FROM busybox
|
||||
RUN pwd
|
||||
_EOF
|
||||
for flagdir in default: timestamp:--timestamp=0 sde:--source-date-epoch=0 suppressed:--unsetannotation=org.opencontainers.image.created specific:--created-annotation=false explicit:--created-annotation=true ; do
|
||||
local flag=${flagdir##*:}
|
||||
local subdir=${flagdir%%:*}
|
||||
run_buildah build --layers --no-cache $flag -t oci:${TEST_SCRATCH_DIR}/$subdir ${TEST_SCRATCH_DIR}/buildcontext
|
||||
local manifest=${TEST_SCRATCH_DIR}/$subdir/$(oci_image_manifest ${TEST_SCRATCH_DIR}/$subdir)
|
||||
run jq -r '.annotations["org.opencontainers.image.created"]' "$manifest"
|
||||
assert $status -eq 0
|
||||
echo "$output"
|
||||
local manifestcreated="$output"
|
||||
local config=${TEST_SCRATCH_DIR}/$subdir/$(oci_image_config ${TEST_SCRATCH_DIR}/$subdir)
|
||||
run jq -r '.created' "$config"
|
||||
assert $status -eq 0
|
||||
echo "$output"
|
||||
local configcreated="$output"
|
||||
if [[ "$flag" =~ "=0" ]]; then
|
||||
assert $manifestcreated = $configcreated "manifest and config disagree on the image's created-time"
|
||||
assert $manifestcreated = "1970-01-01T00:00:00Z"
|
||||
elif [[ "$flag" =~ "unsetannotation" ]]; then
|
||||
assert $configcreated != ""
|
||||
assert $manifestcreated = "null"
|
||||
elif [[ "$flag" =~ "created-annotation=false" ]]; then
|
||||
assert $configcreated != ""
|
||||
assert $manifestcreated = "null"
|
||||
else
|
||||
assert $manifestcreated = $configcreated "manifest and config disagree on the image's created-time"
|
||||
assert $manifestcreated != ""
|
||||
assert $manifestcreated != "1970-01-01T00:00:00Z"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
|
|
@ -580,3 +580,47 @@ load helpers
|
|||
assert "$output" != "$timestamp" "unexpected datestamp on $file in layer"
|
||||
done
|
||||
}
|
||||
|
||||
@test "commit-sets-created-annotation" {
|
||||
_prefetch busybox
|
||||
run_buildah from -q busybox
|
||||
local cid="$output"
|
||||
for annotation in a=b c=d ; do
|
||||
local subdir=${annotation%%=*}
|
||||
run_buildah commit --annotation $annotation "$cid" oci:${TEST_SCRATCH_DIR}/$subdir
|
||||
local manifest=${TEST_SCRATCH_DIR}/$subdir/$(oci_image_manifest ${TEST_SCRATCH_DIR}/$subdir)
|
||||
run jq -r '.annotations["'$subdir'"]' "$manifest"
|
||||
assert $status -eq 0
|
||||
echo "$output"
|
||||
assert "$output" = ${annotation##*=}
|
||||
done
|
||||
for flagdir in default: timestamp:--timestamp=0 sde:--source-date-epoch=0 suppressed:--unsetannotation=org.opencontainers.image.created specific:--created-annotation=false explicit:--created-annotation=true ; do
|
||||
local flag=${flagdir##*:}
|
||||
local subdir=${flagdir%%:*}
|
||||
run_buildah commit $flag "$cid" oci:${TEST_SCRATCH_DIR}/$subdir
|
||||
local manifest=${TEST_SCRATCH_DIR}/$subdir/$(oci_image_manifest ${TEST_SCRATCH_DIR}/$subdir)
|
||||
run jq -r '.annotations["org.opencontainers.image.created"]' "$manifest"
|
||||
assert $status -eq 0
|
||||
echo "$output"
|
||||
local manifestcreated="$output"
|
||||
local config=${TEST_SCRATCH_DIR}/$subdir/$(oci_image_config ${TEST_SCRATCH_DIR}/$subdir)
|
||||
run jq -r '.created' "$config"
|
||||
assert $status -eq 0
|
||||
echo "$output"
|
||||
local configcreated="$output"
|
||||
if [[ "$flag" =~ "=0" ]]; then
|
||||
assert $manifestcreated = $configcreated "manifest and config disagree on the image's created-time"
|
||||
assert $manifestcreated = "1970-01-01T00:00:00Z"
|
||||
elif [[ "$flag" =~ "unsetannotation" ]]; then
|
||||
assert $configcreated != ""
|
||||
assert $manifestcreated = "null"
|
||||
elif [[ "$flag" =~ "created-annotation=false" ]]; then
|
||||
assert $configcreated != ""
|
||||
assert $manifestcreated = "null"
|
||||
else
|
||||
assert $manifestcreated = $configcreated "manifest and config disagree on the image's created-time"
|
||||
assert $manifestcreated != ""
|
||||
assert $manifestcreated != "1970-01-01T00:00:00Z"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
|
|
@ -209,7 +209,7 @@ function check_matrix() {
|
|||
$cid
|
||||
|
||||
run_buildah commit --format docker $WITH_POLICY_JSON $cid scratch-image-docker
|
||||
run_buildah commit --format oci $WITH_POLICY_JSON $cid scratch-image-oci
|
||||
run_buildah commit --created-annotation=false --format oci $WITH_POLICY_JSON $cid scratch-image-oci
|
||||
|
||||
run_buildah inspect --type=image --format '{{.ImageAnnotations}}' scratch-image-oci
|
||||
expect_output "map[]"
|
||||
|
|
|
@ -914,6 +914,18 @@ function oci_image_manifest_digest() {
|
|||
echo "$output"
|
||||
}
|
||||
|
||||
########################
|
||||
# oci_image_manifest #
|
||||
########################
|
||||
# prints the relative path of the manifest for the main image in an OCI
|
||||
# layout in "$1"
|
||||
function oci_image_manifest() {
|
||||
local diff_id=$(oci_image_manifest_digest "$@")
|
||||
local alg=${diff_id%%:*}
|
||||
local val=${diff_id##*:}
|
||||
echo blobs/"$alg"/"$val"
|
||||
}
|
||||
|
||||
#############################
|
||||
# oci_image_config_digest #
|
||||
#############################
|
||||
|
|
Loading…
Reference in New Issue