diff options
Diffstat (limited to 'vendor/github.com/projectatomic/buildah/new.go')
-rw-r--r-- | vendor/github.com/projectatomic/buildah/new.go | 313 |
1 files changed, 313 insertions, 0 deletions
diff --git a/vendor/github.com/projectatomic/buildah/new.go b/vendor/github.com/projectatomic/buildah/new.go new file mode 100644 index 000000000..82de524c0 --- /dev/null +++ b/vendor/github.com/projectatomic/buildah/new.go @@ -0,0 +1,313 @@ +package buildah + +import ( + "context" + "fmt" + "os" + "strings" + + is "github.com/containers/image/storage" + "github.com/containers/image/transports" + "github.com/containers/image/transports/alltransports" + "github.com/containers/image/types" + "github.com/containers/storage" + "github.com/opencontainers/selinux/go-selinux" + "github.com/opencontainers/selinux/go-selinux/label" + "github.com/openshift/imagebuilder" + "github.com/pkg/errors" + "github.com/projectatomic/buildah/util" + "github.com/sirupsen/logrus" +) + +const ( + // BaseImageFakeName is the "name" of a source image which we interpret + // as "no image". + BaseImageFakeName = imagebuilder.NoBaseImageSpecifier + + // DefaultTransport is a prefix that we apply to an image name if we + // can't find one in the local Store, in order to generate a source + // reference for the image that we can then copy to the local Store. + DefaultTransport = "docker://" + + // minimumTruncatedIDLength is the minimum length of an identifier that + // we'll accept as possibly being a truncated image ID. + minimumTruncatedIDLength = 3 +) + +func reserveSELinuxLabels(store storage.Store, id string) error { + if selinux.GetEnabled() { + containers, err := store.Containers() + if err != nil { + return err + } + + for _, c := range containers { + if id == c.ID { + continue + } else { + b, err := OpenBuilder(store, c.ID) + if err != nil { + if os.IsNotExist(err) { + // Ignore not exist errors since containers probably created by other tool + // TODO, we need to read other containers json data to reserve their SELinux labels + continue + } + return err + } + // Prevent containers from using same MCS Label + if err := label.ReserveLabel(b.ProcessLabel); err != nil { + return err + } + } + } + } + return nil +} + +func pullAndFindImage(ctx context.Context, store storage.Store, imageName string, options BuilderOptions, sc *types.SystemContext) (*storage.Image, types.ImageReference, error) { + ref, err := pullImage(ctx, store, imageName, options, sc) + if err != nil { + logrus.Debugf("error pulling image %q: %v", imageName, err) + return nil, nil, err + } + img, err := is.Transport.GetStoreImage(store, ref) + if err != nil { + logrus.Debugf("error reading pulled image %q: %v", imageName, err) + return nil, nil, err + } + return img, ref, nil +} + +func getImageName(name string, img *storage.Image) string { + imageName := name + if len(img.Names) > 0 { + imageName = img.Names[0] + // When the image used by the container is a tagged image + // the container name might be set to the original image instead of + // the image given in the "form" command line. + // This loop is supposed to fix this. + for _, n := range img.Names { + if strings.Contains(n, name) { + imageName = n + break + } + } + } + return imageName +} + +func imageNamePrefix(imageName string) string { + prefix := imageName + s := strings.Split(imageName, "/") + if len(s) > 0 { + prefix = s[len(s)-1] + } + s = strings.Split(prefix, ":") + if len(s) > 0 { + prefix = s[0] + } + s = strings.Split(prefix, "@") + if len(s) > 0 { + prefix = s[0] + } + return prefix +} + +func imageManifestAndConfig(ctx context.Context, ref types.ImageReference, systemContext *types.SystemContext) (manifest, config []byte, err error) { + if ref != nil { + src, err := ref.NewImage(ctx, systemContext) + if err != nil { + return nil, nil, errors.Wrapf(err, "error instantiating image for %q", transports.ImageName(ref)) + } + defer src.Close() + config, err := src.ConfigBlob(ctx) + if err != nil { + return nil, nil, errors.Wrapf(err, "error reading image configuration for %q", transports.ImageName(ref)) + } + manifest, _, err := src.Manifest(ctx) + if err != nil { + return nil, nil, errors.Wrapf(err, "error reading image manifest for %q", transports.ImageName(ref)) + } + return manifest, config, nil + } + return nil, nil, nil +} + +func newBuilder(ctx context.Context, store storage.Store, options BuilderOptions) (*Builder, error) { + var ref types.ImageReference + var img *storage.Image + var err error + var manifest []byte + var config []byte + + if options.FromImage == BaseImageFakeName { + options.FromImage = "" + } + if options.Transport == "" { + options.Transport = DefaultTransport + } + + systemContext := getSystemContext(options.SystemContext, options.SignaturePolicyPath) + + for _, image := range util.ResolveName(options.FromImage, options.Registry, systemContext, store) { + if len(image) >= minimumTruncatedIDLength { + if img, err = store.Image(image); err == nil && img != nil && strings.HasPrefix(img.ID, image) { + if ref, err = is.Transport.ParseStoreReference(store, img.ID); err != nil { + return nil, errors.Wrapf(err, "error parsing reference to image %q", img.ID) + } + break + } + } + + if options.PullPolicy == PullAlways { + pulledImg, pulledReference, err2 := pullAndFindImage(ctx, store, image, options, systemContext) + if err2 != nil { + logrus.Debugf("error pulling and reading image %q: %v", image, err2) + err = err2 + continue + } + ref = pulledReference + img = pulledImg + break + } + + srcRef, err2 := alltransports.ParseImageName(image) + if err2 != nil { + if options.Transport == "" { + logrus.Debugf("error parsing image name %q: %v", image, err2) + err = err2 + continue + } + transport := options.Transport + if transport != DefaultTransport { + transport = transport + ":" + } + srcRef2, err3 := alltransports.ParseImageName(transport + image) + if err3 != nil { + logrus.Debugf("error parsing image name %q: %v", image, err2) + err = err3 + continue + } + srcRef = srcRef2 + } + + destImage, err2 := localImageNameForReference(ctx, store, srcRef, options.FromImage) + if err2 != nil { + return nil, errors.Wrapf(err2, "error computing local image name for %q", transports.ImageName(srcRef)) + } + if destImage == "" { + return nil, errors.Errorf("error computing local image name for %q", transports.ImageName(srcRef)) + } + + ref, err = is.Transport.ParseStoreReference(store, destImage) + if err != nil { + return nil, errors.Wrapf(err, "error parsing reference to image %q", destImage) + } + img, err = is.Transport.GetStoreImage(store, ref) + if err != nil { + if errors.Cause(err) == storage.ErrImageUnknown && options.PullPolicy != PullIfMissing { + logrus.Debugf("no such image %q: %v", transports.ImageName(ref), err) + continue + } + pulledImg, pulledReference, err2 := pullAndFindImage(ctx, store, image, options, systemContext) + if err2 != nil { + logrus.Debugf("error pulling and reading image %q: %v", image, err2) + err = err2 + continue + } + ref = pulledReference + img = pulledImg + } + break + } + + if options.FromImage != "" && (ref == nil || img == nil) { + // If options.FromImage is set but we ended up + // with nil in ref or in img then there was an error that + // we should return. + return nil, util.GetFailureCause(err, errors.Wrapf(storage.ErrImageUnknown, "no such image %q in registry", options.FromImage)) + } + image := options.FromImage + imageID := "" + if img != nil { + image = getImageName(imageNamePrefix(image), img) + imageID = img.ID + } + if manifest, config, err = imageManifestAndConfig(ctx, ref, systemContext); err != nil { + return nil, errors.Wrapf(err, "error reading data from image %q", transports.ImageName(ref)) + } + + name := "working-container" + if options.Container != "" { + name = options.Container + } else { + var err2 error + if image != "" { + name = imageNamePrefix(image) + "-" + name + } + suffix := 1 + tmpName := name + for errors.Cause(err2) != storage.ErrContainerUnknown { + _, err2 = store.Container(tmpName) + if err2 == nil { + suffix++ + tmpName = fmt.Sprintf("%s-%d", name, suffix) + } + } + name = tmpName + } + + coptions := storage.ContainerOptions{} + container, err := store.CreateContainer("", []string{name}, imageID, "", "", &coptions) + if err != nil { + return nil, errors.Wrapf(err, "error creating container") + } + + defer func() { + if err != nil { + if err2 := store.DeleteContainer(container.ID); err != nil { + logrus.Errorf("error deleting container %q: %v", container.ID, err2) + } + } + }() + + if err = reserveSELinuxLabels(store, container.ID); err != nil { + return nil, err + } + processLabel, mountLabel, err := label.InitLabels(options.CommonBuildOpts.LabelOpts) + if err != nil { + return nil, err + } + + builder := &Builder{ + store: store, + Type: containerType, + FromImage: image, + FromImageID: imageID, + Config: config, + Manifest: manifest, + Container: name, + ContainerID: container.ID, + ImageAnnotations: map[string]string{}, + ImageCreatedBy: "", + ProcessLabel: processLabel, + MountLabel: mountLabel, + DefaultMountsFilePath: options.DefaultMountsFilePath, + CommonBuildOpts: options.CommonBuildOpts, + } + + if options.Mount { + _, err = builder.Mount(mountLabel) + if err != nil { + return nil, errors.Wrapf(err, "error mounting build container") + } + } + + builder.initConfig() + err = builder.Save() + if err != nil { + return nil, errors.Wrapf(err, "error saving builder state") + } + + return builder, nil +} |