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 }