Skip to content

Commit 9944151

Browse files
committed
Isolate manifest handling in release-extraction
This pull adds a new type `ManifestReceiver` that works as a middleware between the upstream `extract.ExtractOptions`'s `TarEntryCallback` and the downstream `manifestsCallback`. There are two files `image-references` and `release-metadata` that are handled differently from manifest files. When those files come, their readers from the upstream are sent to the downstream callback right away. Other files contain manifests. They are parsed out and then sent to the downstream. We will embed more changes into this part, e.g., collecting all manifests in the image and then use them to calculate the enabled capabilities which are sent as an argument to the downstream callback. Those changes are coming in other pulls.
1 parent ea5c720 commit 9944151

File tree

2 files changed

+48
-26
lines changed

2 files changed

+48
-26
lines changed

pkg/cli/admin/release/extract.go

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"fmt"
99
"io"
1010
"os"
11-
"path"
1211
"path/filepath"
1312
"sync"
1413
"time"
@@ -20,6 +19,7 @@ import (
2019

2120
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2221
"k8s.io/apimachinery/pkg/runtime/schema"
22+
"k8s.io/apimachinery/pkg/util/sets"
2323
"k8s.io/cli-runtime/pkg/genericiooptions"
2424
"k8s.io/client-go/rest"
2525
kcmdutil "k8s.io/kubectl/pkg/cmd/util"
@@ -349,7 +349,7 @@ func (o *ExtractOptions) Run(ctx context.Context) error {
349349
}
350350
}
351351

