@@ -18,14 +18,18 @@ import (
1818 "k8s.io/klog/v2"
1919 "sigs.k8s.io/yaml"
2020
21+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2122 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2223 "k8s.io/apimachinery/pkg/runtime/schema"
24+ "k8s.io/apimachinery/pkg/util/sets"
2325 "k8s.io/cli-runtime/pkg/genericiooptions"
2426 "k8s.io/client-go/rest"
2527 kcmdutil "k8s.io/kubectl/pkg/cmd/util"
2628 "k8s.io/kubectl/pkg/util/templates"
2729
30+ configv1 "github.com/openshift/api/config/v1"
2831 imagev1 "github.com/openshift/api/image/v1"
32+ configv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"
2933 "github.com/openshift/library-go/pkg/image/dockerv1client"
3034 "github.com/openshift/library-go/pkg/manifest"
3135 "github.com/openshift/oc/pkg/cli/image/extract"
@@ -349,17 +353,16 @@ func (o *ExtractOptions) Run(ctx context.Context) error {
349353 }
350354 }
351355
352- tarEntryCallbacks := []extract. TarEntryFunc {}
356+ var manifestsCallbacks []func ( string , []manifest. Manifest , io. Reader , []configv1. ClusterVersionCapability ) ( bool , error )
353357
354- var manifestErrs []error
358+ var needEnabledCapabilities bool
359+ inclusionConfig := manifestInclusionConfiguration {}
355360 if o .ExtractManifests {
356361 expectedProviderSpecKind := credRequestCloudProviderSpecKindMapping [o .Cloud ]
357-
358- include := func (m * manifest.Manifest ) error { return nil } // default to including everything
359362 if o .Included {
360363 context := "connected cluster"
361- inclusionConfig := manifestInclusionConfiguration {}
362364 if o .InstallConfig == "" {
365+ needEnabledCapabilities = true
363366 inclusionConfig , err = findClusterIncludeConfig (ctx , o .RESTConfig )
364367 } else {
365368 inclusionConfig , err = findClusterIncludeConfigFromInstallConfig (ctx , o .InstallConfig )
@@ -377,11 +380,10 @@ func (o *ExtractOptions) Run(ctx context.Context) error {
377380 return fmt .Errorf ("unrecognized platform for CredentialsRequests: %q" , * inclusionConfig .Platform )
378381 }
379382 }
380- include = newIncluder (inclusionConfig )
381383 }
382384
383- tarEntryCallbacks = append (tarEntryCallbacks , func (hdr * tar. Header , _ extract. LayerInfo , r io.Reader ) (bool , error ) {
384- if hdr . Name == "image-references" && ! o .CredentialsRequests {
385+ manifestsCallbacks = append (manifestsCallbacks , func (name string , ms []manifest. Manifest , r io.Reader , enabled []configv1. ClusterVersionCapability ) (cont bool , err error ) {
386+ if name == "image-references" && ! o .CredentialsRequests {
385387 buf := & bytes.Buffer {}
386388 if _ , err := io .Copy (buf , r ); err != nil {
387389 return false , fmt .Errorf ("unable to load image-references from release payload: %w" , err )
@@ -399,7 +401,7 @@ func (o *ExtractOptions) Run(ctx context.Context) error {
399401
400402 out := o .Out
401403 if o .Directory != "" {
402- out , err = os .Create (filepath .Join (o .Directory , hdr . Name ))
404+ out , err = os .Create (filepath .Join (o .Directory , name ))
403405 if err != nil {
404406 return false , err
405407 }
@@ -409,10 +411,10 @@ func (o *ExtractOptions) Run(ctx context.Context) error {
409411 return true , err
410412 }
411413 return true , nil
412- } else if hdr . Name == "release-metadata" && ! o .CredentialsRequests {
414+ } else if name == "release-metadata" && ! o .CredentialsRequests {
413415 out := o .Out
414416 if o .Directory != "" {
415- out , err = os .Create (filepath .Join (o .Directory , hdr . Name ))
417+ out , err = os .Create (filepath .Join (o .Directory , name ))
416418 if err != nil {
417419 return false , err
418420 }
@@ -424,22 +426,18 @@ func (o *ExtractOptions) Run(ctx context.Context) error {
424426 return true , nil
425427 }
426428
427- if ext := path .Ext (hdr .Name ); len (ext ) == 0 || ! (ext == ".yaml" || ext == ".yml" || ext == ".json" ) {
428- return true , nil
429- }
430- klog .V (4 ).Infof ("Found manifest %s" , hdr .Name )
431- ms , err := manifest .ParseManifests (r )
432- if err != nil {
433- manifestErrs = append (manifestErrs , errors .Wrapf (err , "error parsing %s" , hdr .Name ))
434- return true , nil
435- }
436-
437429 for i := len (ms ) - 1 ; i >= 0 ; i -- {
438430 if o .Included && o .CredentialsRequests && ms [i ].GVK == credentialsRequestGVK && len (ms [i ].Obj .GetAnnotations ()) == 0 {
439431 klog .V (4 ).Infof ("Including %s for manual CredentialsRequests, despite lack of annotations" , ms [i ].String ())
440- } else if err := include (& ms [i ]); err != nil {
441- klog .V (4 ).Infof ("Excluding %s: %s" , ms [i ].String (), err )
442- ms = append (ms [:i ], ms [i + 1 :]... )
432+ } else if o .Included {
433+ clusterVersionCapabilitiesStatus := & configv1.ClusterVersionCapabilitiesStatus {
434+ KnownCapabilities : sets .New [configv1.ClusterVersionCapability ](append (inclusionConfig .Capabilities .KnownCapabilities , configv1 .KnownClusterVersionCapabilities ... )... ).UnsortedList (),
435+ EnabledCapabilities : sets .New [configv1.ClusterVersionCapability ](append (inclusionConfig .Capabilities .EnabledCapabilities , enabled ... )... ).UnsortedList (),
436+ }
437+ if err := ms [i ].Include (inclusionConfig .ExcludeIdentifier , inclusionConfig .RequiredFeatureSet , inclusionConfig .Profile , clusterVersionCapabilitiesStatus , inclusionConfig .Overrides ); err != nil {
438+ klog .V (4 ).Infof ("Excluding %s: %s" , ms [i ].String (), err )
439+ ms = append (ms [:i ], ms [i + 1 :]... )
440+ }
443441 }
444442 }
445443
@@ -470,20 +468,20 @@ func (o *ExtractOptions) Run(ctx context.Context) error {
470468
471469 out := o .Out
472470 if o .Directory != "" {
473- out , err = os .Create (filepath .Join (o .Directory , hdr . Name ))
471+ out , err = os .Create (filepath .Join (o .Directory , name ))
474472 if err != nil {
475- return false , errors .Wrapf (err , "error creating manifest in %s" , hdr . Name )
473+ return false , errors .Wrapf (err , "error creating manifest in %s" , name )
476474 }
477475 }
478476 if out != nil {
479477 for _ , m := range manifestsToWrite {
480478 yamlBytes , err := yaml .JSONToYAML (m .Raw )
481479 if err != nil {
482- return false , errors .Wrapf (err , "error serializing manifest in %s" , hdr . Name )
480+ return false , errors .Wrapf (err , "error serializing manifest in %s" , name )
483481 }
484482 fmt .Fprintf (out , "---\n " )
485483 if _ , err := out .Write (yamlBytes ); err != nil {
486- return false , errors .Wrapf (err , "error writing manifest in %s" , hdr . Name )
484+ return false , errors .Wrapf (err , "error writing manifest in %s" , name )
487485 }
488486 }
489487 }
@@ -493,39 +491,72 @@ func (o *ExtractOptions) Run(ctx context.Context) error {
493491
494492 fileFound := false
495493 if o .File != "" {
496- tarEntryCallbacks = append (tarEntryCallbacks , func (hdr * tar. Header , _ extract. LayerInfo , r io.Reader ) (bool , error ) {
497- if hdr . Name != o .File {
494+ manifestsCallbacks = append (manifestsCallbacks , func (name string , _ []manifest. Manifest , r io.Reader , _ []configv1. ClusterVersionCapability ) (bool , error ) {
495+ if name != o .File {
498496 return true , nil
499497 }
500498 fileFound = true
501499 _ , err := io .Copy (o .Out , r )
502500 return false , err
503501 })
504502 }
505-
506- if len (tarEntryCallbacks ) > 0 {
507- tarEntryCallbacksDone := make ([]bool , len (tarEntryCallbacks ))
508- opts .TarEntryCallback = func (hdr * tar.Header , layer extract.LayerInfo , r io.Reader ) (bool , error ) {
509- for i , callback := range tarEntryCallbacks {
510- if tarEntryCallbacksDone [i ] {
503+ manifestsCallback := func (name string , ms []manifest.Manifest , r io.Reader , enabled []configv1.ClusterVersionCapability ) (bool , error ) {
504+ if len (manifestsCallbacks ) > 0 {
505+ callbacksDone := make ([]bool , len (manifestsCallbacks ))
506+ for i , callback := range manifestsCallbacks {
507+ if callbacksDone [i ] {
511508 continue
512509 }
513- if cont , err := callback (hdr , layer , r ); err != nil {
510+ if cont , err := callback (name , ms , r , enabled ); err != nil {
514511 return cont , err
515512 } else if ! cont {
516- tarEntryCallbacksDone [i ] = true
513+ callbacksDone [i ] = true
517514 }
518515 }
519516
520- for _ , done := range tarEntryCallbacksDone {
517+ for _ , done := range callbacksDone {
521518 if ! done {
522519 return true , nil // still some callbacks that want to keep working
523520 }
524521 }
525522
526523 return false , nil
527524 }
525+ return true , nil
526+ }
527+
528+ var currentPayloadManifests []manifest.Manifest
529+ if needEnabledCapabilities {
530+ optsToGetCurrentPayloadManifests , err := getOptsToGetCurrentPayloadManifests (ctx , opts , o .RESTConfig , inclusionConfig )
531+ if err != nil {
532+ return fmt .Errorf ("error getting opts to get current payload manifests: %w" , err )
533+ }
534+ optsToGetCurrentPayloadManifests .TarEntryCallback = func (h * tar.Header , _ extract.LayerInfo , r io.Reader ) (cont bool , err error ) {
535+ if ext := path .Ext (h .Name ); len (ext ) == 0 || ! (ext == ".yaml" || ext == ".yml" || ext == ".json" ) {
536+ return true , nil
537+ }
538+ klog .V (4 ).Infof ("Found manifest %s in the current release payload" , h .Name )
539+ ms , err := manifest .ParseManifests (r )
540+ if err != nil {
541+ return false , err
542+ }
543+ for i := len (ms ) - 1 ; i >= 0 ; i -- {
544+ if err := ms [i ].Include (inclusionConfig .ExcludeIdentifier , inclusionConfig .RequiredFeatureSet , inclusionConfig .Profile , inclusionConfig .Capabilities , inclusionConfig .Overrides ); err != nil {
545+ klog .V (4 ).Infof ("Excluding %s in the current release payload: %s" , ms [i ].String (), err )
546+ ms = append (ms [:i ], ms [i + 1 :]... )
547+ }
548+ }
549+ currentPayloadManifests = append (currentPayloadManifests , ms ... )
550+ return true , nil
551+ }
552+ if err := optsToGetCurrentPayloadManifests .Run (); err != nil {
553+ return fmt .Errorf ("error getting current payload manifests: %w" , err )
554+ }
555+
528556 }
557+ manifestReceiver := NewManifestReceiver (manifestsCallback , needEnabledCapabilities , sets .New [string ]("image-references" , "release-metadata" ), currentPayloadManifests , inclusionConfig )
558+ opts .TarEntryCallback = manifestReceiver .TarEntryCallback
559+ opts .TarEntryCallbackDoneCallback = manifestReceiver .TarEntryCallbackDoneCallback
529560
530561 if err := opts .Run (); err != nil {
531562 return err
@@ -553,14 +584,48 @@ func (o *ExtractOptions) Run(ctx context.Context) error {
553584
554585 // Only output manifest errors if manifests were being extracted.
555586 // Do not return an error so current operation, e.g. mirroring, continues.
556- if o .ExtractManifests && len (manifestErrs ) > 0 {
557- fmt .Fprintf (o .ErrOut , "Errors: %s\n " , errorList (manifestErrs ))
587+ if o .ExtractManifests && len (manifestReceiver . ManifestErrs ) > 0 {
588+ fmt .Fprintf (o .ErrOut , "Errors: %s\n " , errorList (manifestReceiver . ManifestErrs ))
558589 }
559590
560591 return nil
561592
562593}
563594
595+ func getOptsToGetCurrentPayloadManifests (ctx context.Context , source * extract.ExtractOptions , config * rest.Config , inclusionConfiguration manifestInclusionConfiguration ) (* extract.ExtractOptions , error ) {
596+ client , err := configv1client .NewForConfig (config )
597+ if err != nil {
598+ return nil , err
599+ }
600+
601+ clusterVersion , err := client .ClusterVersions ().Get (ctx , "version" , metav1.GetOptions {})
602+ if err != nil {
603+ return nil , err
604+ }
605+
606+ src := clusterVersion .Status .Desired .Image
607+ ref , err := imagesource .ParseReference (src )
608+ if err != nil {
609+ return nil , err
610+ }
611+ klog .V (4 ).Infof ("The outgoing release payload from %s is running on the cluster: %s" , src , config .Host )
612+ opts := extract .NewExtractOptions (genericiooptions.IOStreams {Out : source .Out , ErrOut : source .ErrOut })
613+ opts .ParallelOptions = source .ParallelOptions
614+ opts .SecurityOptions = source .SecurityOptions
615+ opts .FilterOptions = source .FilterOptions
616+ opts .FileDir = source .FileDir
617+ opts .OnlyFiles = true
618+ opts .ICSPFile = source .ICSPFile
619+ opts .IDMSFile = source .IDMSFile
620+ opts .Mappings = []extract.Mapping {
621+ {
622+ ImageRef : ref ,
623+ From : "release-manifests/" ,
624+ },
625+ }
626+ return opts , nil
627+ }
628+
564629func (o * ExtractOptions ) extractGit (dir string ) error {
565630 switch o .Output {
566631 case "commit" , "" :
0 commit comments