2017-02-25 04:18:35 +08:00
|
|
|
package buildah
|
|
|
|
|
|
|
|
import (
|
2018-04-12 22:20:36 +08:00
|
|
|
"context"
|
|
|
|
|
2021-02-07 06:49:40 +08:00
|
|
|
"github.com/containers/buildah/define"
|
2018-09-18 03:20:16 +08:00
|
|
|
"github.com/containers/buildah/docker"
|
|
|
|
"github.com/containers/buildah/util"
|
2019-11-01 03:18:10 +08:00
|
|
|
"github.com/containers/image/v5/image"
|
2019-10-26 05:19:30 +08:00
|
|
|
"github.com/containers/image/v5/manifest"
|
|
|
|
is "github.com/containers/image/v5/storage"
|
2019-11-01 03:18:10 +08:00
|
|
|
"github.com/containers/image/v5/transports"
|
2019-10-26 05:19:30 +08:00
|
|
|
"github.com/containers/image/v5/types"
|
2017-05-17 23:53:28 +08:00
|
|
|
"github.com/containers/storage"
|
2019-10-02 04:03:57 +08:00
|
|
|
digest "github.com/opencontainers/go-digest"
|
2017-06-02 03:23:02 +08:00
|
|
|
"github.com/pkg/errors"
|
2017-02-25 04:18:35 +08:00
|
|
|
)
|
|
|
|
|
2018-04-12 22:20:36 +08:00
|
|
|
func importBuilderDataFromImage(ctx context.Context, store storage.Store, systemContext *types.SystemContext, imageID, containerName, containerID string) (*Builder, error) {
|
2018-06-12 06:23:48 +08:00
|
|
|
if imageID == "" {
|
|
|
|
return nil, errors.Errorf("Internal error: imageID is empty in importBuilderDataFromImage")
|
|
|
|
}
|
|
|
|
|
2019-03-25 18:23:56 +08:00
|
|
|
storeopts, err := storage.DefaultStoreOptions(false, 0)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
uidmap, gidmap := convertStorageIDMaps(storeopts.UIDMap, storeopts.GIDMap)
|
2017-02-25 04:18:35 +08:00
|
|
|
|
2018-06-12 06:23:48 +08:00
|
|
|
ref, err := is.Transport.ParseStoreReference(store, imageID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "no such image %q", imageID)
|
|
|
|
}
|
2019-11-01 03:18:10 +08:00
|
|
|
src, err := ref.NewImageSource(ctx, systemContext)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "error instantiating image source")
|
2018-06-12 06:23:48 +08:00
|
|
|
}
|
|
|
|
defer src.Close()
|
2018-06-12 06:41:11 +08:00
|
|
|
|
2019-11-01 03:18:10 +08:00
|
|
|
imageDigest := ""
|
|
|
|
manifestBytes, manifestType, err := src.GetManifest(ctx, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "error loading image manifest for %q", transports.ImageName(ref))
|
|
|
|
}
|
|
|
|
if manifestDigest, err := manifest.Digest(manifestBytes); err == nil {
|
|
|
|
imageDigest = manifestDigest.String()
|
|
|
|
}
|
|
|
|
|
|
|
|
var instanceDigest *digest.Digest
|
|
|
|
if manifest.MIMETypeIsMultiImage(manifestType) {
|
|
|
|
list, err := manifest.ListFromBlob(manifestBytes, manifestType)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "error parsing image manifest for %q as list", transports.ImageName(ref))
|
|
|
|
}
|
|
|
|
instance, err := list.ChooseInstance(systemContext)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "error finding an appropriate image in manifest list %q", transports.ImageName(ref))
|
|
|
|
}
|
|
|
|
instanceDigest = &instance
|
|
|
|
}
|
|
|
|
|
|
|
|
image, err := image.FromUnparsedImage(ctx, systemContext, image.UnparsedInstance(src, instanceDigest))
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "error instantiating image for %q instance %q", transports.ImageName(ref), instanceDigest)
|
|
|
|
}
|
|
|
|
|
2018-06-12 06:23:48 +08:00
|
|
|
imageName := ""
|
|
|
|
if img, err3 := store.Image(imageID); err3 == nil {
|
|
|
|
if len(img.Names) > 0 {
|
|
|
|
imageName = img.Names[0]
|
2017-02-25 04:18:35 +08:00
|
|
|
}
|
2018-06-12 06:23:48 +08:00
|
|
|
if img.TopLayer != "" {
|
|
|
|
layer, err4 := store.Layer(img.TopLayer)
|
|
|
|
if err4 != nil {
|
|
|
|
return nil, errors.Wrapf(err4, "error reading information about image's top layer")
|
2018-03-08 07:11:43 +08:00
|
|
|
}
|
2018-06-12 06:23:48 +08:00
|
|
|
uidmap, gidmap = convertStorageIDMaps(layer.UIDMap, layer.GIDMap)
|
2017-03-16 05:19:29 +08:00
|
|
|
}
|
2017-02-25 04:18:35 +08:00
|
|
|
}
|
|
|
|
|
2018-06-27 04:35:43 +08:00
|
|
|
defaultNamespaceOptions, err := DefaultNamespaceOptions()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-01-06 04:36:49 +08:00
|
|
|
netInt, err := getNetworkInterface(store, "", "")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2017-02-25 04:18:35 +08:00
|
|
|
builder := &Builder{
|
Maintain multiple working container configs
Maintain the container configuration in multiple formats in the Buildah
object, initializing one based on the other, depending on which format
the source image used for its configuration.
Replace directly manipulated fields in the Buildah object (Annotations,
CreatedBy, OS, Architecture, Maintainer, User, Workdir, Env, Cmd,
Entrypoint, Expose, Labels, and Volumes) with accessor functions which
update both configurations and which read from whichever one we consider
to be authoritative. Drop Args because we weren't using them.
Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
Closes: #102
Approved by: rhatdan
2017-05-16 23:08:52 +08:00
|
|
|
store: store,
|
|
|
|
Type: containerType,
|
|
|
|
FromImage: imageName,
|
2017-05-19 05:38:41 +08:00
|
|
|
FromImageID: imageID,
|
2019-07-02 05:14:07 +08:00
|
|
|
FromImageDigest: imageDigest,
|
2017-05-19 05:38:41 +08:00
|
|
|
Container: containerName,
|
|
|
|
ContainerID: containerID,
|
Maintain multiple working container configs
Maintain the container configuration in multiple formats in the Buildah
object, initializing one based on the other, depending on which format
the source image used for its configuration.
Replace directly manipulated fields in the Buildah object (Annotations,
CreatedBy, OS, Architecture, Maintainer, User, Workdir, Env, Cmd,
Entrypoint, Expose, Labels, and Volumes) with accessor functions which
update both configurations and which read from whichever one we consider
to be authoritative. Drop Args because we weren't using them.
Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
Closes: #102
Approved by: rhatdan
2017-05-16 23:08:52 +08:00
|
|
|
ImageAnnotations: map[string]string{},
|
|
|
|
ImageCreatedBy: "",
|
2018-06-27 04:35:43 +08:00
|
|
|
NamespaceOptions: defaultNamespaceOptions,
|
2021-02-07 06:49:40 +08:00
|
|
|
IDMappingOptions: define.IDMappingOptions{
|
2018-03-08 07:11:43 +08:00
|
|
|
HostUIDMapping: len(uidmap) == 0,
|
|
|
|
HostGIDMapping: len(uidmap) == 0,
|
|
|
|
UIDMap: uidmap,
|
|
|
|
GIDMap: gidmap,
|
|
|
|
},
|
2022-01-06 04:36:49 +08:00
|
|
|
NetworkInterface: netInt,
|
2017-02-25 04:18:35 +08:00
|
|
|
}
|
|
|
|
|
bud: teach --platform to take a list
Add a pkg/parse.PlatformsFromOptions() which understands a "variant"
value as an optional third value in an OS/ARCH[/VARIANT] argument value,
which accepts a comma-separated list of them, and which returns a list
of platforms.
Teach "from" and "pull" about the --platform option and add integration
tests for them, warning if --platform was given multiple values.
Add a define.BuildOptions.JobSemaphore which an imagebuildah executor
will use in preference to one that it might allocate for itself.
In main(), allocate a JobSemaphore if the number of jobs is not 0 (which
we treat as "unlimited", and continue to allow executors to do).
In addManifest(), take a lock on the manifest list's image ID so that we
don't overwrite changes that another thread might be making while we're
attempting to make changes to it. In main(), create an empty list if
the list doesn't already exist before we start down this path, so that
we don't get two threads trying to create that manifest list at the same
time later on. Two processes could still try to create the same list
twice, but it's an incremental improvement.
Finally, if we've been given multiple platforms to build for, run their
builds concurrently and gather up their results.
Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
2021-06-22 22:52:49 +08:00
|
|
|
if err := builder.initConfig(ctx, image, systemContext); err != nil {
|
2018-06-12 05:43:21 +08:00
|
|
|
return nil, errors.Wrapf(err, "error preparing image configuration")
|
|
|
|
}
|
2017-05-19 05:38:41 +08:00
|
|
|
|
|
|
|
return builder, nil
|
|
|
|
}
|
|
|
|
|
2018-04-12 22:20:36 +08:00
|
|
|
func importBuilder(ctx context.Context, store storage.Store, options ImportOptions) (*Builder, error) {
|
2017-05-19 05:38:41 +08:00
|
|
|
if options.Container == "" {
|
2017-06-03 00:17:27 +08:00
|
|
|
return nil, errors.Errorf("container name must be specified")
|
2017-05-19 05:38:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
c, err := store.Container(options.Container)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-03-14 04:03:13 +08:00
|
|
|
systemContext := getSystemContext(store, &types.SystemContext{}, options.SignaturePolicyPath)
|
2017-05-19 05:38:41 +08:00
|
|
|
|
2018-04-12 22:20:36 +08:00
|
|
|
builder, err := importBuilderDataFromImage(ctx, store, systemContext, c.ImageID, options.Container, c.ID)
|
2017-05-19 05:38:41 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2017-06-07 02:20:55 +08:00
|
|
|
if builder.FromImageID != "" {
|
|
|
|
if d, err2 := digest.Parse(builder.FromImageID); err2 == nil {
|
|
|
|
builder.Docker.Parent = docker.ID(d)
|
|
|
|
} else {
|
|
|
|
builder.Docker.Parent = docker.ID(digest.NewDigestFromHex(digest.Canonical.String(), builder.FromImageID))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if builder.FromImage != "" {
|
|
|
|
builder.Docker.ContainerConfig.Image = builder.FromImage
|
|
|
|
}
|
2018-03-08 07:11:43 +08:00
|
|
|
builder.IDMappingOptions.UIDMap, builder.IDMappingOptions.GIDMap = convertStorageIDMaps(c.UIDMap, c.GIDMap)
|
2017-06-07 02:20:55 +08:00
|
|
|
|
2017-02-25 04:18:35 +08:00
|
|
|
err = builder.Save()
|
|
|
|
if err != nil {
|
2017-06-02 03:23:02 +08:00
|
|
|
return nil, errors.Wrapf(err, "error saving builder state")
|
2017-02-25 04:18:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return builder, nil
|
|
|
|
}
|
2017-05-19 05:38:41 +08:00
|
|
|
|
2018-04-12 22:20:36 +08:00
|
|
|
func importBuilderFromImage(ctx context.Context, store storage.Store, options ImportFromImageOptions) (*Builder, error) {
|
2017-05-19 05:38:41 +08:00
|
|
|
if options.Image == "" {
|
2017-06-03 00:17:27 +08:00
|
|
|
return nil, errors.Errorf("image name must be specified")
|
2017-05-19 05:38:41 +08:00
|
|
|
}
|
|
|
|
|
2019-03-14 04:03:13 +08:00
|
|
|
systemContext := getSystemContext(store, options.SystemContext, options.SignaturePolicyPath)
|
2017-05-19 05:38:41 +08:00
|
|
|
|
2021-04-23 16:26:26 +08:00
|
|
|
_, img, err := util.FindImage(store, "", systemContext, options.Image)
|
2018-05-02 03:37:13 +08:00
|
|
|
if err != nil {
|
2020-11-10 19:58:31 +08:00
|
|
|
return nil, errors.Wrapf(err, "importing settings")
|
2018-05-02 03:37:13 +08:00
|
|
|
}
|
2017-05-19 05:38:41 +08:00
|
|
|
|
2018-05-02 03:37:13 +08:00
|
|
|
builder, err := importBuilderDataFromImage(ctx, store, systemContext, img.ID, "", "")
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "error importing build settings from image %q", options.Image)
|
2017-06-29 05:07:58 +08:00
|
|
|
}
|
2018-05-02 03:37:13 +08:00
|
|
|
|
2021-05-08 01:38:44 +08:00
|
|
|
builder.setupLogger()
|
2018-05-02 03:37:13 +08:00
|
|
|
return builder, nil
|
2017-05-19 05:38:41 +08:00
|
|
|
}
|