352-
var manifestErrs []error
352+
manifestReceiver := ManifestReceiver{skipNames: sets.New[string]("image-references", "release-metadata")}
353353
// o.ExtractManifests implies o.File == ""
354354
if o.ExtractManifests {
355355
expectedProviderSpecKind := credRequestCloudProviderSpecKindMapping[o.Cloud]
@@ -379,8 +379,8 @@ func (o *ExtractOptions) Run(ctx context.Context) error {
379379
include = newIncluder(inclusionConfig)
380380
}
381381

382-
opts.TarEntryCallback = func(hdr *tar.Header, _ extract.LayerInfo, r io.Reader) (bool, error) {
383-
if hdr.Name == "image-references" && !o.CredentialsRequests {
382+
manifestReceiver.manifestsCallback = func(filename string, ms []manifest.Manifest, r io.Reader) (bool, error) {
383+
if filename == "image-references" && !o.CredentialsRequests {
384384
buf := &bytes.Buffer{}
385385
if _, err := io.Copy(buf, r); err != nil {
386386
return false, fmt.Errorf("unable to load image-references from release payload: %w", err)
@@ -398,7 +398,7 @@ func (o *ExtractOptions) Run(ctx context.Context) error {
398398

399399
out := o.Out
400400
if o.Directory != "" {
401-
out, err = os.Create(filepath.Join(o.Directory, hdr.Name))
401+
out, err = os.Create(filepath.Join(o.Directory, filename))
402402
if err != nil {
403403
return false, err
404404
}
@@ -408,10 +408,10 @@ func (o *ExtractOptions) Run(ctx context.Context) error {
408408
return true, err
409409
}
410410
return true, nil
411-
} else if hdr.Name == "release-metadata" && !o.CredentialsRequests {
411+
} else if filename == "release-metadata" && !o.CredentialsRequests {
412412
out := o.Out
413413
if o.Directory != "" {
414-
out, err = os.Create(filepath.Join(o.Directory, hdr.Name))
414+
out, err = os.Create(filepath.Join(o.Directory, filename))
415415
if err != nil {
416416
return false, err
417417
}
@@ -423,16 +423,6 @@ func (o *ExtractOptions) Run(ctx context.Context) error {
423423
return true, nil
424424
}
425425

426-
if ext := path.Ext(hdr.Name); len(ext) == 0 || !(ext == ".yaml" || ext == ".yml" || ext == ".json") {
427-
return true, nil
428-
}
429-
klog.V(4).Infof("Found manifest %s", hdr.Name)
430-
ms, err := manifest.ParseManifests(r)
431-
if err != nil {
432-
manifestErrs = append(manifestErrs, errors.Wrapf(err, "error parsing %s", hdr.Name))
433-
return true, nil
434-
}
435-
436426
for i := len(ms) - 1; i >= 0; i-- {
437427
if o.Included && o.CredentialsRequests && ms[i].GVK == credentialsRequestGVK && len(ms[i].Obj.GetAnnotations()) == 0 {
438428
klog.V(4).Infof("Including %s for manual CredentialsRequests, despite lack of annotations", ms[i].String())
@@ -469,25 +459,26 @@ func (o *ExtractOptions) Run(ctx context.Context) error {
469459

470460
out := o.Out
471461
if o.Directory != "" {
472-
out, err = os.Create(filepath.Join(o.Directory, hdr.Name))
462+
out, err = os.Create(filepath.Join(o.Directory, filename))
473463
if err != nil {
474-
return false, errors.Wrapf(err, "error creating manifest in %s", hdr.Name)
464+
return false, errors.Wrapf(err, "error creating manifest in %s", filename)
475465
}
476466
}
477467
if out != nil {
478468
for _, m := range manifestsToWrite {
479469
yamlBytes, err := yaml.JSONToYAML(m.Raw)
480470
if err != nil {
481-
return false, errors.Wrapf(err, "error serializing manifest in %s", hdr.Name)
471+
return false, errors.Wrapf(err, "error serializing manifest in %s", filename)
482472
}
483473
fmt.Fprintf(out, "---\n")
484474
if _, err := out.Write(yamlBytes); err != nil {
485-
return false, errors.Wrapf(err, "error writing manifest in %s", hdr.Name)
475+
return false, errors.Wrapf(err, "error writing manifest in %s", filename)
486476
}
487477
}
488478
}
489479
return true, nil
490480
}
481+
opts.TarEntryCallback = manifestReceiver.TarEntryCallback
491482
}
492483

493484
fileFound := false
@@ -506,6 +497,7 @@ func (o *ExtractOptions) Run(ctx context.Context) error {
506497
return err
507498
}
508499

500+
manifestErrs := manifestReceiver.ManifestErrs
509501
if metadataVerifyMsg != "" {
510502
if o.File == "" && o.Out != nil {
511503
fmt.Fprintf(o.Out, "%s\n", metadataVerifyMsg)

pkg/cli/admin/release/extract_tools.go

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"hash"
1414
"io"
1515
"os"
16+
"path"
1617
"path/filepath"
1718
"regexp"
1819
"runtime"
@@ -21,25 +22,25 @@ import (
2122
"sync"
2223
"syscall"
2324

24-
"k8s.io/utils/ptr"
25-
25+
"github.com/MakeNowJust/heredoc"
26+
"github.com/pkg/errors"
2627
"golang.org/x/crypto/openpgp"
2728
terminal "golang.org/x/term"
2829

29-
"k8s.io/klog/v2"
30-
3130
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3231
"k8s.io/apimachinery/pkg/util/sets"
3332
"k8s.io/cli-runtime/pkg/genericiooptions"
3433
appsv1client "k8s.io/client-go/kubernetes/typed/apps/v1"
3534
"k8s.io/client-go/rest"
35+
"k8s.io/klog/v2"
36+
"k8s.io/utils/ptr"
3637
"sigs.k8s.io/yaml"
3738

38-
"github.com/MakeNowJust/heredoc"
3939
configv1 "github.com/openshift/api/config/v1"
4040
configv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"
4141
imagereference "github.com/openshift/library-go/pkg/image/reference"
4242
"github.com/openshift/library-go/pkg/manifest"
43+
4344
"github.com/openshift/oc/pkg/cli/admin/internal/codesign"
4445
"github.com/openshift/oc/pkg/cli/image/extract"
4546
"github.com/openshift/oc/pkg/cli/image/imagesource"
@@ -1286,3 +1287,32 @@ func newIncluder(config manifestInclusionConfiguration) includer {
12861287
return m.Include(config.ExcludeIdentifier, config.RequiredFeatureSet, config.Profile, config.Capabilities, config.Overrides)
12871288
}
12881289
}
1290+
1291+
// ManifestReceiver has a TarEntryCallback function which can be used to as a callback to ExtractOptions.TarEntryCallback.
1292+
// It feeds the downstream manifestsCallback
1293+
// * with the manifests from every file whose name is not in skipNames, OR
1294+
// * with the reader that contains the content of each file whose name is in skipNames.
1295+
// All the errors encountered when parsing the manifests are collected in ManifestErrs.
1296+
type ManifestReceiver struct {
1297+
manifestsCallback func(filename string, manifests []manifest.Manifest, reader io.Reader) (cont bool, err error)
1298+
skipNames sets.Set[string]
1299+
1300+
ManifestErrs []error
1301+
}
1302+
1303+
func (mr *ManifestReceiver) TarEntryCallback(h *tar.Header, _ extract.LayerInfo, r io.Reader) (cont bool, err error) {
1304+
if mr.skipNames.Has(h.Name) {
1305+
return mr.manifestsCallback(h.Name, nil, r)
1306+
}
1307+
1308+
if ext := path.Ext(h.Name); len(ext) == 0 || !(ext == ".yaml" || ext == ".yml" || ext == ".json") {
1309+
return true, nil
1310+
}
1311+
klog.V(4).Infof("Found manifest %s", h.Name)
1312+
ms, err := manifest.ParseManifests(r)
1313+
if err != nil {
1314+
mr.ManifestErrs = append(mr.ManifestErrs, errors.Wrapf(err, "error parsing %s", h.Name))
1315+
return true, nil
1316+
}
1317+
return mr.manifestsCallback(h.Name, ms, nil)
1318+
}

0 commit comments

Comments
 (0)