Support parallel execution of extract for internal callers
@@ -32,6 +32,7 @@ import (
"github.com/openshift/origin/pkg/image/registryclient/dockercredentials"
"github.com/openshift/origin/pkg/oc/cli/image/archive"
imagemanifest "github.com/openshift/origin/pkg/oc/cli/image/manifest"
+ "github.com/openshift/origin/pkg/oc/cli/image/workqueue"
)
var (
@@ -110,7 +111,7 @@ func NewOptions(streams genericclioptions.IOStreams) *Options {
Paths: []string{"/:."},
IOStreams: streams,
- MaxPerRegistry: 3,
+ MaxPerRegistry: 1,
}
}
@@ -138,8 +139,6 @@ func New(name string, streams genericclioptions.IOStreams) *cobra.Command {
flag.StringSliceVar(&o.Paths, "path", o.Paths, "Extract only part of an image. Must be SRC:DST where SRC is the path within the image and DST a local directory. If not specified the default is to extract everything to the current directory.")
flag.BoolVar(&o.OnlyFiles, "only-files", o.OnlyFiles, "Only extract regular files and directories from the image.")
- flag.IntVar(&o.MaxPerRegistry, "max-per-registry", o.MaxPerRegistry, "Number of concurrent requests allowed per registry.")
-
return cmd
}
@@ -148,13 +147,20 @@ type LayerFilter interface {
}
type Mapping struct {
+ // Name is provided for caller convenience for associating image callback metadata with a mapping
+ Name string
+ // Image is the raw input image to extract
Image string
+ // ImageRef is the parsed version of the raw input image
ImageRef imagereference.DockerImageReference
-
+ // LayerFilter can select which images to load
LayerFilter LayerFilter
-
+ // From is the directory or file in the image to extract
From string
+ // To is the directory to extract the contents of the directory or the named file into.
To string
+ // ConditionFn is invoked before extracting the content and allows the set of images to be filtered.
+ ConditionFn func(m *Mapping, dgst digest.Digest, imageConfig *docker10.DockerImageConfig) (bool, error)
}
func parseMappings(images, paths []string) ([]Mapping, error) {
@@ -249,9 +255,13 @@ func (o *Options) Run() error {
ctx := context.Background()
fromContext := registryclient.NewContext(rt, insecureRT).WithCredentials(creds)
+ stopCh := make(chan struct{})
+ defer close(stopCh)
+ q := workqueue.New(o.MaxPerRegistry, stopCh)
+ return q.Try(func(q workqueue.Try) {
for _, mapping := range o.Mappings {
from := mapping.ImageRef
-
+ q.Try(func() error {
repo, err := fromContext.Repository(ctx, from.DockerClientDefaults().RegistryURL(), from.RepositoryName(), o.Insecure)
if err != nil {
return err
@@ -267,6 +277,17 @@ func (o *Options) Run() error {
return fmt.Errorf("unable to parse image %s: %v", from, err)
}
+ if mapping.ConditionFn != nil {
+ ok, err := mapping.ConditionFn(&mapping, srcDigest, imageConfig)
+ if err != nil {
+ return fmt.Errorf("unable to check whether to include image %s: %v", from, err)
+ }
+ if !ok {
+ glog.V(2).Infof("Filtered out image %s with digest %s from being extracted", from, srcDigest)
+ return nil
+ }
+ }
+
var alter alterations
if o.OnlyFiles {
alter = append(alter, filesOnly{})
@@ -330,8 +351,10 @@ func (o *Options) Run() error {
if o.ImageMetadataCallback != nil {
o.ImageMetadataCallback(&mapping, srcDigest, imageConfig)
}
- }
return nil
+ })
+ }
+ })
}
func printLayer(w io.Writer, r io.Reader, path string, options *archive.TarOptions) error {
