github.com/operator-framework/operator-lifecycle-manager@v0.30.0/pkg/package-server/storage/reststorage.go (about)

     1  package storage
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"k8s.io/apimachinery/pkg/fields"
     9  
    10  	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/printers"
    11  	printerstorage "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/printers/storage"
    12  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    13  	metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
    14  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    15  	"k8s.io/apimachinery/pkg/labels"
    16  	"k8s.io/apimachinery/pkg/runtime"
    17  	"k8s.io/apimachinery/pkg/runtime/schema"
    18  	genericreq "k8s.io/apiserver/pkg/endpoints/request"
    19  	"k8s.io/apiserver/pkg/registry/rest"
    20  
    21  	"github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators"
    22  	"github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/provider"
    23  )
    24  
    25  type PackageManifestStorage struct {
    26  	groupResource schema.GroupResource
    27  	prov          provider.PackageManifestProvider
    28  	scheme        *runtime.Scheme
    29  	rest.TableConvertor
    30  }
    31  
    32  var _ rest.Storage = &PackageManifestStorage{}
    33  var _ rest.KindProvider = &PackageManifestStorage{}
    34  var _ rest.Lister = &PackageManifestStorage{}
    35  var _ rest.Getter = &PackageManifestStorage{}
    36  var _ rest.Scoper = &PackageManifestStorage{}
    37  var _ rest.TableConvertor = &PackageManifestStorage{}
    38  var _ rest.SingularNameProvider = &PackageManifestStorage{}
    39  
    40  // NewStorage returns a struct that implements methods needed for Kubernetes to satisfy API requests for the `PackageManifest` resource
    41  func NewStorage(groupResource schema.GroupResource, prov provider.PackageManifestProvider, scheme *runtime.Scheme) *PackageManifestStorage {
    42  	return &PackageManifestStorage{
    43  		groupResource:  groupResource,
    44  		prov:           prov,
    45  		scheme:         scheme,
    46  		TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(addTableHandlers)},
    47  	}
    48  }
    49  
    50  // New satisfies the Storage interface
    51  func (m *PackageManifestStorage) New() runtime.Object {
    52  	return &operators.PackageManifest{}
    53  }
    54  
    55  // Destroy satisfies the Storage interface
    56  // Performs a no-op
    57  func (m *PackageManifestStorage) Destroy() {}
    58  
    59  // Kind satisfies the KindProvider interface
    60  func (m *PackageManifestStorage) Kind() string {
    61  	return "PackageManifest"
    62  }
    63  
    64  func (m *PackageManifestStorage) GetSingularName() string {
    65  	return strings.ToLower(m.Kind())
    66  }
    67  
    68  // NewList satisfies part of the Lister interface
    69  func (m *PackageManifestStorage) NewList() runtime.Object {
    70  	return &operators.PackageManifestList{}
    71  }
    72  
    73  // List satisfies part of the Lister interface
    74  func (m *PackageManifestStorage) List(ctx context.Context, options *metainternalversion.ListOptions) (runtime.Object, error) {
    75  	namespace := genericreq.NamespaceValue(ctx)
    76  
    77  	labelSelector := labels.Everything()
    78  	if options != nil && options.LabelSelector != nil {
    79  		labelSelector = options.LabelSelector
    80  	}
    81  
    82  	name, err := nameFor(options.FieldSelector)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  
    87  	res, err := m.prov.List(namespace, labelSelector)
    88  	if err != nil {
    89  		return nil, apierrors.NewInternalError(err)
    90  	}
    91  
    92  	filtered := []operators.PackageManifest{}
    93  	for _, manifest := range res.Items {
    94  		if matches(manifest, name) {
    95  			filtered = append(filtered, manifest)
    96  		}
    97  	}
    98  
    99  	for i := range filtered {
   100  		for j := range filtered[i].Status.Channels {
   101  			filtered[i].Status.Channels[j].CurrentCSVDesc.Icon = []operators.Icon{}
   102  		}
   103  	}
   104  	res.Items = filtered
   105  
   106  	return res, nil
   107  }
   108  
   109  // Get satisfies the Getter interface
   110  func (m *PackageManifestStorage) Get(ctx context.Context, name string, opts *metav1.GetOptions) (runtime.Object, error) {
   111  	namespace := genericreq.NamespaceValue(ctx)
   112  	manifest, err := m.prov.Get(namespace, name)
   113  	if err != nil || manifest == nil {
   114  		return nil, apierrors.NewNotFound(m.groupResource, name)
   115  	}
   116  	// Strip logo icons
   117  	for i := range manifest.Status.Channels {
   118  		manifest.Status.Channels[i].CurrentCSVDesc.Icon = []operators.Icon{}
   119  	}
   120  
   121  	return manifest, nil
   122  }
   123  
   124  // NamespaceScoped satisfies the Scoper interface
   125  func (m *PackageManifestStorage) NamespaceScoped() bool {
   126  	return true
   127  }
   128  
   129  func nameFor(fs fields.Selector) (string, error) {
   130  	if fs == nil {
   131  		fs = fields.Everything()
   132  	}
   133  	name := ""
   134  	if value, found := fs.RequiresExactMatch("metadata.name"); found {
   135  		name = value
   136  	} else if !fs.Empty() {
   137  		return "", fmt.Errorf("field label not supported: %s", fs.Requirements()[0].Field)
   138  	}
   139  	return name, nil
   140  }
   141  
   142  func matches(pm operators.PackageManifest, name string) bool {
   143  	if name == "" {
   144  		name = pm.GetName()
   145  	}
   146  	return pm.GetName() == name
   147  }