mirror of
https://github.com/containers/buildah.git
synced 2026-02-05 09:45:38 +01:00
buildah manifest: add artifact-related options
Add functionality for creating artifact manifests and adding them to image indexes. `buildah manifest add` gets a `--artifact` option for telling it to create artifact manifests, and `--artifact-type`, `--artifact-config`, `--artifact-config-type`, `--artifact-layer-type`, `--artifact-exclude-titles`, and `--subject` options to fine-tune the contents of the artifact manifests it creates. Add a `--index` flag to `buildah manifest annotate` so that it can be told to set annotations on the index itself instead of on one of the entries in the image index. Add a `--subject` flag to `buildah manifest annotate` for setting the `subject` field of an image index. Add a `--annotation` flag to `buildah manifest create` to allow for adding annotations to the new image index. Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
This commit is contained in:
@@ -26,6 +26,7 @@ import (
|
||||
"github.com/hashicorp/go-multierror"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -33,12 +34,17 @@ import (
|
||||
type manifestCreateOpts struct {
|
||||
os, arch string
|
||||
all, tlsVerify, insecure, amend bool
|
||||
annotations []string
|
||||
}
|
||||
|
||||
type manifestAddOpts struct {
|
||||
authfile, certDir, creds, os, arch, variant, osVersion string
|
||||
features, osFeatures, annotations []string
|
||||
tlsVerify, insecure, all bool
|
||||
artifact, artifactExcludeTitles bool
|
||||
artifactType, artifactLayerType string
|
||||
artifactConfigType, artifactConfigFile string
|
||||
artifactSubject string
|
||||
}
|
||||
|
||||
type manifestRemoveOpts struct{}
|
||||
@@ -46,6 +52,8 @@ type manifestRemoveOpts struct{}
|
||||
type manifestAnnotateOpts struct {
|
||||
os, arch, variant, osVersion string
|
||||
features, osFeatures, annotations []string
|
||||
index bool
|
||||
subject string
|
||||
}
|
||||
|
||||
type manifestInspectOpts struct {
|
||||
@@ -57,9 +65,9 @@ func init() {
|
||||
var (
|
||||
manifestDescription = "\n Creates, modifies, and pushes manifest lists and image indexes."
|
||||
manifestCreateDescription = "\n Creates manifest lists and image indexes."
|
||||
manifestAddDescription = "\n Adds an image to a manifest list or image index."
|
||||
manifestRemoveDescription = "\n Removes an image from a manifest list or image index."
|
||||
manifestAnnotateDescription = "\n Adds or updates information about an entry in a manifest list or image index."
|
||||
manifestAddDescription = "\n Adds an image or artifact to a manifest list or image index."
|
||||
manifestRemoveDescription = "\n Removes an image or artifact from a manifest list or image index."
|
||||
manifestAnnotateDescription = "\n Adds or updates information about an image index or an entry in a manifest list or image index."
|
||||
manifestInspectDescription = "\n Display the contents of a manifest list or image index."
|
||||
manifestPushDescription = "\n Pushes manifest lists and image indexes to registries."
|
||||
manifestRmDescription = "\n Remove one or more manifest lists from local storage."
|
||||
@@ -103,6 +111,7 @@ func init() {
|
||||
flags := manifestCreateCommand.Flags()
|
||||
flags.BoolVar(&manifestCreateOpts.all, "all", false, "add all of the lists' images if the images to add are lists")
|
||||
flags.BoolVar(&manifestCreateOpts.amend, "amend", false, "modify an existing list if one with the desired name already exists")
|
||||
flags.StringSliceVar(&manifestCreateOpts.annotations, "annotation", nil, "set an `annotation` for the image index")
|
||||
flags.StringVar(&manifestCreateOpts.os, "os", "", "if any of the specified images is a list, choose the one for `os`")
|
||||
if err := flags.MarkHidden("os"); err != nil {
|
||||
panic(fmt.Sprintf("error marking --os as hidden: %v", err))
|
||||
@@ -121,17 +130,25 @@ func init() {
|
||||
|
||||
manifestAddCommand := &cobra.Command{
|
||||
Use: "add",
|
||||
Short: "Add images to a manifest list or image index",
|
||||
Short: "Add an image or artifact to a manifest list or image index",
|
||||
Long: manifestAddDescription,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return manifestAddCmd(cmd, args, manifestAddOpts)
|
||||
},
|
||||
Example: `buildah manifest add mylist:v1.11 image:v1.11-amd64
|
||||
buildah manifest add mylist:v1.11 transport:imageName`,
|
||||
buildah manifest add mylist:v1.11 transport:imageName
|
||||
buildah manifest add --artifact --artifact-type text/plain mylist:v1.11 ./somefile.txt ./somefile.png`,
|
||||
Args: cobra.MinimumNArgs(2),
|
||||
}
|
||||
manifestAddCommand.SetUsageTemplate(UsageTemplate())
|
||||
flags = manifestAddCommand.Flags()
|
||||
flags.BoolVar(&manifestAddOpts.artifact, "artifact", false, "treat the argument as a filename and add it as an artifact")
|
||||
flags.StringVar(&manifestAddOpts.artifactType, "artifact-type", "", "artifact manifest media type")
|
||||
flags.StringVar(&manifestAddOpts.artifactConfigType, "artifact-config-type", imgspecv1.DescriptorEmptyJSON.MediaType, "artifact config media type")
|
||||
flags.StringVar(&manifestAddOpts.artifactConfigFile, "artifact-config", "", "artifact config file")
|
||||
flags.StringVar(&manifestAddOpts.artifactLayerType, "artifact-layer-type", "", "artifact layer media type")
|
||||
flags.BoolVar(&manifestAddOpts.artifactExcludeTitles, "artifact-exclude-titles", false, fmt.Sprintf(`refrain from setting %q annotations on "layers"`, v1.AnnotationTitle))
|
||||
flags.StringVar(&manifestAddOpts.artifactSubject, "artifact-subject", "", "artifact subject reference")
|
||||
flags.StringVar(&manifestAddOpts.authfile, "authfile", auth.GetDefaultAuthFile(), "path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
|
||||
flags.StringVar(&manifestAddOpts.certDir, "cert-dir", "", "use certificates at the specified path to access the registry")
|
||||
flags.StringVar(&manifestAddOpts.creds, "creds", "", "use `[username[:password]]` for accessing the registry")
|
||||
@@ -141,7 +158,7 @@ func init() {
|
||||
flags.StringVar(&manifestAddOpts.osVersion, "os-version", "", "override the OS `version` of the specified image")
|
||||
flags.StringSliceVar(&manifestAddOpts.features, "features", nil, "override the `features` of the specified image")
|
||||
flags.StringSliceVar(&manifestAddOpts.osFeatures, "os-features", nil, "override the OS `features` of the specified image")
|
||||
flags.StringSliceVar(&manifestAddOpts.annotations, "annotation", nil, "set an `annotation` for the specified image")
|
||||
flags.StringSliceVar(&manifestAddOpts.annotations, "annotation", nil, "set an `annotation` for the specified image or artifact")
|
||||
flags.BoolVar(&manifestAddOpts.insecure, "insecure", false, "neither require HTTPS nor verify certificates when accessing the registry. TLS verification cannot be used when talking to an insecure registry.")
|
||||
if err := flags.MarkHidden("insecure"); err != nil {
|
||||
panic(fmt.Sprintf("error marking insecure as hidden: %v", err))
|
||||
@@ -185,16 +202,18 @@ func init() {
|
||||
return manifestAnnotateCmd(cmd, args, manifestAnnotateOpts)
|
||||
},
|
||||
Example: `buildah manifest annotate --annotation left=right mylist:v1.11 image:v1.11-amd64`,
|
||||
Args: cobra.MinimumNArgs(2),
|
||||
Args: cobra.RangeArgs(1, 2),
|
||||
}
|
||||
flags = manifestAnnotateCommand.Flags()
|
||||
flags.StringVar(&manifestAnnotateOpts.os, "os", "", "override the `OS` of the specified image")
|
||||
flags.StringVar(&manifestAnnotateOpts.arch, "arch", "", "override the `Architecture` of the specified image")
|
||||
flags.BoolVar(&manifestAnnotateOpts.index, "index", false, "set annotations or artifact type for the index itself instead of for an entry in the index")
|
||||
flags.StringVar(&manifestAnnotateOpts.variant, "variant", "", "override the `Variant` of the specified image")
|
||||
flags.StringVar(&manifestAnnotateOpts.osVersion, "os-version", "", "override the os `version` of the specified image")
|
||||
flags.StringSliceVar(&manifestAnnotateOpts.features, "features", nil, "override the `features` of the specified image")
|
||||
flags.StringSliceVar(&manifestAnnotateOpts.osFeatures, "os-features", nil, "override the os `features` of the specified image")
|
||||
flags.StringSliceVar(&manifestAnnotateOpts.annotations, "annotation", nil, "set an `annotation` for the specified image")
|
||||
flags.StringVar(&manifestAnnotateOpts.subject, "subject", "", "set a subject for the image index")
|
||||
manifestAnnotateCommand.SetUsageTemplate(UsageTemplate())
|
||||
manifestCommand.AddCommand(manifestAnnotateCommand)
|
||||
|
||||
@@ -327,7 +346,7 @@ func manifestCreateCmd(c *cobra.Command, args []string, opts manifestCreateOpts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encountered while expanding image name %q: %w", listImageSpec, err)
|
||||
}
|
||||
if manifestListID, err = list.SaveToImage(store, "", names, manifest.DockerV2ListMediaType); err != nil {
|
||||
if manifestListID, err = list.SaveToImage(store, "", names, ""); err != nil {
|
||||
if errors.Is(err, storage.ErrDuplicateName) && opts.amend {
|
||||
for _, name := range names {
|
||||
manifestList, err := runtime.LookupManifestList(listImageSpec)
|
||||
@@ -361,6 +380,20 @@ func manifestCreateCmd(c *cobra.Command, args []string, opts manifestCreateOpts)
|
||||
return err
|
||||
}
|
||||
|
||||
if len(opts.annotations) != 0 {
|
||||
annotations := make(map[string]string)
|
||||
for _, annotationSpec := range opts.annotations {
|
||||
k, v, ok := strings.Cut(annotationSpec, "=")
|
||||
if !ok {
|
||||
return fmt.Errorf(`no "=" found in annotation %q`, annotationSpec)
|
||||
}
|
||||
annotations[k] = v
|
||||
}
|
||||
if err := list.SetAnnotations(nil, annotations); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, imageSpec := range imageSpecs {
|
||||
ref, err := alltransports.ParseImageName(imageSpec)
|
||||
if err != nil {
|
||||
@@ -376,13 +409,12 @@ func manifestCreateCmd(c *cobra.Command, args []string, opts manifestCreateOpts)
|
||||
// Found local image so use that.
|
||||
ref = refLocal
|
||||
}
|
||||
_, err = list.Add(getContext(), systemContext, ref, opts.all)
|
||||
if err != nil {
|
||||
if _, err = list.Add(getContext(), systemContext, ref, opts.all); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
imageID, err := list.SaveToImage(store, manifestListID, names, manifest.DockerV2ListMediaType)
|
||||
imageID, err := list.SaveToImage(store, manifestListID, names, "")
|
||||
if err == nil {
|
||||
fmt.Printf("%s\n", imageID)
|
||||
}
|
||||
@@ -396,20 +428,29 @@ func manifestAddCmd(c *cobra.Command, args []string, opts manifestAddOpts) error
|
||||
|
||||
listImageSpec := ""
|
||||
imageSpec := ""
|
||||
artifactSpec := []string{}
|
||||
switch len(args) {
|
||||
case 0, 1:
|
||||
return errors.New("At least a list image and an image to add must be specified")
|
||||
return errors.New("At least a list image and an image or artifact to add must be specified")
|
||||
case 2:
|
||||
listImageSpec = args[0]
|
||||
if listImageSpec == "" {
|
||||
return fmt.Errorf(`Invalid image name "%s"`, args[0])
|
||||
}
|
||||
imageSpec = args[1]
|
||||
if imageSpec == "" {
|
||||
return fmt.Errorf(`Invalid image name "%s"`, args[1])
|
||||
if opts.artifact {
|
||||
artifactSpec = args[1:]
|
||||
} else {
|
||||
imageSpec = args[1]
|
||||
if imageSpec == "" {
|
||||
return fmt.Errorf(`Invalid image name "%s"`, args[1])
|
||||
}
|
||||
}
|
||||
default:
|
||||
return errors.New("At least two arguments are necessary: list and image to add to list")
|
||||
if opts.artifact {
|
||||
artifactSpec = args[1:]
|
||||
} else {
|
||||
return errors.New("Too many arguments: expected list and image add to list")
|
||||
}
|
||||
}
|
||||
|
||||
store, err := getStore(c)
|
||||
@@ -442,79 +483,129 @@ func manifestAddCmd(c *cobra.Command, args []string, opts manifestAddOpts) error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ref, err := alltransports.ParseImageName(imageSpec)
|
||||
if err != nil {
|
||||
if ref, err = alltransports.ParseImageName(util.DefaultTransport + imageSpec); err != nil {
|
||||
// check if the local image exists
|
||||
if ref, _, err = util.FindImage(store, "", systemContext, imageSpec); err != nil {
|
||||
|
||||
var instanceDigest digest.Digest
|
||||
if opts.artifact {
|
||||
var subjectRef types.ImageReference
|
||||
if opts.artifactSubject != "" {
|
||||
if subjectRef, err = alltransports.ParseImageName(opts.artifactSubject); err != nil {
|
||||
if subjectRef, err = alltransports.ParseImageName(util.DefaultTransport + opts.artifactSubject); err != nil {
|
||||
if subjectRef, _, err = util.FindImage(store, "", systemContext, opts.artifactSubject); err != nil {
|
||||
logrus.Errorf("Error while trying to parse artifact subject %q: %v", opts.artifactSubject, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var artifactType *string
|
||||
if c.Flags().Changed("artifact-type") {
|
||||
artifactType = &opts.artifactType
|
||||
}
|
||||
var artifactLayerType *string
|
||||
if c.Flags().Changed("artifact-layer-type") {
|
||||
artifactLayerType = &opts.artifactLayerType
|
||||
}
|
||||
options := manifests.AddArtifactOptions{
|
||||
ManifestArtifactType: artifactType,
|
||||
LayerMediaType: artifactLayerType,
|
||||
SubjectReference: subjectRef,
|
||||
}
|
||||
if opts.artifactConfigType != "" {
|
||||
tmp := imgspecv1.DescriptorEmptyJSON
|
||||
tmp.MediaType = opts.artifactConfigType
|
||||
options.ConfigDescriptor = &tmp
|
||||
}
|
||||
if opts.artifactConfigFile != "" {
|
||||
if options.ConfigDescriptor == nil {
|
||||
tmp := imgspecv1.DescriptorEmptyJSON
|
||||
if opts.artifactConfigType == "" {
|
||||
tmp.MediaType = imgspecv1.MediaTypeImageConfig
|
||||
}
|
||||
options.ConfigDescriptor = &tmp
|
||||
}
|
||||
options.ConfigDescriptor.Size = -1
|
||||
options.ConfigFile = opts.artifactConfigFile
|
||||
}
|
||||
options.ExcludeTitles = opts.artifactExcludeTitles
|
||||
instanceDigest, err = list.AddArtifact(getContext(), systemContext, options, artifactSpec...)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error while trying to add artifact %q to image index: %v", artifactSpec, err)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
var ref types.ImageReference
|
||||
if ref, err = alltransports.ParseImageName(imageSpec); err != nil {
|
||||
if ref, err = alltransports.ParseImageName(util.DefaultTransport + imageSpec); err != nil {
|
||||
if ref, _, err = util.FindImage(store, "", systemContext, imageSpec); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
instanceDigest, err = list.Add(getContext(), systemContext, ref, opts.all)
|
||||
if err != nil {
|
||||
var storeErr error
|
||||
// Retry without a custom system context. A user may want to add
|
||||
// a custom platform (see #3511).
|
||||
if ref, _, storeErr = util.FindImage(store, "", nil, imageSpec); storeErr != nil {
|
||||
logrus.Errorf("Error while trying to find image on local storage: %v", storeErr)
|
||||
return err
|
||||
}
|
||||
instanceDigest, storeErr = list.Add(getContext(), systemContext, ref, opts.all)
|
||||
if storeErr != nil {
|
||||
logrus.Errorf("Error while trying to add on manifest list: %v", storeErr)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
digest, err := list.Add(getContext(), systemContext, ref, opts.all)
|
||||
if err != nil {
|
||||
var storeErr error
|
||||
// Retry without a custom system context. A user may want to add
|
||||
// a custom platform (see #3511).
|
||||
if ref, _, storeErr = util.FindImage(store, "", nil, imageSpec); storeErr != nil {
|
||||
logrus.Errorf("Error while trying to find image on local storage: %v", storeErr)
|
||||
return err
|
||||
}
|
||||
digest, storeErr = list.Add(getContext(), systemContext, ref, opts.all)
|
||||
if storeErr != nil {
|
||||
logrus.Errorf("Error while trying to add on manifest list: %v", storeErr)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if opts.os != "" {
|
||||
if err := list.SetOS(digest, opts.os); err != nil {
|
||||
if err := list.SetOS(instanceDigest, opts.os); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if opts.osVersion != "" {
|
||||
if err := list.SetOSVersion(digest, opts.osVersion); err != nil {
|
||||
if err := list.SetOSVersion(instanceDigest, opts.osVersion); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(opts.osFeatures) != 0 {
|
||||
if err := list.SetOSFeatures(digest, opts.osFeatures); err != nil {
|
||||
if err := list.SetOSFeatures(instanceDigest, opts.osFeatures); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if opts.arch != "" {
|
||||
if err := list.SetArchitecture(digest, opts.arch); err != nil {
|
||||
if err := list.SetArchitecture(instanceDigest, opts.arch); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if opts.variant != "" {
|
||||
if err := list.SetVariant(digest, opts.variant); err != nil {
|
||||
if err := list.SetVariant(instanceDigest, opts.variant); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(opts.features) != 0 {
|
||||
if err := list.SetFeatures(digest, opts.features); err != nil {
|
||||
if err := list.SetFeatures(instanceDigest, opts.features); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(opts.annotations) != 0 {
|
||||
annotations := make(map[string]string)
|
||||
for _, annotationSpec := range opts.annotations {
|
||||
spec := strings.SplitN(annotationSpec, "=", 2)
|
||||
if len(spec) != 2 {
|
||||
return fmt.Errorf("no value given for annotation %q", spec[0])
|
||||
k, v, ok := strings.Cut(annotationSpec, "=")
|
||||
if !ok {
|
||||
return fmt.Errorf(`no "=" found in annotation %q`, annotationSpec)
|
||||
}
|
||||
annotations[spec[0]] = spec[1]
|
||||
annotations[k] = v
|
||||
}
|
||||
if err := list.SetAnnotations(&digest, annotations); err != nil {
|
||||
if err := list.SetAnnotations(&instanceDigest, annotations); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
updatedListID, err := list.SaveToImage(store, manifestList.ID(), nil, "")
|
||||
if err == nil {
|
||||
fmt.Printf("%s: %s\n", updatedListID, digest.String())
|
||||
fmt.Printf("%s: %s\n", updatedListID, instanceDigest.String())
|
||||
}
|
||||
|
||||
return err
|
||||
@@ -523,6 +614,7 @@ func manifestAddCmd(c *cobra.Command, args []string, opts manifestAddOpts) error
|
||||
func manifestRemoveCmd(c *cobra.Command, args []string, opts manifestRemoveOpts) error {
|
||||
listImageSpec := ""
|
||||
var instanceDigest digest.Digest
|
||||
var instanceSpec string
|
||||
switch len(args) {
|
||||
case 0, 1:
|
||||
return errors.New("At least a list image and one or more instance digests must be specified")
|
||||
@@ -531,15 +623,10 @@ func manifestRemoveCmd(c *cobra.Command, args []string, opts manifestRemoveOpts)
|
||||
if listImageSpec == "" {
|
||||
return fmt.Errorf(`Invalid image name "%s"`, args[0])
|
||||
}
|
||||
instanceSpec := args[1]
|
||||
instanceSpec = args[1]
|
||||
if instanceSpec == "" {
|
||||
return fmt.Errorf(`Invalid instance "%s"`, args[1])
|
||||
}
|
||||
d, err := digest.Parse(instanceSpec)
|
||||
if err != nil {
|
||||
return fmt.Errorf(`Invalid instance "%s": %v`, args[1], err)
|
||||
}
|
||||
instanceDigest = d
|
||||
default:
|
||||
return errors.New("At least two arguments are necessary: list and digest of instance to remove from list")
|
||||
}
|
||||
@@ -562,7 +649,36 @@ func manifestRemoveCmd(c *cobra.Command, args []string, opts manifestRemoveOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, list, err := manifests.LoadFromImage(store, manifestList.ID())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d, err := list.InstanceByFile(instanceSpec)
|
||||
if err != nil {
|
||||
instanceRef, err := alltransports.ParseImageName(instanceSpec)
|
||||
if err != nil {
|
||||
if instanceRef, err = alltransports.ParseImageName(util.DefaultTransport + instanceSpec); err != nil {
|
||||
if instanceRef, _, err = util.FindImage(store, "", systemContext, instanceSpec); err != nil {
|
||||
return fmt.Errorf(`Invalid instance "%s": %v`, instanceSpec, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx := getContext()
|
||||
instanceImg, err := instanceRef.NewImageSource(ctx, systemContext)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Reading image instance: %w", err)
|
||||
}
|
||||
defer instanceImg.Close()
|
||||
manifestBytes, _, err := instanceImg.GetManifest(ctx, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Reading image instance manifest: %w", err)
|
||||
}
|
||||
d, err = manifest.Digest(manifestBytes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Digesting image instance manifest: %w", err)
|
||||
}
|
||||
}
|
||||
instanceDigest = d
|
||||
if err := manifestList.RemoveInstance(instanceDigest); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -611,7 +727,11 @@ func manifestRmCmd(c *cobra.Command, args []string) error {
|
||||
|
||||
func manifestAnnotateCmd(c *cobra.Command, args []string, opts manifestAnnotateOpts) error {
|
||||
listImageSpec := ""
|
||||
imageSpec := ""
|
||||
instanceSpec := ""
|
||||
if opts.subject != "" {
|
||||
// this option is always only working at the index level
|
||||
opts.index = true
|
||||
}
|
||||
switch len(args) {
|
||||
case 0:
|
||||
return errors.New("At least a list image must be specified")
|
||||
@@ -620,17 +740,23 @@ func manifestAnnotateCmd(c *cobra.Command, args []string, opts manifestAnnotateO
|
||||
if listImageSpec == "" {
|
||||
return fmt.Errorf(`Invalid image name "%s"`, args[0])
|
||||
}
|
||||
if !opts.index {
|
||||
return errors.New(`Expected an instance digest, image name, or artifact name`)
|
||||
}
|
||||
case 2:
|
||||
listImageSpec = args[0]
|
||||
if listImageSpec == "" {
|
||||
return fmt.Errorf(`Invalid image name "%s"`, args[0])
|
||||
}
|
||||
imageSpec = args[1]
|
||||
if imageSpec == "" {
|
||||
return fmt.Errorf(`Invalid image name "%s"`, args[1])
|
||||
if opts.index {
|
||||
return fmt.Errorf(`Did not expect image or artifact name "%s" when modifying the entire index`, args[1])
|
||||
}
|
||||
instanceSpec = args[1]
|
||||
if instanceSpec == "" {
|
||||
return fmt.Errorf(`Invalid instance digest, image name, or artifact name "%s"`, instanceSpec)
|
||||
}
|
||||
default:
|
||||
return errors.New("At least two arguments are necessary: list and image to add to list")
|
||||
return errors.New("Expected either a list name and --index or a list name and an image digest or image name or artifact name")
|
||||
}
|
||||
|
||||
store, err := getStore(c)
|
||||
@@ -664,75 +790,148 @@ func manifestAnnotateCmd(c *cobra.Command, args []string, opts manifestAnnotateO
|
||||
return err
|
||||
}
|
||||
|
||||
digest, err := digest.Parse(imageSpec)
|
||||
if err != nil {
|
||||
ctx := getContext()
|
||||
ref, _, err := util.FindImage(store, "", systemContext, imageSpec)
|
||||
var instance digest.Digest
|
||||
if !opts.index {
|
||||
d, err := list.InstanceByFile(instanceSpec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
img, err := ref.NewImageSource(ctx, systemContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer img.Close()
|
||||
manifestBytes, _, err := img.GetManifest(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
digest, err = manifest.Digest(manifestBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
instanceRef, err := alltransports.ParseImageName(instanceSpec)
|
||||
if err != nil {
|
||||
if instanceRef, err = alltransports.ParseImageName(util.DefaultTransport + instanceSpec); err != nil {
|
||||
// check if the local image exists
|
||||
if instanceRef, _, err = util.FindImage(store, "", systemContext, instanceSpec); err != nil {
|
||||
return fmt.Errorf(`Invalid instance "%s": %v`, instanceSpec, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx := getContext()
|
||||
instanceImg, err := instanceRef.NewImageSource(ctx, systemContext)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Reading image instance: %w", err)
|
||||
}
|
||||
defer instanceImg.Close()
|
||||
manifestBytes, _, err := instanceImg.GetManifest(ctx, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Reading image instance manifest: %w", err)
|
||||
}
|
||||
d, err = manifest.Digest(manifestBytes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Digesting image instance manifest: %w", err)
|
||||
}
|
||||
}
|
||||
instance = d
|
||||
}
|
||||
|
||||
if opts.os != "" {
|
||||
if err := list.SetOS(digest, opts.os); err != nil {
|
||||
if opts.index {
|
||||
return fmt.Errorf("--index is not compatible with --os")
|
||||
}
|
||||
if err := list.SetOS(instance, opts.os); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if opts.osVersion != "" {
|
||||
if err := list.SetOSVersion(digest, opts.osVersion); err != nil {
|
||||
if opts.index {
|
||||
return fmt.Errorf("--index is not compatible with --os-version")
|
||||
}
|
||||
if err := list.SetOSVersion(instance, opts.osVersion); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(opts.osFeatures) != 0 {
|
||||
if err := list.SetOSFeatures(digest, opts.osFeatures); err != nil {
|
||||
if opts.index {
|
||||
return fmt.Errorf("--index is not compatible with --os-features")
|
||||
}
|
||||
if err := list.SetOSFeatures(instance, opts.osFeatures); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if opts.arch != "" {
|
||||
if err := list.SetArchitecture(digest, opts.arch); err != nil {
|
||||
if opts.index {
|
||||
return fmt.Errorf("--index is not compatible with --arch")
|
||||
}
|
||||
if err := list.SetArchitecture(instance, opts.arch); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if opts.variant != "" {
|
||||
if err := list.SetVariant(digest, opts.variant); err != nil {
|
||||
if opts.index {
|
||||
return fmt.Errorf("--index is not compatible with --variant")
|
||||
}
|
||||
if err := list.SetVariant(instance, opts.variant); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(opts.features) != 0 {
|
||||
if err := list.SetFeatures(digest, opts.features); err != nil {
|
||||
if opts.index {
|
||||
return fmt.Errorf("--index is not compatible with --features")
|
||||
}
|
||||
if err := list.SetFeatures(instance, opts.features); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(opts.annotations) != 0 {
|
||||
annotations := make(map[string]string)
|
||||
for _, annotationSpec := range opts.annotations {
|
||||
spec := strings.SplitN(annotationSpec, "=", 2)
|
||||
if len(spec) != 2 {
|
||||
return fmt.Errorf("no value given for annotation %q", spec[0])
|
||||
k, v, ok := strings.Cut(annotationSpec, "=")
|
||||
if !ok {
|
||||
return fmt.Errorf(`no "=" found in annotation %q`, annotationSpec)
|
||||
}
|
||||
annotations[spec[0]] = spec[1]
|
||||
annotations[k] = v
|
||||
}
|
||||
if err := list.SetAnnotations(&digest, annotations); err != nil {
|
||||
var instanceDigest *digest.Digest
|
||||
if !opts.index {
|
||||
instanceDigest = &instance
|
||||
}
|
||||
if err := list.SetAnnotations(instanceDigest, annotations); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if opts.subject != "" {
|
||||
subjectRef, err := alltransports.ParseImageName(opts.subject)
|
||||
if err != nil {
|
||||
if subjectRef, err = alltransports.ParseImageName(util.DefaultTransport + opts.subject); err != nil {
|
||||
// check if the local image exists
|
||||
if subjectRef, _, err = util.FindImage(store, "", systemContext, opts.subject); err != nil {
|
||||
logrus.Errorf("Error while trying to parse artifact subject: %v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx := getContext()
|
||||
src, err := subjectRef.NewImageSource(ctx, systemContext)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error while trying to read artifact subject: %v", err)
|
||||
return err
|
||||
}
|
||||
defer src.Close()
|
||||
|
||||
manifestBytes, manifestType, err := src.GetManifest(ctx, nil)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error while trying to read artifact subject manifest: %v", err)
|
||||
return err
|
||||
}
|
||||
manifestDigest, err := manifest.Digest(manifestBytes)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error while trying to digest artifact subject manifest: %v", err)
|
||||
return err
|
||||
}
|
||||
descriptor := imgspecv1.Descriptor{
|
||||
MediaType: manifestType,
|
||||
Size: int64(len(manifestBytes)),
|
||||
Digest: manifestDigest,
|
||||
}
|
||||
if err := list.SetSubject(&descriptor); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
updatedListID, err := list.SaveToImage(store, manifestList.ID(), nil, "")
|
||||
if err == nil {
|
||||
fmt.Printf("%s: %s\n", updatedListID, digest.String())
|
||||
if instance == "" {
|
||||
fmt.Printf("%s\n", updatedListID)
|
||||
} else {
|
||||
fmt.Printf("%s: %s\n", updatedListID, instance.String())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -2,15 +2,16 @@
|
||||
|
||||
## NAME
|
||||
|
||||
buildah\-manifest\-add - Add an image to a manifest list or image index.
|
||||
buildah\-manifest\-add - Add an image or artifact to a manifest list or image index.
|
||||
|
||||
## SYNOPSIS
|
||||
|
||||
**buildah manifest add** *listNameOrIndexName* *imageName*
|
||||
**buildah manifest add** [options...] *listNameOrIndexName* *imageOrArtifactName* [...]
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
Adds the specified image to the specified manifest list or image index.
|
||||
Adds the specified image to the specified manifest list or image index, or
|
||||
creates an artifact manifest and adds it to the specified image index.
|
||||
|
||||
## RETURN VALUE
|
||||
|
||||
@@ -27,7 +28,7 @@ from such a list or index will be added to the list or index. Combining
|
||||
|
||||
**--annotation** *annotation=value*
|
||||
|
||||
Set an annotation on the entry for the newly-added image.
|
||||
Set an annotation on the entry for the newly-added image or artifact manifest.
|
||||
|
||||
**--arch**
|
||||
|
||||
@@ -36,6 +37,55 @@ the image. If *imageName* refers to a manifest list or image index, the
|
||||
architecture information will be retrieved from it. Otherwise, it will be
|
||||
retrieved from the image's configuration information.
|
||||
|
||||
**--artifact**
|
||||
|
||||
Create an artifact manifest and add it to the image index. Arguments after the
|
||||
index name will be interpreted as file names rather than as image references.
|
||||
In most scenarios, the **--artifact-type** option should also be specified.
|
||||
|
||||
**--artifact-config** *filename*
|
||||
|
||||
When creating an artifact manifest and adding it to the image index, use the
|
||||
specified file's contents as the configuration blob in the artifact manifest.
|
||||
In most scenarios, leaving the default value, which signifies an empty
|
||||
configuration, unchanged, is the preferred option.
|
||||
|
||||
**--artifact-config-type** *type*
|
||||
|
||||
When creating an artifact manifest and adding it to the image index, use the
|
||||
specified MIME type as the `mediaType` associated with the configuration blob
|
||||
in the artifact manifest. In most scenarios, leaving the default value, which
|
||||
signifies either an empty configuration or the standard OCI configuration type,
|
||||
unchanged, is the preferred option.
|
||||
|
||||
**--artifact-exclude-titles**
|
||||
|
||||
When creating an artifact manifest and adding it to the image index, do not
|
||||
set "org.opencontainers.image.title" annotations equal to the file's basename
|
||||
for each file added to the artifact manifest. Tools which retrieve artifacts
|
||||
from a registry may use these values to choose names for files when saving
|
||||
artifacts to disk, so this option is not recommended unless it is required
|
||||
for interoperability with a particular registry.
|
||||
|
||||
**--artifact-layer-type** *type*
|
||||
|
||||
When creating an artifact manifest and adding it to the image index, use the
|
||||
specified MIME type as the `mediaType` associated with the files' contents. If
|
||||
not specified, guesses based on either the files names or their contents will
|
||||
be made and used, but the option should be specified if certainty is needed.
|
||||
|
||||
**--artifact-subject** *imageName*
|
||||
|
||||
When creating an artifact manifest and adding it to the image index, set the
|
||||
*subject* field in the artifact manifest to mark the artifact manifest as being
|
||||
associated with the specified image in some way. An artifact manifest can only
|
||||
be associated with, at most, one subject.
|
||||
|
||||
**--artifact-type** *type*
|
||||
|
||||
When creating an artifact manifest, use the specified MIME type as the
|
||||
manifest's `artifactType` value instead of the less informative default value.
|
||||
|
||||
**--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`.
|
||||
@@ -105,5 +155,11 @@ buildah manifest add --arch arm64 --variant v8 mylist:v1.11 docker://fedora@sha2
|
||||
506d8f4bb54931ea03a7e70173a0ed6302e3fb92dfadb3955ba5c17812e95c51: sha256:c829b1810d2dbb456e74a695fd3847530c8319e5a95dca623e9f1b1b89020d8b
|
||||
```
|
||||
|
||||
```
|
||||
buildah manifest add --artifact --artifact-type application/x-cd-image mylist:v1.11 ./imagefile.iso
|
||||
506d8f4bb54931ea03a7e70173a0ed6302e3fb92dfadb3955ba5c17812e95c51: sha256:1768fae728f6f8ff3d0f8c7df409d7f4f0ca5c89b070810bd4aa4a2ed2eca8bb
|
||||
```
|
||||
|
||||
|
||||
## SEE ALSO
|
||||
buildah(1), buildah-login(1), buildah-manifest(1), buildah-manifest-create(1), buildah-manifest-remove(1), buildah-manifest-annotate(1), buildah-manifest-inspect(1), buildah-manifest-push(1), buildah-rmi(1), docker-login(1), containers-auth.json(5)
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
|
||||
## NAME
|
||||
|
||||
buildah\-manifest\-annotate - Add and update information about an image to a manifest list or image index.
|
||||
buildah\-manifest\-annotate - Add and update information about an image or artifact to a manifest list or image index.
|
||||
|
||||
## SYNOPSIS
|
||||
|
||||
**buildah manifest annotate** [options...] *listNameOrIndexName* *imageManifestDigest*
|
||||
**buildah manifest annotate** [options...] *listNameOrIndexName* *imageManifestDigestOrImageOrArtifactName*
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
Adds or updates information about an image included in a manifest list or image index.
|
||||
Adds or updates information about an image or artifact included in a manifest list or image index.
|
||||
|
||||
## RETURN VALUE
|
||||
|
||||
@@ -20,7 +20,8 @@ The list image's ID and the digest of the image's manifest.
|
||||
|
||||
**--annotation** *annotation=value*
|
||||
|
||||
Set an annotation on the entry for the specified image.
|
||||
Set an annotation on the entry for the specified image or artifact. If
|
||||
**--index** is also specified, sets the annotation on the entire image index.
|
||||
|
||||
**--arch**
|
||||
|
||||
@@ -33,6 +34,12 @@ configuration information, so it is rarely necessary to use this option.
|
||||
Specify the features list which the list or index records as requirements for
|
||||
the image. This option is rarely used.
|
||||
|
||||
**--index**
|
||||
|
||||
Treats arguments to the **--annotation** option as annotation values to be set
|
||||
on the image index itself rather than on an entry in the image index. Implied
|
||||
for **--subject**.
|
||||
|
||||
**--os**
|
||||
|
||||
Override the OS which the list or index records as a requirement for the image.
|
||||
@@ -49,6 +56,12 @@ for the image. This option is rarely used.
|
||||
Specify the OS version which the list or index records as a requirement for the
|
||||
image. This option is rarely used.
|
||||
|
||||
**--subject** *imageName*
|
||||
|
||||
Set the *subject* field in the image index to mark the image index as being
|
||||
associated with the specified image in some way. An image index can only be
|
||||
associated with, at most, one subject.
|
||||
|
||||
**--variant**
|
||||
|
||||
Specify the variant which the list or index records for the image. This option
|
||||
@@ -62,5 +75,10 @@ buildah manifest annotate --arch arm64 --variant v8 mylist:v1.11 sha256:c829b181
|
||||
506d8f4bb54931ea03a7e70173a0ed6302e3fb92dfadb3955ba5c17812e95c51: sha256:c829b1810d2dbb456e74a695fd3847530c8319e5a95dca623e9f1b1b89020d8b
|
||||
```
|
||||
|
||||
```
|
||||
buildah manifest annotate --index --annotation food=yummy mylist:v1.11
|
||||
506d8f4bb54931ea03a7e70173a0ed6302e3fb92dfadb3955ba5c17812e95c51: sha256:c829b1810d2dbb456e74a695fd3847530c8319e5a95dca623e9f1b1b89020d8b
|
||||
```
|
||||
|
||||
## SEE ALSO
|
||||
buildah(1), buildah-manifest(1), buildah-manifest-create(1), buildah-manifest-add(1), buildah-manifest-remove(1), buildah-manifest-inspect(1), buildah-manifest-push(1), buildah-rmi(1)
|
||||
|
||||
@@ -6,7 +6,7 @@ buildah\-manifest\-create - Create a manifest list or image index.
|
||||
|
||||
## SYNOPSIS
|
||||
|
||||
**buildah manifest create** *listNameOrIndexName* [*imageName* ...]
|
||||
**buildah manifest create** [options...] *listNameOrIndexName* [*imageName* ...]
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
@@ -35,6 +35,10 @@ If a manifest list named *listNameOrIndexName* already exists, modify the
|
||||
preexisting list instead of exiting with an error. The contents of
|
||||
*listNameOrIndexName* are not modified if no *imageName*s are given.
|
||||
|
||||
**--annotation** *annotation=value*
|
||||
|
||||
Set an annotation on the newly-created image index.
|
||||
|
||||
**--tls-verify** *bool-value*
|
||||
|
||||
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.
|
||||
|
||||
@@ -6,11 +6,12 @@ buildah\-manifest\-remove - Remove an image from a manifest list or image index.
|
||||
|
||||
## SYNOPSIS
|
||||
|
||||
**buildah manifest remove** *listNameOrIndexName* *imageManifestDigest*
|
||||
**buildah manifest remove** *listNameOrIndexName* *imageNameOrManifestDigestOrArtifactName*
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
Removes the image with the specified digest from the specified manifest list or image index.
|
||||
Removes the image with the specified name or digest from the specified manifest
|
||||
list or image index, or the specified artifact from the specified image index.
|
||||
|
||||
## RETURN VALUE
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ The `buildah manifest` command provides subcommands which can be used to:
|
||||
|
||||
* Create a working Docker manifest list or OCI image index.
|
||||
* Add an entry to a manifest list or image index for a specified image.
|
||||
* Add an entry to an image index for an artifact manifest referring to a file.
|
||||
* Add or update information about an entry in a manifest list or image index.
|
||||
* Delete a working container or an image.
|
||||
* Push a manifest list or image index to a registry or other location.
|
||||
@@ -19,8 +20,8 @@ The `buildah manifest` command provides subcommands which can be used to:
|
||||
|
||||
| Command | Man Page | Description |
|
||||
| ------- | -------------------------------------------------------------- | --------------------------------------------------------------------------- |
|
||||
| add | [buildah-manifest-add(1)](buildah-manifest-add.1.md) | Add an image to a manifest list or image index. |
|
||||
| annotate | [buildah-manifest-annotate(1)](buildah-manifest-annotate.1.md) | Add or update information about an image in a manifest list or image index. |
|
||||
| add | [buildah-manifest-add(1)](buildah-manifest-add.1.md) | Add an image or artifact to a manifest list or image index. |
|
||||
| annotate | [buildah-manifest-annotate(1)](buildah-manifest-annotate.1.md) | Add or update information about an image or artifact in a manifest list or image index. |
|
||||
| create | [buildah-manifest-create(1)](buildah-manifest-create.1.md) | Create a manifest list or image index. |
|
||||
| exists | [buildah-manifest-exists(1)](buildah-manifest-exists.1.md) | Check if a manifest list exists in local storage. |
|
||||
| inspect | [buildah-manifest-inspect(1)](buildah-manifest-inspect.1.md) | Display the contents of a manifest list or image index. |
|
||||
@@ -41,8 +42,8 @@ the scope of this example. Building a multi-arch manifest list
|
||||
$ platarch=linux/amd64,linux/ppc64le,linux/arm64,linux/s390x
|
||||
$ buildah build --jobs=4 --platform=$platarch --manifest shazam .
|
||||
|
||||
**Note:** The `--jobs` argument is optional, and the `-t` or `--tag`
|
||||
option should *not* be used.
|
||||
**Note:** The `--jobs` argument is optional, and the `--manifest` option
|
||||
should be used instead of the`-t` or `--tag` options.
|
||||
|
||||
### Assembling a multi-arch manifest from separately built images
|
||||
|
||||
|
||||
@@ -12,12 +12,20 @@ IMAGE_LIST_PPC64LE_INSTANCE_DIGEST=sha256:bcf9771c0b505e68c65440474179592ffdfa98
|
||||
IMAGE_LIST_S390X_INSTANCE_DIGEST=sha256:882a20ee0df7399a445285361d38b711c299ca093af978217112c73803546d5e
|
||||
|
||||
@test "manifest-create" {
|
||||
_prefetch busybox
|
||||
run_buildah inspect -f '{{ .FromImageDigest }}' busybox
|
||||
imagedigest="$output"
|
||||
run_buildah manifest create foo
|
||||
listid="$output"
|
||||
run_buildah 125 manifest create foo
|
||||
assert "$output" =~ "that name is already in use"
|
||||
run_buildah manifest create --amend foo
|
||||
assert "$output" == "$listid"
|
||||
run_buildah manifest create --amend --annotation red=blue foo busybox
|
||||
assert "$output" == "$listid"
|
||||
run_buildah manifest inspect foo
|
||||
assert "$output" =~ '"red": "blue"'
|
||||
assert "$output" =~ "${imagedigest}"
|
||||
# since manifest exists in local storage this should exit with `0`
|
||||
run_buildah manifest exists foo
|
||||
# since manifest does not exist in local storage this should exit with `1`
|
||||
@@ -40,6 +48,33 @@ IMAGE_LIST_S390X_INSTANCE_DIGEST=sha256:882a20ee0df7399a445285361d38b711c299ca09
|
||||
run_buildah manifest rm foo
|
||||
}
|
||||
|
||||
@test "manifest-add artifact" {
|
||||
_prefetch busybox
|
||||
createrandom $TEST_SCRATCH_DIR/randomfile2
|
||||
createrandom $TEST_SCRATCH_DIR/randomfile
|
||||
run sha256sum $TEST_SCRATCH_DIR/randomfile
|
||||
blobencoded="${output%% *}"
|
||||
run_buildah manifest create foo
|
||||
run_buildah manifest add --artifact --artifact-type image/jpeg --artifact-layer-type image/not-validated --artifact-config-type text/x-not-really --artifact-subject busybox foo $TEST_SCRATCH_DIR/randomfile2
|
||||
run_buildah manifest add --artifact --artifact-type image/png --artifact-layer-type image/not-validated --artifact-config-type text/x-not-really --artifact-subject busybox foo $TEST_SCRATCH_DIR/randomfile
|
||||
digest="${output##* }"
|
||||
alg="${digest%%:*}"
|
||||
encoded="${digest##*:}"
|
||||
run_buildah manifest annotate --annotation red=blue foo $TEST_SCRATCH_DIR/randomfile
|
||||
run_buildah manifest inspect foo
|
||||
assert "$output" =~ '"image/png"'
|
||||
assert "$output" =~ '"red": "blue"'
|
||||
run_buildah manifest push --all foo oci:$TEST_SCRATCH_DIR/pushed
|
||||
run cmp $TEST_SCRATCH_DIR/randomfile $TEST_SCRATCH_DIR/pushed/blobs/sha256/$blobencoded
|
||||
assert "$status" -eq 0 "pushed copy of random file did not match original"
|
||||
run cat $TEST_SCRATCH_DIR/pushed/blobs/$alg/$encoded
|
||||
assert "$status" -eq 0 "artifact manifest not found in expected location"
|
||||
assert "$output" =~ '"artifactType":"image/png"' "cat $TEST_SCRATCH_DIR/pushed/blobs/$alg/$encoded"
|
||||
assert "$output" =~ '"mediaType":"image/not-validated"' "cat $TEST_SCRATCH_DIR/pushed/blobs/$alg/$encoded"
|
||||
assert "$output" =~ '"mediaType":"text/x-not-really"' "cat $TEST_SCRATCH_DIR/pushed/blobs/$alg/$encoded"
|
||||
run_buildah manifest rm foo
|
||||
}
|
||||
|
||||
@test "manifest-add local image" {
|
||||
target=scratch-image
|
||||
run_buildah bud $WITH_POLICY_JSON -t ${target} $BUDFILES/from-scratch
|
||||
@@ -70,6 +105,44 @@ IMAGE_LIST_S390X_INSTANCE_DIGEST=sha256:882a20ee0df7399a445285361d38b711c299ca09
|
||||
expect_output --substring ${IMAGE_LIST_S390X_INSTANCE_DIGEST}
|
||||
}
|
||||
|
||||
@test "manifest-annotate global annotation" {
|
||||
_prefetch busybox
|
||||
run_buildah manifest create foo
|
||||
run_buildah manifest add foo busybox
|
||||
run_buildah manifest annotate --index --annotation red=blue foo
|
||||
run_buildah manifest inspect foo
|
||||
assert "$output" =~ '"red": "blue"'
|
||||
}
|
||||
|
||||
@test "manifest-annotate instance annotation" {
|
||||
_prefetch busybox
|
||||
run_buildah manifest create foo
|
||||
run_buildah manifest add foo busybox
|
||||
instance="${output##* }"
|
||||
run_buildah manifest annotate --annotation red=blue foo "${instance}"
|
||||
run_buildah manifest annotate --os OperatingSystem foo "${instance}"
|
||||
run_buildah manifest annotate --arch aRCHITECTURE foo "${instance}"
|
||||
run_buildah manifest annotate --variant vARIANT foo "${instance}"
|
||||
run_buildah manifest annotate --features FEATURE1 --features FEATURE2 foo "${instance}"
|
||||
run_buildah manifest annotate --os-features OSFEATURE1 --os-features OSFEATURE2 foo "${instance}"
|
||||
run_buildah manifest inspect foo
|
||||
assert "$output" =~ '"red": "blue"'
|
||||
assert "$output" =~ '"os": "OperatingSystem"'
|
||||
assert "$output" =~ '"architecture": "aRCHITECTURE"'
|
||||
assert "$output" =~ '"variant": "vARIANT"'
|
||||
}
|
||||
|
||||
@test "manifest-annotate subject" {
|
||||
_prefetch busybox "${IMAGE_LIST_INSTANCE##*://}"
|
||||
run_buildah manifest create foo
|
||||
run_buildah manifest add foo busybox
|
||||
run_buildah manifest annotate --subject "${IMAGE_LIST_INSTANCE##*://}" foo
|
||||
run_buildah inspect -f '{{ .FromImageDigest }}' "${IMAGE_LIST_INSTANCE##*://}"
|
||||
imagedigest="$output"
|
||||
run_buildah manifest inspect foo
|
||||
assert "$output" =~ "$imagedigest"
|
||||
}
|
||||
|
||||
@test "manifest-remove" {
|
||||
run_buildah manifest create foo
|
||||
run_buildah manifest add --all foo ${IMAGE_LIST}
|
||||
|
||||
Reference in New Issue
Block a user