233 lines
6.3 KiB
Go
233 lines
6.3 KiB
Go
package buildah
|
|
|
|
import (
|
|
"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/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://"
|
|
)
|
|
|
|
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 newBuilder(store storage.Store, options BuilderOptions) (*Builder, error) {
|
|
var ref types.ImageReference
|
|
var img *storage.Image
|
|
manifest := []byte{}
|
|
config := []byte{}
|
|
|
|
if options.FromImage == BaseImageFakeName {
|
|
options.FromImage = ""
|
|
}
|
|
image := options.FromImage
|
|
|
|
if options.Transport == "" {
|
|
options.Transport = DefaultTransport
|
|
}
|
|
|
|
systemContext := getSystemContext(options.SignaturePolicyPath)
|
|
|
|
imageID := ""
|
|
if image != "" {
|
|
var err error
|
|
if options.PullPolicy == PullAlways {
|
|
pulledReference, err2 := pullImage(store, options, systemContext)
|
|
if err2 != nil {
|
|
return nil, errors.Wrapf(err2, "error pulling image %q", image)
|
|
}
|
|
ref = pulledReference
|
|
}
|
|
if ref == nil {
|
|
srcRef, err2 := alltransports.ParseImageName(image)
|
|
if err2 != nil {
|
|
srcRef2, err3 := alltransports.ParseImageName(options.Registry + image)
|
|
if err3 != nil {
|
|
srcRef3, err4 := alltransports.ParseImageName(options.Transport + options.Registry + image)
|
|
if err4 != nil {
|
|
return nil, errors.Wrapf(err4, "error parsing image name %q", options.Transport+options.Registry+image)
|
|
}
|
|
srcRef2 = srcRef3
|
|
}
|
|
srcRef = srcRef2
|
|
}
|
|
|
|
destImage, err2 := localImageNameForReference(store, srcRef)
|
|
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)
|
|
}
|
|
|
|
image = destImage
|
|
}
|
|
img, err = is.Transport.GetStoreImage(store, ref)
|
|
if err != nil {
|
|
if errors.Cause(err) == storage.ErrImageUnknown && options.PullPolicy != PullIfMissing {
|
|
return nil, errors.Wrapf(err, "no such image %q", transports.ImageName(ref))
|
|
}
|
|
ref2, err2 := pullImage(store, options, systemContext)
|
|
if err2 != nil {
|
|
return nil, errors.Wrapf(err2, "error pulling image %q", image)
|
|
}
|
|
ref = ref2
|
|
img, err = is.Transport.GetStoreImage(store, ref)
|
|
}
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "no such image %q", transports.ImageName(ref))
|
|
}
|
|
imageID = img.ID
|
|
src, err := ref.NewImage(systemContext)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "error instantiating image for %q", transports.ImageName(ref))
|
|
}
|
|
defer src.Close()
|
|
config, err = src.ConfigBlob()
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "error reading image configuration for %q", transports.ImageName(ref))
|
|
}
|
|
manifest, _, err = src.Manifest()
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "error reading image manifest for %q", transports.ImageName(ref))
|
|
}
|
|
}
|
|
|
|
name := "working-container"
|
|
if options.Container != "" {
|
|
name = options.Container
|
|
} else {
|
|
var err2 error
|
|
if image != "" {
|
|
prefix := image
|
|
s := strings.Split(prefix, "/")
|
|
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]
|
|
}
|
|
name = prefix + "-" + 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(nil)
|
|
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,
|
|
}
|
|
|
|
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
|
|
}
|