From d7d3c4dbd19118ea00a216006e56101d6539a6a7 Mon Sep 17 00:00:00 2001 From: ttimonen Date: Wed, 10 Jul 2024 10:42:33 +0000 Subject: [PATCH 1/2] Trivial: Simplify parser In particular fixed the issue that quotes were trimmed twice in some places. Signed-off-by: ttimonen --- .../softwarecomposition/v1beta1/spdx_types.go | 102 +++++++----------- 1 file changed, 37 insertions(+), 65 deletions(-) diff --git a/pkg/apis/softwarecomposition/v1beta1/spdx_types.go b/pkg/apis/softwarecomposition/v1beta1/spdx_types.go index bd0f528f0..643d845da 100644 --- a/pkg/apis/softwarecomposition/v1beta1/spdx_types.go +++ b/pkg/apis/softwarecomposition/v1beta1/spdx_types.go @@ -12,26 +12,30 @@ type Annotator struct { AnnotatorType string } +// kvJSONLine parses a key-value pair from JSON. +// i.e. "\"\""" -> k = "foo", v = "bar". +func kvJSONLine(data []byte) (k, v string, err error) { + var ( + s string + ok bool + ) + if err = json.Unmarshal(data, &s); err != nil { + return k, v, err + } + if k, v, ok = strings.Cut(s, ": "); !ok { + err = fmt.Errorf("failed to parse %q", s) + } + return k, v, err +} + // UnmarshalJSON takes an annotator in the typical one-line format and parses it into an Annotator struct. // This function is also used when unmarshalling YAML func (a *Annotator) UnmarshalJSON(data []byte) error { - // annotator will simply be a string - var annotatorStr string - err := json.Unmarshal(data, &annotatorStr) - if err != nil { - return err - } - annotatorStr = strings.Trim(annotatorStr, "\"") - - annotatorFields := strings.SplitN(annotatorStr, ": ", 2) - - if len(annotatorFields) != 2 { - return fmt.Errorf("failed to parse Annotator '%s'", annotatorStr) + // annotator will simply be a string. + var err error + if a.AnnotatorType, a.Annotator, err = kvJSONLine(data); err != nil { + return fmt.Errorf("failed to parse Annotator: %w", err) } - - a.AnnotatorType = annotatorFields[0] - a.Annotator = annotatorFields[1] - return nil } @@ -87,20 +91,10 @@ type Creator struct { // UnmarshalJSON takes an annotator in the typical one-line format and parses it into a Creator struct. // This function is also used when unmarshalling YAML func (c *Creator) UnmarshalJSON(data []byte) error { - var str string - err := json.Unmarshal(data, &str) - if err != nil { - return err + var err error + if c.CreatorType, c.Creator, err = kvJSONLine(data); err != nil { + return fmt.Errorf("failed to parse Creator: %w", err) } - fields := strings.SplitN(str, ": ", 2) - - if len(fields) != 2 { - return fmt.Errorf("failed to parse Creator '%s'", str) - } - - c.CreatorType = fields[0] - c.Creator = fields[1] - return nil } @@ -356,23 +350,14 @@ type Supplier struct { // This function is also used when unmarshalling YAML func (s *Supplier) UnmarshalJSON(data []byte) error { // the value is just a string presented as a slice of bytes - supplierStr := string(data) - supplierStr = strings.Trim(supplierStr, "\"") - - if supplierStr == "NOASSERTION" { - s.Supplier = supplierStr - return nil - } - - supplierFields := strings.SplitN(supplierStr, ": ", 2) - - if len(supplierFields) != 2 { - return fmt.Errorf("failed to parse Supplier '%s'", supplierStr) + switch k, v, err := kvJSONLine(data); { + case k == "NOASSERTION": + s.Supplier = k + case err != nil: + return fmt.Errorf("failed to parse Supplier '%w'", err) + default: + s.SupplierType, s.Supplier = k, v } - - s.SupplierType = supplierFields[0] - s.Supplier = supplierFields[1] - return nil } @@ -399,27 +384,14 @@ type Originator struct { // This function is also used when unmarshalling YAML func (o *Originator) UnmarshalJSON(data []byte) error { // the value is just a string presented as a slice of bytes - var originatorStr string - err := json.Unmarshal(data, &originatorStr) - if err != nil { - return err + switch k, v, err := kvJSONLine(data); { + case k == "NOASSERTION": + o.Originator = k + case err != nil: + return fmt.Errorf("failed to parse Originator '%w'", err) + default: + o.OriginatorType, o.Originator = k, v } - originatorStr = strings.Trim(originatorStr, "\"") - - if originatorStr == "NOASSERTION" { - o.Originator = originatorStr - return nil - } - - originatorFields := strings.SplitN(originatorStr, ": ", 2) - - if len(originatorFields) != 2 { - return fmt.Errorf("failed to parse Originator '%s'", originatorStr) - } - - o.OriginatorType = originatorFields[0] - o.Originator = originatorFields[1] - return nil } From fcf0283156292b8bc3384592e24b793948528f23 Mon Sep 17 00:00:00 2001 From: ttimonen Date: Sat, 13 Jul 2024 12:22:52 +0000 Subject: [PATCH 2/2] refactor(file): Simplify storage creation logic In particular, reduce the boilerplate of immutable storage layers (configscansummary, generated network policy and vulnerabilitysummary). Also simplify some list creation logic here and there. Signed-off-by: ttimonen --- pkg/apiserver/apiserver.go | 82 +++++++------- .../file/configurationscansummarystorage.go | 104 +++++------------- .../configurationscansummarystorage_test.go | 14 +-- pkg/registry/file/generatednetworkpolicy.go | 49 +-------- .../file/generatednetworkpolicy_test.go | 12 +- pkg/registry/file/storage.go | 46 ++++++-- .../file/vulnerabilitysummarystorage.go | 49 +-------- .../file/vulnerabilitysummarystorage_test.go | 14 +-- 8 files changed, 131 insertions(+), 239 deletions(-) diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index 99dec3f5d..32965c3a7 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -17,6 +17,7 @@ limitations under the License. package apiserver import ( + "github.com/kubescape/storage/pkg/registry" "github.com/kubescape/storage/pkg/registry/file" "github.com/kubescape/storage/pkg/registry/softwarecomposition/applicationactivity" "github.com/kubescape/storage/pkg/registry/softwarecomposition/applicationprofile" @@ -33,9 +34,11 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/apimachinery/pkg/version" + "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/rest" genericapiserver "k8s.io/apiserver/pkg/server" "k8s.io/apiserver/pkg/server/options" + "k8s.io/apiserver/pkg/storage" "github.com/kubescape/storage/pkg/apis/softwarecomposition" "github.com/kubescape/storage/pkg/apis/softwarecomposition/install" @@ -145,46 +148,45 @@ func (c completedConfig) New() (*WardleServer, error) { // https://github.com/kubernetes/kubernetes/issues/86666). apiGroupInfo.NegotiatedSerializer = NewNoProtobufSerializer(Codecs) - osFs := afero.NewOsFs() - - storageImpl := file.NewStorageImpl(osFs, file.DefaultStorageRoot) - - applicationProfileStorageImpl := file.NewStorageImplWithCollector(osFs, file.DefaultStorageRoot, &file.ApplicationProfileProcessor{}) - networkNeighborhoodStorageImpl := file.NewStorageImplWithCollector(osFs, file.DefaultStorageRoot, &file.NetworkNeighborhoodProcessor{}) - configScanStorageImpl := file.NewConfigurationScanSummaryStorage(&storageImpl) - vulnerabilitySummaryStorage := file.NewVulnerabilitySummaryStorage(&storageImpl) - generatedNetworkPolicyStorage := file.NewGeneratedNetworkPolicyStorage(&storageImpl) - - v1beta1storage := map[string]rest.Storage{} - - v1beta1storage["sbomspdxv2p3s"] = sbomregistry.RESTInPeace(sbomspdxv2p3storage.NewREST(Scheme, storageImpl, c.GenericConfig.RESTOptionsGetter)) - v1beta1storage["sbomspdxv2p3filtereds"] = sbomregistry.RESTInPeace(sbomspdxv2p3filteredstorage.NewREST(Scheme, storageImpl, c.GenericConfig.RESTOptionsGetter)) - - v1beta1storage["vulnerabilitymanifests"] = sbomregistry.RESTInPeace(vmstorage.NewREST(Scheme, storageImpl, c.GenericConfig.RESTOptionsGetter)) - v1beta1storage["vulnerabilitymanifestsummaries"] = sbomregistry.RESTInPeace(vmsumstorage.NewREST(Scheme, storageImpl, c.GenericConfig.RESTOptionsGetter)) - - v1beta1storage["workloadconfigurationscans"] = sbomregistry.RESTInPeace(wcsstorage.NewREST(Scheme, storageImpl, c.GenericConfig.RESTOptionsGetter)) - v1beta1storage["workloadconfigurationscansummaries"] = sbomregistry.RESTInPeace(wcssumstorage.NewREST(Scheme, storageImpl, c.GenericConfig.RESTOptionsGetter)) - - v1beta1storage["configurationscansummaries"] = sbomregistry.RESTInPeace(configurationscansummary.NewREST(Scheme, configScanStorageImpl, c.GenericConfig.RESTOptionsGetter)) - v1beta1storage["vulnerabilitysummaries"] = sbomregistry.RESTInPeace(vsumstorage.NewREST(Scheme, vulnerabilitySummaryStorage, c.GenericConfig.RESTOptionsGetter)) - - v1beta1storage["applicationprofiles"] = sbomregistry.RESTInPeace(applicationprofile.NewREST(Scheme, applicationProfileStorageImpl, c.GenericConfig.RESTOptionsGetter)) - v1beta1storage["applicationactivities"] = sbomregistry.RESTInPeace(applicationactivity.NewREST(Scheme, storageImpl, c.GenericConfig.RESTOptionsGetter)) - - v1beta1storage["networkneighborses"] = sbomregistry.RESTInPeace(networkneighbors.NewREST(Scheme, storageImpl, c.GenericConfig.RESTOptionsGetter)) - v1beta1storage["networkneighborhoods"] = sbomregistry.RESTInPeace(networkneighborhood.NewREST(Scheme, networkNeighborhoodStorageImpl, c.GenericConfig.RESTOptionsGetter)) - v1beta1storage["openvulnerabilityexchangecontainers"] = sbomregistry.RESTInPeace(openvulnerabilityexchange.NewREST(Scheme, storageImpl, c.GenericConfig.RESTOptionsGetter)) - - v1beta1storage["generatednetworkpolicies"] = sbomregistry.RESTInPeace(generatednetworkpolicy.NewREST(Scheme, generatedNetworkPolicyStorage, c.GenericConfig.RESTOptionsGetter)) - v1beta1storage["knownservers"] = sbomregistry.RESTInPeace(knownserver.NewREST(Scheme, storageImpl, c.GenericConfig.RESTOptionsGetter)) - - v1beta1storage["sbomsyfts"] = sbomregistry.RESTInPeace(sbomsyfts.NewREST(Scheme, storageImpl, c.GenericConfig.RESTOptionsGetter)) - v1beta1storage["sbomsyftfiltereds"] = sbomregistry.RESTInPeace(sbomsyftfiltereds.NewREST(Scheme, storageImpl, c.GenericConfig.RESTOptionsGetter)) - - v1beta1storage["seccompprofiles"] = sbomregistry.RESTInPeace(seccompprofiles.NewREST(Scheme, storageImpl, c.GenericConfig.RESTOptionsGetter)) - - apiGroupInfo.VersionedResourcesStorageMap["v1beta1"] = v1beta1storage + var ( + osFs = afero.NewOsFs() + storageImpl = file.NewStorageImpl(osFs, file.DefaultStorageRoot) + + applicationProfileStorageImpl = file.NewStorageImplWithCollector(osFs, file.DefaultStorageRoot, &file.ApplicationProfileProcessor{}) + networkNeighborhoodStorageImpl = file.NewStorageImplWithCollector(osFs, file.DefaultStorageRoot, &file.NetworkNeighborhoodProcessor{}) + configScanStorageImpl = file.NewConfigurationScanSummaryStorage(storageImpl) + vulnerabilitySummaryStorage = file.NewVulnerabilitySummaryStorage(storageImpl) + generatedNetworkPolicyStorage = file.NewGeneratedNetworkPolicyStorage(storageImpl) + + // REST endpoint registration, defaults to storageImpl. + ep = func(f func(*runtime.Scheme, storage.Interface, generic.RESTOptionsGetter) (*registry.REST, error), s ...storage.Interface) *registry.REST { + var si storage.Interface = storageImpl + if len(s) > 0 { + si = s[0] + } + return sbomregistry.RESTInPeace(f(Scheme, si, c.GenericConfig.RESTOptionsGetter)) + } + ) + apiGroupInfo.VersionedResourcesStorageMap["v1beta1"] = map[string]rest.Storage{ + "applicationactivities": ep(applicationactivity.NewREST), + "applicationprofiles": ep(applicationprofile.NewREST, applicationProfileStorageImpl), + "configurationscansummaries": ep(configurationscansummary.NewREST, configScanStorageImpl), + "generatednetworkpolicies": ep(generatednetworkpolicy.NewREST, generatedNetworkPolicyStorage), + "knownservers": ep(knownserver.NewREST), + "networkneighborhoods": ep(networkneighborhood.NewREST, networkNeighborhoodStorageImpl), + "networkneighborses": ep(networkneighbors.NewREST), + "openvulnerabilityexchangecontainers": ep(openvulnerabilityexchange.NewREST), + "sbomspdxv2p3filtereds": ep(sbomspdxv2p3filteredstorage.NewREST), + "sbomspdxv2p3s": ep(sbomspdxv2p3storage.NewREST), + "sbomsyftfiltereds": ep(sbomsyftfiltereds.NewREST), + "sbomsyfts": ep(sbomsyfts.NewREST), + "seccompprofiles": ep(seccompprofiles.NewREST), + "vulnerabilitymanifests": ep(vmstorage.NewREST), + "vulnerabilitymanifestsummaries": ep(vmsumstorage.NewREST), + "vulnerabilitysummaries": ep(vsumstorage.NewREST, vulnerabilitySummaryStorage), + "workloadconfigurationscans": ep(wcsstorage.NewREST), + "workloadconfigurationscansummaries": ep(wcssumstorage.NewREST), + } if err := s.GenericAPIServer.InstallAPIGroup(&apiGroupInfo); err != nil { return nil, err diff --git a/pkg/registry/file/configurationscansummarystorage.go b/pkg/registry/file/configurationscansummarystorage.go index 61bbc03f9..4d4f9c06f 100644 --- a/pkg/registry/file/configurationscansummarystorage.go +++ b/pkg/registry/file/configurationscansummarystorage.go @@ -12,7 +12,6 @@ import ( "go.opentelemetry.io/otel/attribute" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/watch" "k8s.io/apiserver/pkg/storage" ) @@ -23,37 +22,14 @@ const ( // ConfigurationScanSummaryStorage offers a storage solution for ConfigurationScanSummary objects, implementing custom business logic for these objects and using the underlying default storage implementation. type ConfigurationScanSummaryStorage struct { + immutableStorage realStore StorageQuerier - versioner storage.Versioner } var _ storage.Interface = &ConfigurationScanSummaryStorage{} -func NewConfigurationScanSummaryStorage(realStore *StorageQuerier) storage.Interface { - return &ConfigurationScanSummaryStorage{ - realStore: *realStore, - versioner: storage.APIObjectVersioner{}, - } -} - -// Versioner Returns Versioner associated with this interface. -func (s *ConfigurationScanSummaryStorage) Versioner() storage.Versioner { - return s.versioner -} - -// Create is not supported for ConfigurationScanSummary objects. Objects are generated on the fly and not stored. -func (s *ConfigurationScanSummaryStorage) Create(ctx context.Context, key string, obj, out runtime.Object, _ uint64) error { - return storage.NewInvalidObjError(key, operationNotSupportedMsg) -} - -// Delete is not supported for ConfigurationScanSummary objects. Objects are generated on the fly and not stored. -func (s *ConfigurationScanSummaryStorage) Delete(ctx context.Context, key string, out runtime.Object, _ *storage.Preconditions, _ storage.ValidateObjectFunc, _ runtime.Object) error { - return storage.NewInvalidObjError(key, operationNotSupportedMsg) -} - -// Watch is not supported for ConfigurationScanSummary objects. Objects are generated on the fly and not stored. -func (s *ConfigurationScanSummaryStorage) Watch(ctx context.Context, key string, _ storage.ListOptions) (watch.Interface, error) { - return nil, storage.NewInvalidObjError(key, operationNotSupportedMsg) +func NewConfigurationScanSummaryStorage(realStore StorageQuerier) storage.Interface { + return &ConfigurationScanSummaryStorage{realStore: realStore} } // Get generates and returns a single ConfigurationScanSummary object for a namespace @@ -124,67 +100,37 @@ func (s *ConfigurationScanSummaryStorage) GetList(ctx context.Context, key strin return nil } -// GuaranteedUpdate is not supported for ConfigurationScanSummary objects. Objects are generated on the fly and not stored. -func (s *ConfigurationScanSummaryStorage) GuaranteedUpdate( - ctx context.Context, key string, destination runtime.Object, ignoreNotFound bool, - preconditions *storage.Preconditions, tryUpdate storage.UpdateFunc, cachedExistingObject runtime.Object) error { - return storage.NewInvalidObjError(key, operationNotSupportedMsg) -} - -// Count is not supported for ConfigurationScanSummary objects. Objects are generated on the fly and not stored. -func (s *ConfigurationScanSummaryStorage) Count(key string) (int64, error) { - return 0, storage.NewInvalidObjError(key, operationNotSupportedMsg) -} - -// RequestWatchProgress fulfills the storage.Interface -// -// It’s function is only relevant to etcd. -func (s *ConfigurationScanSummaryStorage) RequestWatchProgress(context.Context) error { - return nil -} - // buildConfigurationScanSummaryForCluster generates a configuration scan summary list for the cluster, where each item is a configuration scan summary for a namespace -func buildConfigurationScanSummaryForCluster(wlConfigurationScanSummaryList softwarecomposition.WorkloadConfigurationScanSummaryList) softwarecomposition.ConfigurationScanSummaryList { +func buildConfigurationScanSummaryForCluster(list softwarecomposition.WorkloadConfigurationScanSummaryList) softwarecomposition.ConfigurationScanSummaryList { // build an map of namespace to workload configuration scan summaries - mapNamespaceToSummaries := make(map[string][]softwarecomposition.WorkloadConfigurationScanSummary) - - for _, wlSummary := range wlConfigurationScanSummaryList.Items { - if _, ok := mapNamespaceToSummaries[wlSummary.Namespace]; !ok { - mapNamespaceToSummaries[wlSummary.Namespace] = make([]softwarecomposition.WorkloadConfigurationScanSummary, 0) - } - mapNamespaceToSummaries[wlSummary.Namespace] = append(mapNamespaceToSummaries[wlSummary.Namespace], wlSummary) + perNS := map[string][]softwarecomposition.WorkloadConfigurationScanSummary{} + for _, s := range list.Items { + perNS[s.Namespace] = append(perNS[s.Namespace], s) } - configurationScanSummaryList := softwarecomposition.ConfigurationScanSummaryList{ + ret := softwarecomposition.ConfigurationScanSummaryList{ TypeMeta: v1.TypeMeta{ Kind: configurationScanSummaryKind, APIVersion: StorageV1Beta1ApiVersion, }, } + type wList = softwarecomposition.WorkloadConfigurationScanSummaryList // 1 - build a workload configuration scan summary list for each namespace // 2 - generate a single configuration scan summary for the namespace // 3 - add the configuration scan summary to the cluster summary list object - for namespace, wlSummaries := range mapNamespaceToSummaries { + for ns, sums := range perNS { // for each namespace, create a single workload configuration scan summary object - nsListObj := softwarecomposition.WorkloadConfigurationScanSummaryList{ - TypeMeta: v1.TypeMeta{ - Kind: configurationScanSummaryKind, - APIVersion: StorageV1Beta1ApiVersion, - }, - Items: wlSummaries, - } - - configurationScanSummaryList.Items = append(configurationScanSummaryList.Items, buildConfigurationScanSummary(nsListObj, namespace)) + ret.Items = append(ret.Items, buildConfigurationScanSummary(wList{Items: sums}, ns)) } - return configurationScanSummaryList + return ret } // buildConfigurationScanSummary generates a single configuration scan summary for the given namespace -func buildConfigurationScanSummary(wlConfigurationScanSummaryList softwarecomposition.WorkloadConfigurationScanSummaryList, namespace string) softwarecomposition.ConfigurationScanSummary { - configurationScanSummaryObj := softwarecomposition.ConfigurationScanSummary{ +func buildConfigurationScanSummary(list softwarecomposition.WorkloadConfigurationScanSummaryList, namespace string) softwarecomposition.ConfigurationScanSummary { + summary := softwarecomposition.ConfigurationScanSummary{ TypeMeta: v1.TypeMeta{ Kind: configurationScanSummaryKind, APIVersion: StorageV1Beta1ApiVersion, @@ -194,22 +140,22 @@ func buildConfigurationScanSummary(wlConfigurationScanSummaryList softwarecompos }, } - for i := range wlConfigurationScanSummaryList.Items { - configurationScanSummaryObj.Spec.Severities.Critical += wlConfigurationScanSummaryList.Items[i].Spec.Severities.Critical - configurationScanSummaryObj.Spec.Severities.High += wlConfigurationScanSummaryList.Items[i].Spec.Severities.High - configurationScanSummaryObj.Spec.Severities.Medium += wlConfigurationScanSummaryList.Items[i].Spec.Severities.Medium - configurationScanSummaryObj.Spec.Severities.Low += wlConfigurationScanSummaryList.Items[i].Spec.Severities.Low - configurationScanSummaryObj.Spec.Severities.Unknown += wlConfigurationScanSummaryList.Items[i].Spec.Severities.Unknown + for i := range list.Items { + summary.Spec.Severities.Critical += list.Items[i].Spec.Severities.Critical + summary.Spec.Severities.High += list.Items[i].Spec.Severities.High + summary.Spec.Severities.Medium += list.Items[i].Spec.Severities.Medium + summary.Spec.Severities.Low += list.Items[i].Spec.Severities.Low + summary.Spec.Severities.Unknown += list.Items[i].Spec.Severities.Unknown - wlIdentifier := softwarecomposition.WorkloadConfigurationScanSummaryIdentifier{ - Namespace: wlConfigurationScanSummaryList.Items[i].Namespace, + id := softwarecomposition.WorkloadConfigurationScanSummaryIdentifier{ + Namespace: list.Items[i].Namespace, Kind: "WorkloadConfigurationScanSummary", - Name: wlConfigurationScanSummaryList.Items[i].Name, + Name: list.Items[i].Name, } - configurationScanSummaryObj.Spec.WorkloadConfigurationScanSummaryIdentifiers = append(configurationScanSummaryObj.Spec.WorkloadConfigurationScanSummaryIdentifiers, wlIdentifier) + summary.Spec.WorkloadConfigurationScanSummaryIdentifiers = append(summary.Spec.WorkloadConfigurationScanSummaryIdentifiers, id) } - return configurationScanSummaryObj + return summary } diff --git a/pkg/registry/file/configurationscansummarystorage_test.go b/pkg/registry/file/configurationscansummarystorage_test.go index 14f335576..1ea18cc1a 100644 --- a/pkg/registry/file/configurationscansummarystorage_test.go +++ b/pkg/registry/file/configurationscansummarystorage_test.go @@ -15,7 +15,7 @@ import ( func TestConfigurationScanSummaryStorage_Count(t *testing.T) { storageImpl := NewStorageImpl(afero.NewMemMapFs(), "") - configScanSummaryStorage := NewConfigurationScanSummaryStorage(&storageImpl) + configScanSummaryStorage := NewConfigurationScanSummaryStorage(storageImpl) count, err := configScanSummaryStorage.Count("random") @@ -28,7 +28,7 @@ func TestConfigurationScanSummaryStorage_Count(t *testing.T) { func TestConfigurationScanSummaryStorage_Create(t *testing.T) { storageImpl := NewStorageImpl(afero.NewMemMapFs(), "") - configScanSummaryStorage := NewConfigurationScanSummaryStorage(&storageImpl) + configScanSummaryStorage := NewConfigurationScanSummaryStorage(storageImpl) err := configScanSummaryStorage.Create(context.TODO(), "", nil, nil, 0) @@ -39,7 +39,7 @@ func TestConfigurationScanSummaryStorage_Create(t *testing.T) { func TestConfigurationScanSummaryStorage_Delete(t *testing.T) { storageImpl := NewStorageImpl(afero.NewMemMapFs(), "") - configScanSummaryStorage := NewConfigurationScanSummaryStorage(&storageImpl) + configScanSummaryStorage := NewConfigurationScanSummaryStorage(storageImpl) err := configScanSummaryStorage.Delete(context.TODO(), "", nil, nil, nil, nil) @@ -50,7 +50,7 @@ func TestConfigurationScanSummaryStorage_Delete(t *testing.T) { func TestConfigurationScanSummaryStorage_Watch(t *testing.T) { storageImpl := NewStorageImpl(afero.NewMemMapFs(), "") - configScanSummaryStorage := NewConfigurationScanSummaryStorage(&storageImpl) + configScanSummaryStorage := NewConfigurationScanSummaryStorage(storageImpl) _, err := configScanSummaryStorage.Watch(context.TODO(), "", storage.ListOptions{}) @@ -61,7 +61,7 @@ func TestConfigurationScanSummaryStorage_Watch(t *testing.T) { func TestConfigurationScanSummaryStorage_GuaranteedUpdate(t *testing.T) { storageImpl := NewStorageImpl(afero.NewMemMapFs(), "") - configScanSummaryStorage := NewConfigurationScanSummaryStorage(&storageImpl) + configScanSummaryStorage := NewConfigurationScanSummaryStorage(storageImpl) err := configScanSummaryStorage.GuaranteedUpdate(context.TODO(), "", nil, false, nil, nil, nil) @@ -111,7 +111,7 @@ func TestConfigurationScanSummaryStorage_Get(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - configScanSummaryStorage := NewConfigurationScanSummaryStorage(&realStorage) + configScanSummaryStorage := NewConfigurationScanSummaryStorage(realStorage) if tt.create { wlObj := &softwarecomposition.WorkloadConfigurationScanSummary{} @@ -177,7 +177,7 @@ func TestConfigurationScanSummaryStorage_GetList(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - configScanSummaryStorage := NewConfigurationScanSummaryStorage(&realStorage) + configScanSummaryStorage := NewConfigurationScanSummaryStorage(realStorage) if tt.create { wlObj := &softwarecomposition.WorkloadConfigurationScanSummary{} diff --git a/pkg/registry/file/generatednetworkpolicy.go b/pkg/registry/file/generatednetworkpolicy.go index 6be8bef6d..58aa311c6 100644 --- a/pkg/registry/file/generatednetworkpolicy.go +++ b/pkg/registry/file/generatednetworkpolicy.go @@ -13,7 +13,6 @@ import ( "go.opentelemetry.io/otel/attribute" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/watch" "k8s.io/apiserver/pkg/storage" ) @@ -24,37 +23,14 @@ const ( // GeneratedNetworkPolicyStorage offers a storage solution for GeneratedNetworkPolicy objects, implementing custom business logic for these objects and using the underlying default storage implementation. type GeneratedNetworkPolicyStorage struct { + immutableStorage realStore StorageQuerier - versioner storage.Versioner } var _ storage.Interface = &GeneratedNetworkPolicyStorage{} -func NewGeneratedNetworkPolicyStorage(realStore *StorageQuerier) storage.Interface { - return &GeneratedNetworkPolicyStorage{ - realStore: *realStore, - versioner: storage.APIObjectVersioner{}, - } -} - -// Versioner Returns Versioner associated with this interface. -func (s *GeneratedNetworkPolicyStorage) Versioner() storage.Versioner { - return s.versioner -} - -// Create is not supported for GeneratedNetworkPolicy objects. Objects are generated on the fly and not stored. -func (s *GeneratedNetworkPolicyStorage) Create(ctx context.Context, key string, obj, out runtime.Object, _ uint64) error { - return storage.NewInvalidObjError(key, operationNotSupportedMsg) -} - -// Delete is not supported for GeneratedNetworkPolicy objects. Objects are generated on the fly and not stored. -func (s *GeneratedNetworkPolicyStorage) Delete(ctx context.Context, key string, out runtime.Object, _ *storage.Preconditions, _ storage.ValidateObjectFunc, _ runtime.Object) error { - return storage.NewInvalidObjError(key, operationNotSupportedMsg) -} - -// Watch is not supported for GeneratedNetworkPolicy objects. Objects are generated on the fly and not stored. -func (s *GeneratedNetworkPolicyStorage) Watch(ctx context.Context, key string, _ storage.ListOptions) (watch.Interface, error) { - return nil, storage.NewInvalidObjError(key, operationNotSupportedMsg) +func NewGeneratedNetworkPolicyStorage(realStore StorageQuerier) storage.Interface { + return &GeneratedNetworkPolicyStorage{realStore: realStore} } // Get generates and returns a single GeneratedNetworkPolicy object @@ -147,22 +123,3 @@ func (s *GeneratedNetworkPolicyStorage) GetList(ctx context.Context, key string, return nil } - -// GuaranteedUpdate is not supported for GeneratedNetworkPolicy objects. Objects are generated on the fly and not stored. -func (s *GeneratedNetworkPolicyStorage) GuaranteedUpdate( - ctx context.Context, key string, destination runtime.Object, ignoreNotFound bool, - preconditions *storage.Preconditions, tryUpdate storage.UpdateFunc, cachedExistingObject runtime.Object) error { - return storage.NewInvalidObjError(key, operationNotSupportedMsg) -} - -// Count is not supported for GeneratedNetworkPolicy objects. Objects are generated on the fly and not stored. -func (s *GeneratedNetworkPolicyStorage) Count(key string) (int64, error) { - return 0, storage.NewInvalidObjError(key, operationNotSupportedMsg) -} - -// RequestWatchProgress fulfills the storage.Interface -// -// It’s function is only relevant to etcd. -func (s *GeneratedNetworkPolicyStorage) RequestWatchProgress(context.Context) error { - return nil -} diff --git a/pkg/registry/file/generatednetworkpolicy_test.go b/pkg/registry/file/generatednetworkpolicy_test.go index c956b6dbd..2760cea51 100644 --- a/pkg/registry/file/generatednetworkpolicy_test.go +++ b/pkg/registry/file/generatednetworkpolicy_test.go @@ -79,7 +79,7 @@ func TestGeneratedNetworkPolicyStorage_Get(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { realStorage := NewStorageImpl(afero.NewMemMapFs(), "/") - generatedNetworkPolicyStorage := NewGeneratedNetworkPolicyStorage(&realStorage) + generatedNetworkPolicyStorage := NewGeneratedNetworkPolicyStorage(realStorage) if tt.create { wlObj := &softwarecomposition.NetworkNeighbors{ @@ -115,7 +115,7 @@ func TestGeneratedNetworkPolicyStorage_Get(t *testing.T) { func TestGeneratedNetworkPolicyStorage_Count(t *testing.T) { storageImpl := NewStorageImpl(afero.NewMemMapFs(), "") - generatedNetworkPolicyStorage := NewGeneratedNetworkPolicyStorage(&storageImpl) + generatedNetworkPolicyStorage := NewGeneratedNetworkPolicyStorage(storageImpl) count, err := generatedNetworkPolicyStorage.Count("random") @@ -128,7 +128,7 @@ func TestGeneratedNetworkPolicyStorage_Count(t *testing.T) { func TestGeneratedNetworkPolicyStorage_Create(t *testing.T) { storageImpl := NewStorageImpl(afero.NewMemMapFs(), "") - generatedNetworkPolicyStorage := NewGeneratedNetworkPolicyStorage(&storageImpl) + generatedNetworkPolicyStorage := NewGeneratedNetworkPolicyStorage(storageImpl) err := generatedNetworkPolicyStorage.Create(context.TODO(), "", nil, nil, 0) @@ -139,7 +139,7 @@ func TestGeneratedNetworkPolicyStorage_Create(t *testing.T) { func TestGeneratedNetworkPolicyStorage_Delete(t *testing.T) { storageImpl := NewStorageImpl(afero.NewMemMapFs(), "") - generatedNetworkPolicyStorage := NewGeneratedNetworkPolicyStorage(&storageImpl) + generatedNetworkPolicyStorage := NewGeneratedNetworkPolicyStorage(storageImpl) err := generatedNetworkPolicyStorage.Delete(context.TODO(), "", nil, nil, nil, nil) @@ -150,7 +150,7 @@ func TestGeneratedNetworkPolicyStorage_Delete(t *testing.T) { func TestGeneratedNetworkPolicyStorage_Watch(t *testing.T) { storageImpl := NewStorageImpl(afero.NewMemMapFs(), "") - generatedNetworkPolicyStorage := NewGeneratedNetworkPolicyStorage(&storageImpl) + generatedNetworkPolicyStorage := NewGeneratedNetworkPolicyStorage(storageImpl) _, err := generatedNetworkPolicyStorage.Watch(context.TODO(), "", storage.ListOptions{}) @@ -161,7 +161,7 @@ func TestGeneratedNetworkPolicyStorage_Watch(t *testing.T) { func TestGeneratedNetworkPolicyStorage_GuaranteedUpdate(t *testing.T) { storageImpl := NewStorageImpl(afero.NewMemMapFs(), "") - generatedNetworkPolicyStorage := NewGeneratedNetworkPolicyStorage(&storageImpl) + generatedNetworkPolicyStorage := NewGeneratedNetworkPolicyStorage(storageImpl) err := generatedNetworkPolicyStorage.GuaranteedUpdate(context.TODO(), "", nil, false, nil, nil, nil) diff --git a/pkg/registry/file/storage.go b/pkg/registry/file/storage.go index 6446495ef..a8796525e 100644 --- a/pkg/registry/file/storage.go +++ b/pkg/registry/file/storage.go @@ -65,14 +65,7 @@ var _ storage.Interface = &StorageImpl{} var _ StorageQuerier = &StorageImpl{} func NewStorageImpl(appFs afero.Fs, root string) StorageQuerier { - return &StorageImpl{ - appFs: appFs, - locks: utils.NewMapMutex[string](), - processor: DefaultProcessor{}, - root: root, - versioner: storage.APIObjectVersioner{}, - watchDispatcher: newWatchDispatcher(), - } + return NewStorageImplWithCollector(appFs, root, DefaultProcessor{}) } func NewStorageImplWithCollector(appFs afero.Fs, root string, processor Processor) StorageQuerier { @@ -741,3 +734,40 @@ func replaceKeyForKind(key string, kind string) string { return strings.Join(keySplit, "/") } + +type immutableStorage struct{} + +// Create is not supported for immutable objects. Objects are generated on the fly and not stored. +func (immutableStorage) Create(ctx context.Context, key string, obj, out runtime.Object, _ uint64) error { + return storage.NewInvalidObjError(key, operationNotSupportedMsg) +} + +// Delete is not supported for immutable objects. Objects are generated on the fly and not stored. +func (immutableStorage) Delete(ctx context.Context, key string, out runtime.Object, _ *storage.Preconditions, _ storage.ValidateObjectFunc, _ runtime.Object) error { + return storage.NewInvalidObjError(key, operationNotSupportedMsg) +} + +// Watch is not supported for immutable objects. Objects are generated on the fly and not stored. +func (immutableStorage) Watch(ctx context.Context, key string, _ storage.ListOptions) (watch.Interface, error) { + return nil, storage.NewInvalidObjError(key, operationNotSupportedMsg) +} + +// GuaranteedUpdate is not supported for immutable objects. Objects are generated on the fly and not stored. +func (immutableStorage) GuaranteedUpdate(_ context.Context, key string, _ runtime.Object, _ bool, _ *storage.Preconditions, _ storage.UpdateFunc, _ runtime.Object) error { + return storage.NewInvalidObjError(key, operationNotSupportedMsg) +} + +// Count is not supported for immutable objects. Objects are generated on the fly and not stored. +func (immutableStorage) Count(key string) (int64, error) { + return 0, storage.NewInvalidObjError(key, operationNotSupportedMsg) +} + +// RequestWatchProgress fulfills the storage.Interface +// +// It’s function is only relevant to etcd. +func (immutableStorage) RequestWatchProgress(context.Context) error { return nil } + +// Versioner Returns fixed versioner associated with this interface. +func (immutableStorage) Versioner() storage.Versioner { + return storage.APIObjectVersioner{} +} diff --git a/pkg/registry/file/vulnerabilitysummarystorage.go b/pkg/registry/file/vulnerabilitysummarystorage.go index 7a84c87d6..366686088 100644 --- a/pkg/registry/file/vulnerabilitysummarystorage.go +++ b/pkg/registry/file/vulnerabilitysummarystorage.go @@ -12,7 +12,6 @@ import ( "go.opentelemetry.io/otel/attribute" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/watch" "k8s.io/apiserver/pkg/storage" ) @@ -25,35 +24,12 @@ const ( // // It provides vulnerability summaries for scopes like namespace and cluster. To get these summaries, the storage fetches existing stored VulnerabilitySummary objects and aggregates them on the fly. type VulnerabilitySummaryStorage struct { + immutableStorage realStore StorageQuerier - versioner storage.Versioner } -func NewVulnerabilitySummaryStorage(realStore *StorageQuerier) storage.Interface { - return &VulnerabilitySummaryStorage{ - realStore: *realStore, - versioner: storage.APIObjectVersioner{}, - } -} - -// Versioner Returns Versioner associated with this interface. -func (s *VulnerabilitySummaryStorage) Versioner() storage.Versioner { - return s.versioner -} - -// Create is not supported for VulnerabilitySummary objects. Objects are generated on the fly and not stored. -func (s *VulnerabilitySummaryStorage) Create(ctx context.Context, key string, obj, out runtime.Object, _ uint64) error { - return storage.NewInvalidObjError(key, operationNotSupportedMsg) -} - -// Delete is not supported for VulnerabilitySummary objects. Objects are generated on the fly and not stored. -func (s *VulnerabilitySummaryStorage) Delete(ctx context.Context, key string, out runtime.Object, _ *storage.Preconditions, _ storage.ValidateObjectFunc, _ runtime.Object) error { - return storage.NewInvalidObjError(key, operationNotSupportedMsg) -} - -// Watch is not supported for VulnerabilitySummary objects. Objects are generated on the fly and not stored. -func (s *VulnerabilitySummaryStorage) Watch(ctx context.Context, key string, _ storage.ListOptions) (watch.Interface, error) { - return nil, storage.NewInvalidObjError(key, operationNotSupportedMsg) +func NewVulnerabilitySummaryStorage(realStore StorageQuerier) storage.Interface { + return &VulnerabilitySummaryStorage{realStore: realStore} } func buildVulnerabilityScanSummary(vulnerabilityManifestSummaryList softwarecomposition.VulnerabilityManifestSummaryList, namespace string) softwarecomposition.VulnerabilitySummary { @@ -179,22 +155,3 @@ func (s *VulnerabilitySummaryStorage) GetList(ctx context.Context, key string, _ return nil } - -// GuaranteedUpdate is not supported for VulnerabilitySummary objects. Objects are generated on the fly and not stored. -func (s *VulnerabilitySummaryStorage) GuaranteedUpdate( - ctx context.Context, key string, destination runtime.Object, ignoreNotFound bool, - preconditions *storage.Preconditions, tryUpdate storage.UpdateFunc, cachedExistingObject runtime.Object) error { - return storage.NewInvalidObjError(key, operationNotSupportedMsg) -} - -// Count is not supported for VulnerabilitySummary objects. Objects are generated on the fly and not stored. -func (s *VulnerabilitySummaryStorage) Count(key string) (int64, error) { - return 0, storage.NewInvalidObjError(key, operationNotSupportedMsg) -} - -// RequestWatchProgress fulfills the storage.Interface -// -// It’s function is only relevant to etcd. -func (s *VulnerabilitySummaryStorage) RequestWatchProgress(context.Context) error { - return nil -} diff --git a/pkg/registry/file/vulnerabilitysummarystorage_test.go b/pkg/registry/file/vulnerabilitysummarystorage_test.go index 4a1e98c5f..41f568234 100644 --- a/pkg/registry/file/vulnerabilitysummarystorage_test.go +++ b/pkg/registry/file/vulnerabilitysummarystorage_test.go @@ -41,7 +41,7 @@ func TestVulnSummaryStorageImpl_Create(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - s := NewVulnerabilitySummaryStorage(&realStorage) + s := NewVulnerabilitySummaryStorage(realStorage) err := s.Create(context.TODO(), tt.args.key, tt.args.obj, tt.args.out, tt.args.in4) if tt.wantErr { assert.Error(t, err) @@ -77,7 +77,7 @@ func TestVulnSummaryStorageImpl_Delete(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - s := NewVulnerabilitySummaryStorage(&realStorage) + s := NewVulnerabilitySummaryStorage(realStorage) err := s.Delete(context.TODO(), tt.args.key, tt.args.obj, tt.args.precondition, tt.args.validateDeletionFunc, tt.args.cachedObj) if tt.wantErr { assert.Error(t, err) @@ -109,7 +109,7 @@ func TestVulnSummaryStorageImpl_Watch(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - s := NewVulnerabilitySummaryStorage(&realStorage) + s := NewVulnerabilitySummaryStorage(realStorage) _, err := s.Watch(context.TODO(), tt.args.key, storage.ListOptions{}) if tt.wantErr { assert.Error(t, err) @@ -270,7 +270,7 @@ func TestVulnSummaryStorageImpl_GetList(t *testing.T) { assert.NoError(t, err) } } - s := NewVulnerabilitySummaryStorage(&realStorage) + s := NewVulnerabilitySummaryStorage(realStorage) o := &softwarecomposition.VulnerabilitySummaryList{} err := s.GetList(context.TODO(), tt.args.keyExpectedObj, storage.ListOptions{}, o) if tt.wantErr { @@ -315,7 +315,7 @@ func TestVulnSummaryStorageImpl_GuaranteedUpdate(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - s := NewVulnerabilitySummaryStorage(&realStorage) + s := NewVulnerabilitySummaryStorage(realStorage) err := s.GuaranteedUpdate(context.TODO(), tt.args.key, tt.args.obj, true, tt.args.preconditions, tt.args.tryUpdate, tt.args.cachedExistingObject) if tt.wantErr { assert.Error(t, err) @@ -347,7 +347,7 @@ func TestVulnSummaryStorageImpl_Count(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - s := NewVulnerabilitySummaryStorage(&realStorage) + s := NewVulnerabilitySummaryStorage(realStorage) _, err := s.Count(tt.args.key) if tt.wantErr { assert.Error(t, err) @@ -435,7 +435,7 @@ func TestVulnSummaryStorageImpl_Get(t *testing.T) { assert.NoError(t, err) } } - s := NewVulnerabilitySummaryStorage(&realStorage) + s := NewVulnerabilitySummaryStorage(realStorage) o := &softwarecomposition.VulnerabilitySummary{} err := s.Get(context.TODO(), tt.args.keyExpectedObj, storage.GetOptions{}, o) if tt.wantErr {