2017-02-11 00:48:15 +08:00
package buildah
import (
2018-04-12 22:20:36 +08:00
"context"
2017-02-11 00:48:15 +08:00
"fmt"
2018-10-20 02:49:51 +08:00
"math/rand"
2017-03-24 04:18:40 +08:00
"strings"
2017-02-11 00:48:15 +08:00
2018-09-18 03:20:16 +08:00
"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"
"github.com/containers/image/v5/pkg/sysregistriesv2"
is "github.com/containers/image/v5/storage"
"github.com/containers/image/v5/transports"
"github.com/containers/image/v5/transports/alltransports"
"github.com/containers/image/v5/types"
2017-05-17 23:53:28 +08:00
"github.com/containers/storage"
2019-11-01 03:18:10 +08:00
digest "github.com/opencontainers/go-digest"
2017-03-22 04:57:07 +08:00
"github.com/openshift/imagebuilder"
2017-06-02 03:23:02 +08:00
"github.com/pkg/errors"
2017-10-10 03:05:56 +08:00
"github.com/sirupsen/logrus"
2017-02-11 00:48:15 +08:00
)
const (
2017-02-11 03:45:06 +08:00
// BaseImageFakeName is the "name" of a source image which we interpret
// as "no image".
2017-03-22 04:57:07 +08:00
BaseImageFakeName = imagebuilder . NoBaseImageSpecifier
2017-02-11 00:48:15 +08:00
)
2019-02-22 07:20:36 +08:00
func pullAndFindImage ( ctx context . Context , store storage . Store , srcRef types . ImageReference , options BuilderOptions , sc * types . SystemContext ) ( * storage . Image , types . ImageReference , error ) {
2018-08-09 04:38:53 +08:00
pullOptions := PullOptions {
ReportWriter : options . ReportWriter ,
Store : store ,
SystemContext : options . SystemContext ,
2019-03-14 04:03:13 +08:00
BlobDirectory : options . BlobDirectory ,
2018-08-09 04:38:53 +08:00
}
2019-02-22 07:20:36 +08:00
ref , err := pullImage ( ctx , store , srcRef , pullOptions , sc )
2017-06-29 05:07:58 +08:00
if err != nil {
2019-02-22 07:20:36 +08:00
logrus . Debugf ( "error pulling image %q: %v" , transports . ImageName ( srcRef ) , err )
2017-06-29 05:07:58 +08:00
return nil , nil , err
}
img , err := is . Transport . GetStoreImage ( store , ref )
if err != nil {
2019-02-22 07:20:36 +08:00
logrus . Debugf ( "error reading pulled image %q: %v" , transports . ImageName ( srcRef ) , err )
2018-10-03 22:05:46 +08:00
return nil , nil , errors . Wrapf ( err , "error locating image %q in local storage" , transports . ImageName ( ref ) )
2017-06-29 05:07:58 +08:00
}
return img , ref , nil
}
2018-01-18 20:04:09 +08:00
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
2018-10-03 22:05:46 +08:00
// the image given in the "from" command line.
2018-01-18 20:04:09 +08:00
// This loop is supposed to fix this.
for _ , n := range img . Names {
if strings . Contains ( n , name ) {
imageName = n
break
}
}
}
return imageName
}
2017-06-29 05:07:58 +08:00
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
}
2018-03-13 01:53:12 +08:00
func newContainerIDMappingOptions ( idmapOptions * IDMappingOptions ) storage . IDMappingOptions {
var options storage . IDMappingOptions
if idmapOptions != nil {
options . HostUIDMapping = idmapOptions . HostUIDMapping
options . HostGIDMapping = idmapOptions . HostGIDMapping
uidmap , gidmap := convertRuntimeIDMaps ( idmapOptions . UIDMap , idmapOptions . GIDMap )
if len ( uidmap ) > 0 && len ( gidmap ) > 0 {
options . UIDMap = uidmap
options . GIDMap = gidmap
} else {
options . HostUIDMapping = true
options . HostGIDMapping = true
}
}
return options
}
2018-06-02 02:52:16 +08:00
2019-02-02 20:29:05 +08:00
func resolveImage ( ctx context . Context , systemContext * types . SystemContext , store storage . Store , options BuilderOptions ) ( types . ImageReference , string , * storage . Image , error ) {
Improve reporting about individual pull failures
Instead of just using multierror to collect the error strings (and hope that they
contain enough context about the attempted image names), explicitly collect pairs of
(attempted image name, error).
Then, report an appropriate error text depending on the failures and environment.
Notably, if there was only one attempt (e.g. a fully-qualified name), just report
the error with minimal context, instead of adding extra "1 error occurred:\n\n".
If search registries were used and empty, note that in the error message (now
for real).
Also, make sure we return _some_ error if util.ResolveName ever returned
an empty list for osome reason.
It seems fairly attractive now to split resolveImage into the outer loop
and a separate function for making one attempt, to consolidate the
repetitive failures = append(...) code. OTOH that would force us to add
another return value as a "fatal" indication. Maybe later.
NOTABLY CHANGES BEHAVIOR:
- Changes the error format.
- Restores more detailed error reporting if we have no search registries,
but had multiple candidates anyway, which was given up in the previous commit.
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
Closes: #909
Approved by: rhatdan
2018-08-04 10:14:03 +08:00
type failure struct {
resolvedImageName string
err error
}
2019-02-02 20:29:05 +08:00
candidates , transport , searchRegistriesWereUsedButEmpty , err := util . ResolveName ( options . FromImage , options . Registry , systemContext , store )
2018-08-22 04:33:36 +08:00
if err != nil {
2019-02-02 20:29:05 +08:00
return nil , "" , nil , errors . Wrapf ( err , "error parsing reference to image %q" , options . FromImage )
2018-08-22 04:33:36 +08:00
}
2019-02-02 20:29:05 +08:00
Improve reporting about individual pull failures
Instead of just using multierror to collect the error strings (and hope that they
contain enough context about the attempted image names), explicitly collect pairs of
(attempted image name, error).
Then, report an appropriate error text depending on the failures and environment.
Notably, if there was only one attempt (e.g. a fully-qualified name), just report
the error with minimal context, instead of adding extra "1 error occurred:\n\n".
If search registries were used and empty, note that in the error message (now
for real).
Also, make sure we return _some_ error if util.ResolveName ever returned
an empty list for osome reason.
It seems fairly attractive now to split resolveImage into the outer loop
and a separate function for making one attempt, to consolidate the
repetitive failures = append(...) code. OTOH that would force us to add
another return value as a "fatal" indication. Maybe later.
NOTABLY CHANGES BEHAVIOR:
- Changes the error format.
- Restores more detailed error reporting if we have no search registries,
but had multiple candidates anyway, which was given up in the previous commit.
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
Closes: #909
Approved by: rhatdan
2018-08-04 10:14:03 +08:00
failures := [ ] failure { }
for _ , image := range candidates {
2019-02-22 06:22:38 +08:00
if transport == "" {
img , err := store . Image ( image )
if err != nil {
logrus . Debugf ( "error looking up known-local image %q: %v" , image , err )
failures = append ( failures , failure { resolvedImageName : image , err : err } )
continue
}
ref , err := is . Transport . ParseStoreReference ( store , img . ID )
if err != nil {
return nil , "" , nil , errors . Wrapf ( err , "error parsing reference to image %q" , img . ID )
2017-06-29 05:07:58 +08:00
}
2019-02-22 06:22:38 +08:00
return ref , transport , img , nil
2017-06-29 05:07:58 +08:00
}
2017-02-11 00:48:15 +08:00
2019-02-22 06:33:42 +08:00
trans := transport
if transport != util . DefaultTransport {
trans = trans + ":"
}
srcRef , err := alltransports . ParseImageName ( trans + image )
2018-06-02 02:52:16 +08:00
if err != nil {
2019-02-22 06:33:42 +08:00
logrus . Debugf ( "error parsing image name %q: %v" , trans + image , err )
failures = append ( failures , failure {
resolvedImageName : image ,
err : errors . Wrapf ( err , "error parsing attempted image name %q" , trans + image ) ,
} )
continue
2017-06-29 05:07:58 +08:00
}
2017-07-29 05:29:37 +08:00
2019-02-22 07:11:51 +08:00
if options . PullPolicy == PullAlways {
2019-02-22 07:20:36 +08:00
pulledImg , pulledReference , err := pullAndFindImage ( ctx , store , srcRef , options , systemContext )
2019-02-22 07:11:51 +08:00
if err != nil {
logrus . Debugf ( "unable to pull and read image %q: %v" , image , err )
failures = append ( failures , failure { resolvedImageName : image , err : err } )
continue
}
return pulledReference , transport , pulledImg , nil
}
2019-02-22 07:01:08 +08:00
destImage , err := localImageNameForReference ( ctx , store , srcRef )
2018-06-02 02:52:16 +08:00
if err != nil {
2019-02-02 20:29:05 +08:00
return nil , "" , nil , errors . Wrapf ( err , "error computing local image name for %q" , transports . ImageName ( srcRef ) )
2017-06-29 05:07:58 +08:00
}
if destImage == "" {
2019-02-02 20:29:05 +08:00
return nil , "" , nil , errors . Errorf ( "error computing local image name for %q" , transports . ImageName ( srcRef ) )
2017-06-29 05:07:58 +08:00
}
2017-07-29 05:29:37 +08:00
2018-08-04 08:58:29 +08:00
ref , err := is . Transport . ParseStoreReference ( store , destImage )
2017-06-29 05:07:58 +08:00
if err != nil {
2019-02-02 20:29:05 +08:00
return nil , "" , nil , errors . Wrapf ( err , "error parsing reference to image %q" , destImage )
2017-02-11 00:48:15 +08:00
}
2018-08-04 08:58:29 +08:00
img , err := is . Transport . GetStoreImage ( store , ref )
2018-08-04 08:54:39 +08:00
if err == nil {
2019-02-02 20:29:05 +08:00
return ref , transport , img , nil
2018-08-04 08:54:39 +08:00
}
if errors . Cause ( err ) == storage . ErrImageUnknown && options . PullPolicy != PullIfMissing {
logrus . Debugf ( "no such image %q: %v" , transports . ImageName ( ref ) , err )
Improve reporting about individual pull failures
Instead of just using multierror to collect the error strings (and hope that they
contain enough context about the attempted image names), explicitly collect pairs of
(attempted image name, error).
Then, report an appropriate error text depending on the failures and environment.
Notably, if there was only one attempt (e.g. a fully-qualified name), just report
the error with minimal context, instead of adding extra "1 error occurred:\n\n".
If search registries were used and empty, note that in the error message (now
for real).
Also, make sure we return _some_ error if util.ResolveName ever returned
an empty list for osome reason.
It seems fairly attractive now to split resolveImage into the outer loop
and a separate function for making one attempt, to consolidate the
repetitive failures = append(...) code. OTOH that would force us to add
another return value as a "fatal" indication. Maybe later.
NOTABLY CHANGES BEHAVIOR:
- Changes the error format.
- Restores more detailed error reporting if we have no search registries,
but had multiple candidates anyway, which was given up in the previous commit.
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
Closes: #909
Approved by: rhatdan
2018-08-04 10:14:03 +08:00
failures = append ( failures , failure {
resolvedImageName : image ,
err : fmt . Errorf ( "no such image %q" , transports . ImageName ( ref ) ) ,
} )
2018-08-04 08:54:39 +08:00
continue
}
2019-02-22 07:20:36 +08:00
pulledImg , pulledReference , err := pullAndFindImage ( ctx , store , srcRef , options , systemContext )
2017-02-11 00:48:15 +08:00
if err != nil {
2018-08-04 08:54:39 +08:00
logrus . Debugf ( "unable to pull and read image %q: %v" , image , err )
Improve reporting about individual pull failures
Instead of just using multierror to collect the error strings (and hope that they
contain enough context about the attempted image names), explicitly collect pairs of
(attempted image name, error).
Then, report an appropriate error text depending on the failures and environment.
Notably, if there was only one attempt (e.g. a fully-qualified name), just report
the error with minimal context, instead of adding extra "1 error occurred:\n\n".
If search registries were used and empty, note that in the error message (now
for real).
Also, make sure we return _some_ error if util.ResolveName ever returned
an empty list for osome reason.
It seems fairly attractive now to split resolveImage into the outer loop
and a separate function for making one attempt, to consolidate the
repetitive failures = append(...) code. OTOH that would force us to add
another return value as a "fatal" indication. Maybe later.
NOTABLY CHANGES BEHAVIOR:
- Changes the error format.
- Restores more detailed error reporting if we have no search registries,
but had multiple candidates anyway, which was given up in the previous commit.
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
Closes: #909
Approved by: rhatdan
2018-08-04 10:14:03 +08:00
failures = append ( failures , failure { resolvedImageName : image , err : err } )
2018-08-04 08:54:39 +08:00
continue
2017-02-11 00:48:15 +08:00
}
2019-02-02 20:29:05 +08:00
return pulledReference , transport , pulledImg , nil
2017-06-29 05:07:58 +08:00
}
Improve reporting about individual pull failures
Instead of just using multierror to collect the error strings (and hope that they
contain enough context about the attempted image names), explicitly collect pairs of
(attempted image name, error).
Then, report an appropriate error text depending on the failures and environment.
Notably, if there was only one attempt (e.g. a fully-qualified name), just report
the error with minimal context, instead of adding extra "1 error occurred:\n\n".
If search registries were used and empty, note that in the error message (now
for real).
Also, make sure we return _some_ error if util.ResolveName ever returned
an empty list for osome reason.
It seems fairly attractive now to split resolveImage into the outer loop
and a separate function for making one attempt, to consolidate the
repetitive failures = append(...) code. OTOH that would force us to add
another return value as a "fatal" indication. Maybe later.
NOTABLY CHANGES BEHAVIOR:
- Changes the error format.
- Restores more detailed error reporting if we have no search registries,
but had multiple candidates anyway, which was given up in the previous commit.
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
Closes: #909
Approved by: rhatdan
2018-08-04 10:14:03 +08:00
if len ( failures ) != len ( candidates ) {
2019-02-02 20:29:05 +08:00
return nil , "" , nil , fmt . Errorf ( "internal error: %d candidates (%#v) vs. %d failures (%#v)" , len ( candidates ) , candidates , len ( failures ) , failures )
Improve reporting about individual pull failures
Instead of just using multierror to collect the error strings (and hope that they
contain enough context about the attempted image names), explicitly collect pairs of
(attempted image name, error).
Then, report an appropriate error text depending on the failures and environment.
Notably, if there was only one attempt (e.g. a fully-qualified name), just report
the error with minimal context, instead of adding extra "1 error occurred:\n\n".
If search registries were used and empty, note that in the error message (now
for real).
Also, make sure we return _some_ error if util.ResolveName ever returned
an empty list for osome reason.
It seems fairly attractive now to split resolveImage into the outer loop
and a separate function for making one attempt, to consolidate the
repetitive failures = append(...) code. OTOH that would force us to add
another return value as a "fatal" indication. Maybe later.
NOTABLY CHANGES BEHAVIOR:
- Changes the error format.
- Restores more detailed error reporting if we have no search registries,
but had multiple candidates anyway, which was given up in the previous commit.
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
Closes: #909
Approved by: rhatdan
2018-08-04 10:14:03 +08:00
}
2019-08-02 17:30:22 +08:00
registriesConfPath := sysregistriesv2 . ConfigPath ( systemContext )
Improve reporting about individual pull failures
Instead of just using multierror to collect the error strings (and hope that they
contain enough context about the attempted image names), explicitly collect pairs of
(attempted image name, error).
Then, report an appropriate error text depending on the failures and environment.
Notably, if there was only one attempt (e.g. a fully-qualified name), just report
the error with minimal context, instead of adding extra "1 error occurred:\n\n".
If search registries were used and empty, note that in the error message (now
for real).
Also, make sure we return _some_ error if util.ResolveName ever returned
an empty list for osome reason.
It seems fairly attractive now to split resolveImage into the outer loop
and a separate function for making one attempt, to consolidate the
repetitive failures = append(...) code. OTOH that would force us to add
another return value as a "fatal" indication. Maybe later.
NOTABLY CHANGES BEHAVIOR:
- Changes the error format.
- Restores more detailed error reporting if we have no search registries,
but had multiple candidates anyway, which was given up in the previous commit.
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
Closes: #909
Approved by: rhatdan
2018-08-04 10:14:03 +08:00
switch len ( failures ) {
case 0 :
if searchRegistriesWereUsedButEmpty {
2019-02-02 20:29:05 +08:00
return nil , "" , nil , errors . Errorf ( "image name %q is a short name and no search registries are defined in %s." , options . FromImage , registriesConfPath )
Improve reporting about individual pull failures
Instead of just using multierror to collect the error strings (and hope that they
contain enough context about the attempted image names), explicitly collect pairs of
(attempted image name, error).
Then, report an appropriate error text depending on the failures and environment.
Notably, if there was only one attempt (e.g. a fully-qualified name), just report
the error with minimal context, instead of adding extra "1 error occurred:\n\n".
If search registries were used and empty, note that in the error message (now
for real).
Also, make sure we return _some_ error if util.ResolveName ever returned
an empty list for osome reason.
It seems fairly attractive now to split resolveImage into the outer loop
and a separate function for making one attempt, to consolidate the
repetitive failures = append(...) code. OTOH that would force us to add
another return value as a "fatal" indication. Maybe later.
NOTABLY CHANGES BEHAVIOR:
- Changes the error format.
- Restores more detailed error reporting if we have no search registries,
but had multiple candidates anyway, which was given up in the previous commit.
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
Closes: #909
Approved by: rhatdan
2018-08-04 10:14:03 +08:00
}
2019-02-02 20:29:05 +08:00
return nil , "" , nil , fmt . Errorf ( "internal error: no pull candidates were available for %q for an unknown reason" , options . FromImage )
Improve reporting about individual pull failures
Instead of just using multierror to collect the error strings (and hope that they
contain enough context about the attempted image names), explicitly collect pairs of
(attempted image name, error).
Then, report an appropriate error text depending on the failures and environment.
Notably, if there was only one attempt (e.g. a fully-qualified name), just report
the error with minimal context, instead of adding extra "1 error occurred:\n\n".
If search registries were used and empty, note that in the error message (now
for real).
Also, make sure we return _some_ error if util.ResolveName ever returned
an empty list for osome reason.
It seems fairly attractive now to split resolveImage into the outer loop
and a separate function for making one attempt, to consolidate the
repetitive failures = append(...) code. OTOH that would force us to add
another return value as a "fatal" indication. Maybe later.
NOTABLY CHANGES BEHAVIOR:
- Changes the error format.
- Restores more detailed error reporting if we have no search registries,
but had multiple candidates anyway, which was given up in the previous commit.
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
Closes: #909
Approved by: rhatdan
2018-08-04 10:14:03 +08:00
case 1 :
err := failures [ 0 ] . err
if failures [ 0 ] . resolvedImageName != options . FromImage {
err = errors . Wrapf ( err , "while pulling %q as %q" , options . FromImage , failures [ 0 ] . resolvedImageName )
}
if searchRegistriesWereUsedButEmpty {
err = errors . Wrapf ( err , "(image name %q is a short name and no search registries are defined in %s)" , options . FromImage , registriesConfPath )
}
2019-02-02 20:29:05 +08:00
return nil , "" , nil , err
Improve reporting about individual pull failures
Instead of just using multierror to collect the error strings (and hope that they
contain enough context about the attempted image names), explicitly collect pairs of
(attempted image name, error).
Then, report an appropriate error text depending on the failures and environment.
Notably, if there was only one attempt (e.g. a fully-qualified name), just report
the error with minimal context, instead of adding extra "1 error occurred:\n\n".
If search registries were used and empty, note that in the error message (now
for real).
Also, make sure we return _some_ error if util.ResolveName ever returned
an empty list for osome reason.
It seems fairly attractive now to split resolveImage into the outer loop
and a separate function for making one attempt, to consolidate the
repetitive failures = append(...) code. OTOH that would force us to add
another return value as a "fatal" indication. Maybe later.
NOTABLY CHANGES BEHAVIOR:
- Changes the error format.
- Restores more detailed error reporting if we have no search registries,
but had multiple candidates anyway, which was given up in the previous commit.
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
Closes: #909
Approved by: rhatdan
2018-08-04 10:14:03 +08:00
default :
// NOTE: a multi-line error string:
e := fmt . Sprintf ( "The following failures happened while trying to pull image specified by %q based on search registries in %s:" , options . FromImage , registriesConfPath )
for _ , f := range failures {
e = e + fmt . Sprintf ( "\n* %q: %s" , f . resolvedImageName , f . err . Error ( ) )
}
2019-02-02 20:29:05 +08:00
return nil , "" , nil , errors . New ( e )
2018-08-04 09:29:16 +08:00
}
2018-06-02 02:52:16 +08:00
}
2017-06-29 05:07:58 +08:00
2018-10-20 02:49:51 +08:00
func containerNameExist ( name string , containers [ ] storage . Container ) bool {
for _ , container := range containers {
for _ , cname := range container . Names {
if cname == name {
return true
}
}
}
return false
}
func findUnusedContainer ( name string , containers [ ] storage . Container ) string {
suffix := 1
tmpName := name
for containerNameExist ( tmpName , containers ) {
tmpName = fmt . Sprintf ( "%s-%d" , name , suffix )
suffix ++
}
return tmpName
}
2018-06-02 02:52:16 +08:00
func newBuilder ( ctx context . Context , store storage . Store , options BuilderOptions ) ( * Builder , error ) {
2019-02-02 20:29:05 +08:00
var (
ref types . ImageReference
img * storage . Image
err error
)
2018-06-02 02:52:16 +08:00
if options . FromImage == BaseImageFakeName {
options . FromImage = ""
}
2019-03-14 04:03:13 +08:00
systemContext := getSystemContext ( store , options . SystemContext , options . SignaturePolicyPath )
2018-06-02 02:52:16 +08:00
2018-08-04 09:02:06 +08:00
if options . FromImage != "" && options . FromImage != "scratch" {
2019-02-02 20:29:05 +08:00
ref , _ , img , err = resolveImage ( ctx , systemContext , store , options )
2018-06-02 02:52:16 +08:00
if err != nil {
return nil , err
}
2017-06-29 05:07:58 +08:00
}
2019-11-01 03:18:10 +08:00
imageSpec := options . FromImage
2017-06-29 05:07:58 +08:00
imageID := ""
2019-07-02 05:14:07 +08:00
imageDigest := ""
2018-06-09 00:55:46 +08:00
topLayer := ""
2017-06-29 05:07:58 +08:00
if img != nil {
2019-11-01 03:18:10 +08:00
imageSpec = getImageName ( imageNamePrefix ( imageSpec ) , img )
2017-03-16 05:19:29 +08:00
imageID = img . ID
2018-06-09 00:55:46 +08:00
topLayer = img . TopLayer
2017-06-29 05:07:58 +08:00
}
2019-11-01 03:18:10 +08:00
var src types . Image
2018-06-12 06:31:04 +08:00
if ref != nil {
2019-11-01 03:18:10 +08:00
srcSrc , err := ref . NewImageSource ( ctx , systemContext )
2018-06-12 06:31:04 +08:00
if err != nil {
return nil , errors . Wrapf ( err , "error instantiating image for %q" , transports . ImageName ( ref ) )
}
2019-11-01 03:18:10 +08:00
defer srcSrc . Close ( )
manifestBytes , manifestType , err := srcSrc . 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 ) )
2019-07-02 05:14:07 +08:00
}
2019-11-01 03:18:10 +08:00
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
}
src , err = image . FromUnparsedImage ( ctx , systemContext , image . UnparsedInstance ( srcSrc , instanceDigest ) )
if err != nil {
return nil , errors . Wrapf ( err , "error instantiating image for %q instance %q" , transports . ImageName ( ref ) , instanceDigest )
2019-07-02 05:14:07 +08:00
}
2018-06-12 06:31:04 +08:00
}
2017-07-29 05:29:37 +08:00
name := "working-container"
if options . Container != "" {
name = options . Container
} else {
2019-11-01 03:18:10 +08:00
if imageSpec != "" {
name = imageNamePrefix ( imageSpec ) + "-" + name
2017-07-29 05:29:37 +08:00
}
}
2018-10-20 02:49:51 +08:00
var container * storage . Container
tmpName := name
if options . Container == "" {
containers , err := store . Containers ( )
if err != nil {
return nil , errors . Wrapf ( err , "unable to check for container names" )
}
tmpName = findUnusedContainer ( tmpName , containers )
}
2017-06-29 05:07:58 +08:00
2018-10-20 02:49:51 +08:00
conflict := 100
2019-02-23 10:08:09 +08:00
for {
2018-10-20 02:49:51 +08:00
coptions := storage . ContainerOptions {
LabelOpts : options . CommonBuildOpts . LabelOpts ,
IDMappingOptions : newContainerIDMappingOptions ( options . IDMappingOptions ) ,
}
container , err = store . CreateContainer ( "" , [ ] string { tmpName } , imageID , "" , "" , & coptions )
if err == nil {
2018-09-13 02:34:05 +08:00
name = tmpName
2018-10-20 02:49:51 +08:00
break
2018-09-13 02:34:05 +08:00
}
2018-10-20 02:49:51 +08:00
if errors . Cause ( err ) != storage . ErrDuplicateName || options . Container != "" {
return nil , errors . Wrapf ( err , "error creating container" )
}
tmpName = fmt . Sprintf ( "%s-%d" , name , rand . Int ( ) % conflict )
conflict = conflict * 10
2018-09-13 02:34:05 +08:00
}
2017-02-11 00:48:15 +08:00
defer func ( ) {
if err != nil {
2018-10-18 04:58:32 +08:00
if err2 := store . DeleteContainer ( container . ID ) ; err2 != nil {
2017-02-11 00:48:15 +08:00
logrus . Errorf ( "error deleting container %q: %v" , container . ID , err2 )
}
}
} ( )
2018-03-08 07:11:43 +08:00
uidmap , gidmap := convertStorageIDMaps ( container . UIDMap , container . GIDMap )
2018-06-27 04:35:43 +08:00
defaultNamespaceOptions , err := DefaultNamespaceOptions ( )
if err != nil {
return nil , err
}
namespaceOptions := defaultNamespaceOptions
2018-03-08 07:11:43 +08:00
namespaceOptions . AddOrReplace ( options . NamespaceOptions ... )
2017-10-20 05:47:15 +08:00
2017-02-11 00:48:15 +08:00
builder := & Builder {
2017-11-08 06:44:24 +08:00
store : store ,
Type : containerType ,
2019-11-01 03:18:10 +08:00
FromImage : imageSpec ,
2017-11-08 06:44:24 +08:00
FromImageID : imageID ,
2019-07-02 05:14:07 +08:00
FromImageDigest : imageDigest ,
2017-11-08 06:44:24 +08:00
Container : name ,
ContainerID : container . ID ,
ImageAnnotations : map [ string ] string { } ,
ImageCreatedBy : "" ,
2018-10-20 02:49:51 +08:00
ProcessLabel : container . ProcessLabel ( ) ,
MountLabel : container . MountLabel ( ) ,
2017-11-08 06:44:24 +08:00
DefaultMountsFilePath : options . DefaultMountsFilePath ,
2018-05-12 01:00:14 +08:00
Isolation : options . Isolation ,
2018-03-08 07:11:43 +08:00
NamespaceOptions : namespaceOptions ,
2018-04-14 06:20:25 +08:00
ConfigureNetwork : options . ConfigureNetwork ,
CNIPluginPath : options . CNIPluginPath ,
CNIConfigDir : options . CNIConfigDir ,
2018-03-08 07:11:43 +08:00
IDMappingOptions : IDMappingOptions {
HostUIDMapping : len ( uidmap ) == 0 ,
HostGIDMapping : len ( uidmap ) == 0 ,
UIDMap : uidmap ,
GIDMap : gidmap ,
} ,
2018-06-05 05:36:26 +08:00
AddCapabilities : copyStringSlice ( options . AddCapabilities ) ,
DropCapabilities : copyStringSlice ( options . DropCapabilities ) ,
CommonBuildOpts : options . CommonBuildOpts ,
TopLayer : topLayer ,
2018-06-25 20:53:47 +08:00
Args : options . Args ,
2018-08-24 00:55:16 +08:00
Format : options . Format ,
2019-04-29 21:41:18 +08:00
TempVolumes : map [ string ] bool { } ,
2019-09-07 03:07:18 +08:00
Devices : options . Devices ,
2017-02-11 00:48:15 +08:00
}
if options . Mount {
2018-10-20 02:49:51 +08:00
_ , err = builder . Mount ( container . MountLabel ( ) )
2017-02-11 00:48:15 +08:00
if err != nil {
2018-10-03 22:05:46 +08:00
return nil , errors . Wrapf ( err , "error mounting build container %q" , builder . ContainerID )
2017-02-11 00:48:15 +08:00
}
}
2018-06-12 06:41:11 +08:00
if err := builder . initConfig ( ctx , src ) ; err != nil {
2018-06-12 05:43:21 +08:00
return nil , errors . Wrapf ( err , "error preparing image configuration" )
}
2017-02-11 00:48:15 +08:00
err = builder . Save ( )
if err != nil {
2018-10-03 22:05:46 +08:00
return nil , errors . Wrapf ( err , "error saving builder state for container %q" , builder . ContainerID )
2017-02-11 00:48:15 +08:00
}
return builder , nil
}