Skip to content

Commit 071775d

Browse files
Read ComponentDescriptor from OCI registry
1 parent ae10e76 commit 071775d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+2420
-478
lines changed

cmd/main.go

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"net/http"
2525
"net/http/pprof"
2626
"os"
27+
"strings"
2728
"time"
2829

2930
certmanagerv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
@@ -72,8 +73,10 @@ import (
7273
"github.com/kyma-project/lifecycle-manager/internal/remote"
7374
"github.com/kyma-project/lifecycle-manager/internal/repository/istiogateway"
7475
kymarepository "github.com/kyma-project/lifecycle-manager/internal/repository/kyma"
76+
"github.com/kyma-project/lifecycle-manager/internal/repository/oci"
7577
secretrepository "github.com/kyma-project/lifecycle-manager/internal/repository/secret"
7678
"github.com/kyma-project/lifecycle-manager/internal/service/accessmanager"
79+
"github.com/kyma-project/lifecycle-manager/internal/service/componentdescriptor"
7780
"github.com/kyma-project/lifecycle-manager/internal/service/kyma/status/modules"
7881
"github.com/kyma-project/lifecycle-manager/internal/service/kyma/status/modules/generator"
7982
"github.com/kyma-project/lifecycle-manager/internal/service/kyma/status/modules/generator/fromerror"
@@ -218,21 +221,44 @@ func setupManager(flagVar *flags.FlagVar, cacheOptions cache.Options, scheme *ma
218221
}
219222

220223
sharedMetrics := metrics.NewSharedMetrics()
221-
descriptorProvider := provider.NewCachedDescriptorProvider()
224+
225+
ociRegistryHost := getOciRegistryHost(mgr.GetConfig(), flagVar, logger)
226+
var insecure bool
227+
228+
if noSchemeRef, found := strings.CutPrefix(ociRegistryHost, "http://"); found {
229+
insecure = true
230+
ociRegistryHost = noSchemeRef
231+
} else if noSchemeRef, found := strings.CutPrefix(ociRegistryHost, "https://"); found {
232+
ociRegistryHost = noSchemeRef
233+
}
234+
235+
ocmDescriptorRepository, err := oci.NewRepository(
236+
keychainLookupFromFlag(mgr.GetClient(), flagVar),
237+
ociRegistryHost,
238+
insecure,
239+
)
240+
if err != nil {
241+
logger.Error(err, "failed to create OCM descriptor repository")
242+
os.Exit(bootstrapFailedExitCode)
243+
}
244+
245+
ocmDescriptorService, err := componentdescriptor.NewService(ocmDescriptorRepository)
246+
if err != nil {
247+
logger.Error(err, "failed to create OCM descriptor service")
248+
os.Exit(bootstrapFailedExitCode)
249+
}
250+
descriptorProvider := provider.NewCachedDescriptorProvider(ocmDescriptorService)
251+
222252
kymaMetrics := metrics.NewKymaMetrics(sharedMetrics)
223253
mandatoryModulesMetrics := metrics.NewMandatoryModulesMetrics()
224254
maintenanceWindow := initMaintenanceWindow(flagVar.MinMaintenanceWindowSize, logger)
225255
metrics.NewFipsMetrics().Update()
226256

227-
//nolint:godox // this will be used in the future
228-
// TODO: use the oci registry host //nolint:godox // this will be used in the future
229-
_ = getOciRegistryHost(mgr.GetConfig(), flagVar, logger)
230-
231257
setupKymaReconciler(mgr, descriptorProvider, skrContextProvider, eventRecorder, flagVar, options, skrWebhookManager,
232-
kymaMetrics, logger, maintenanceWindow)
258+
kymaMetrics, logger, maintenanceWindow, ociRegistryHost)
233259
setupManifestReconciler(mgr, flagVar, options, sharedMetrics, mandatoryModulesMetrics, accessManagerService, logger,
234260
eventRecorder)
235-
setupMandatoryModuleReconciler(mgr, descriptorProvider, flagVar, options, mandatoryModulesMetrics, logger)
261+
setupMandatoryModuleReconciler(mgr, descriptorProvider, flagVar, options, mandatoryModulesMetrics, logger, ociRegistryHost)
236262
setupMandatoryModuleDeletionReconciler(mgr, descriptorProvider, eventRecorder, flagVar, options, logger)
237263
if flagVar.EnablePurgeFinalizer {
238264
setupPurgeReconciler(mgr, skrContextProvider, eventRecorder, flagVar, options, logger)
@@ -376,7 +402,7 @@ func scheduleMetricsCleanup(kymaMetrics *metrics.KymaMetrics, cleanupIntervalInM
376402
func setupKymaReconciler(mgr ctrl.Manager, descriptorProvider *provider.CachedDescriptorProvider,
377403
skrContextFactory remote.SkrContextProvider, event event.Event, flagVar *flags.FlagVar, options ctrlruntime.Options,
378404
skrWebhookManager *watcher.SkrWebhookManifestManager, kymaMetrics *metrics.KymaMetrics,
379-
setupLog logr.Logger, maintenanceWindow maintenancewindows.MaintenanceWindow,
405+
setupLog logr.Logger, maintenanceWindow maintenancewindows.MaintenanceWindow, ociRegistryHost string,
380406
) {
381407
options.RateLimiter = internal.RateLimiter(flagVar.FailureBaseDelay,
382408
flagVar.FailureMaxDelay, flagVar.RateLimiterFrequency, flagVar.RateLimiterBurst)
@@ -417,6 +443,7 @@ func setupKymaReconciler(mgr ctrl.Manager, descriptorProvider *provider.CachedDe
417443
flagVar.RemoteSyncNamespace),
418444
TemplateLookup: templatelookup.NewTemplateLookup(kcpClient, descriptorProvider,
419445
moduleTemplateInfoLookupStrategies),
446+
OCIRegistryHost: ociRegistryHost,
420447
}).SetupWithManager(
421448
mgr, options, kyma.SetupOptions{
422449
ListenerAddr: flagVar.KymaListenerAddr,
@@ -472,7 +499,7 @@ func setupManifestReconciler(mgr ctrl.Manager,
472499

473500
manifestClient := manifestclient.NewManifestClient(event, mgr.GetClient())
474501
orphanDetectionClient := kymarepository.NewClient(mgr.GetClient())
475-
specResolver := spec.NewResolver(keychainLookupFromFlag(mgr, flagVar), img.NewPathExtractor())
502+
specResolver := spec.NewResolver(keychainLookupFromFlag(mgr.GetClient(), flagVar), img.NewPathExtractor())
476503
clientCache := skrclientcache.NewService()
477504
skrClient := skrclient.NewService(mgr.GetConfig().QPS, mgr.GetConfig().Burst, accessManagerService)
478505
if err := manifest.SetupWithManager(mgr, options, queue.RequeueIntervals{
@@ -493,9 +520,9 @@ func setupManifestReconciler(mgr ctrl.Manager,
493520
}
494521

495522
//nolint:ireturn // constructor functions can return interfaces
496-
func keychainLookupFromFlag(mgr ctrl.Manager, flagVar *flags.FlagVar) spec.KeyChainLookup {
523+
func keychainLookupFromFlag(clnt client.Client, flagVar *flags.FlagVar) spec.KeyChainLookup {
497524
if flagVar.OciRegistryCredSecretName != "" {
498-
return keychainprovider.NewFromSecretKeyChainProvider(mgr.GetClient(),
525+
return keychainprovider.NewFromSecretKeyChainProvider(clnt,
499526
types.NamespacedName{
500527
Namespace: shared.DefaultControlPlaneNamespace,
501528
Name: flagVar.OciRegistryCredSecretName,
@@ -536,6 +563,7 @@ func setupMandatoryModuleReconciler(mgr ctrl.Manager,
536563
options ctrlruntime.Options,
537564
metrics *metrics.MandatoryModulesMetrics,
538565
setupLog logr.Logger,
566+
ociRegistryHost string,
539567
) {
540568
options.RateLimiter = internal.RateLimiter(flagVar.FailureBaseDelay,
541569
flagVar.FailureMaxDelay, flagVar.RateLimiterFrequency, flagVar.RateLimiterBurst)
@@ -553,6 +581,7 @@ func setupMandatoryModuleReconciler(mgr ctrl.Manager,
553581
RemoteSyncNamespace: flagVar.RemoteSyncNamespace,
554582
DescriptorProvider: descriptorProvider,
555583
Metrics: metrics,
584+
OCIRegistryHost: ociRegistryHost,
556585
}).SetupWithManager(mgr, options); err != nil {
557586
setupLog.Error(err, "unable to create controller", "controller", "MandatoryModule")
558587
os.Exit(bootstrapFailedExitCode)

internal/controller/kyma/controller.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ type Reconciler struct {
8686
Metrics *metrics.KymaMetrics
8787
RemoteCatalog *remote.RemoteCatalog
8888
TemplateLookup *templatelookup.TemplateLookup
89+
OCIRegistryHost string
8990
}
9091

9192
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
@@ -584,7 +585,8 @@ func (r *Reconciler) updateKyma(ctx context.Context, kyma *v1beta2.Kyma) error {
584585

585586
func (r *Reconciler) reconcileManifests(ctx context.Context, kyma *v1beta2.Kyma) error {
586587
templates := r.TemplateLookup.GetRegularTemplates(ctx, kyma)
587-
prsr := parser.NewParser(r.Client, r.DescriptorProvider, r.RemoteSyncNamespace)
588+
//ociRepo := r.OCIRepository //"http://k3d-kcp-registry.localhost:5000" ///component-descriptors" //TODO: Get from configuration
589+
prsr := parser.NewParser(r.Client, r.DescriptorProvider, r.RemoteSyncNamespace, r.OCIRegistryHost)
588590
modules := prsr.GenerateModulesFromTemplates(kyma, templates)
589591

590592
runner := sync.New(r)

internal/controller/mandatorymodule/deletion_controller.go

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package mandatorymodule
1818

1919
import (
2020
"context"
21+
"errors"
2122
"fmt"
2223

2324
k8slabels "k8s.io/apimachinery/pkg/labels"
@@ -29,6 +30,7 @@ import (
2930
"github.com/kyma-project/lifecycle-manager/api/shared"
3031
"github.com/kyma-project/lifecycle-manager/api/v1beta2"
3132
"github.com/kyma-project/lifecycle-manager/internal/descriptor/provider"
33+
"github.com/kyma-project/lifecycle-manager/internal/descriptor/types/ocmidentity"
3234
"github.com/kyma-project/lifecycle-manager/internal/event"
3335
"github.com/kyma-project/lifecycle-manager/pkg/log"
3436
"github.com/kyma-project/lifecycle-manager/pkg/queue"
@@ -48,6 +50,26 @@ type DeletionReconciler struct {
4850
DescriptorProvider *provider.CachedDescriptorProvider
4951
}
5052

53+
// TODO: This function is a duplicate, we should use some common implementation.
54+
func (r *DeletionReconciler) FindMRMForTemplate(ctx context.Context,
55+
template *v1beta2.ModuleTemplate,
56+
) (*v1beta2.ModuleReleaseMeta, error) {
57+
if template == nil {
58+
return nil, errors.New("template is nil")
59+
}
60+
61+
key := client.ObjectKey{
62+
Name: template.Spec.ModuleName,
63+
Namespace: template.Namespace,
64+
}
65+
obj := &v1beta2.ModuleReleaseMeta{}
66+
if err := r.Get(ctx, key, obj); err != nil {
67+
return nil, fmt.Errorf("failed to get ModuleReleaseMeta %s: %w", key.String(), err)
68+
}
69+
70+
return obj, nil
71+
}
72+
5173
func (r *DeletionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
5274
logger := logf.FromContext(ctx)
5375
logger.V(log.DebugLevel).Info("Mandatory Module Deletion Reconciliation started")
@@ -76,7 +98,14 @@ func (r *DeletionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
7698
return ctrl.Result{}, nil
7799
}
78100

79-
manifests, err := r.getCorrespondingManifests(ctx, template)
101+
mrm, err := r.FindMRMForTemplate(ctx, template)
102+
if err == nil {
103+
return ctrl.Result{}, fmt.Errorf("failed to find ModuleReleaseMeta for Mandatory Module %s: %w",
104+
template.Name, err)
105+
}
106+
ocmi, err := ocmidentity.New(mrm.Spec.OcmComponentName, template.Spec.Version)
107+
108+
manifests, err := r.getCorrespondingManifests(ctx, template.Namespace, *ocmi)
80109
if err != nil {
81110
return ctrl.Result{}, fmt.Errorf("failed to get MandatoryModuleManifests: %w", err)
82111
}
@@ -107,22 +136,18 @@ func (r *DeletionReconciler) updateTemplateFinalizer(ctx context.Context,
107136
}
108137

109138
func (r *DeletionReconciler) getCorrespondingManifests(ctx context.Context,
110-
template *v1beta2.ModuleTemplate) ([]v1beta2.Manifest,
139+
namespace string, ocmi ocmidentity.Component) ([]v1beta2.Manifest,
111140
error,
112141
) {
113142
manifests := &v1beta2.ManifestList{}
114-
descriptor, err := r.DescriptorProvider.GetDescriptor(template)
115-
if err != nil {
116-
return nil, fmt.Errorf("not able to get descriptor from template: %w", err)
117-
}
118143
if err := r.List(ctx, manifests, &client.ListOptions{
119-
Namespace: template.Namespace,
144+
Namespace: namespace,
120145
LabelSelector: k8slabels.SelectorFromSet(k8slabels.Set{shared.IsMandatoryModule: "true"}),
121146
}); client.IgnoreNotFound(err) != nil {
122147
return nil, fmt.Errorf("not able to list mandatory module manifests: %w", err)
123148
}
124149

125-
filtered := filterManifestsByFQDNAndVersion(manifests.Items, descriptor.GetName(), descriptor.GetVersion())
150+
filtered := filterManifestsByComponentIdentity(manifests.Items, ocmi)
126151

127152
return filtered, nil
128153
}
@@ -137,16 +162,18 @@ func (r *DeletionReconciler) removeManifests(ctx context.Context, manifests []v1
137162
return nil
138163
}
139164

140-
func filterManifestsByFQDNAndVersion(manifests []v1beta2.Manifest,
141-
fqdn, moduleVersion string,
165+
// filterManifestsByComponentIdentity filters the manifests by OCM Component Name and module version.
166+
// OCM Component Name is a fully qualified name that looks like: 'kyma-project.io/module/<module-name>'
167+
func filterManifestsByComponentIdentity(manifests []v1beta2.Manifest,
168+
ocmi ocmidentity.Component,
142169
) []v1beta2.Manifest {
143170
filteredManifests := make([]v1beta2.Manifest, 0)
144171
for _, manifest := range manifests {
145172
if manifest.Annotations == nil {
146173
continue
147174
}
148175

149-
if manifest.Annotations[shared.FQDN] == fqdn && manifest.Spec.Version == moduleVersion {
176+
if manifest.Annotations[shared.FQDN] == ocmi.Name() && manifest.Spec.Version == ocmi.Version() {
150177
filteredManifests = append(filteredManifests, manifest)
151178
}
152179
}

internal/controller/mandatorymodule/installation_controller.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ type InstallationReconciler struct {
4343
DescriptorProvider *provider.CachedDescriptorProvider
4444
RemoteSyncNamespace string
4545
Metrics *metrics.MandatoryModulesMetrics
46+
OCIRegistryHost string
4647
}
4748

4849
func (r *InstallationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
@@ -86,7 +87,8 @@ func (r *InstallationReconciler) Reconcile(ctx context.Context, req ctrl.Request
8687
func (r *InstallationReconciler) GenerateModulesFromTemplate(ctx context.Context,
8788
templates templatelookup.ModuleTemplatesByModuleName, kyma *v1beta2.Kyma,
8889
) (modulecommon.Modules, error) {
89-
parser := parser.NewParser(r.Client, r.DescriptorProvider, r.RemoteSyncNamespace)
90+
//ociRepo := "http://k3d-kcp-registry.localhost:5000" ///component-descriptors" //TODO: Get from configuration
91+
parser := parser.NewParser(r.Client, r.DescriptorProvider, r.RemoteSyncNamespace, r.OCIRegistryHost)
9092
return parser.GenerateMandatoryModulesFromTemplates(ctx, kyma, templates), nil
9193
}
9294

internal/descriptor/cache/cache.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package cache
22

33
import (
4+
"fmt"
45
"sync"
56

67
"github.com/kyma-project/lifecycle-manager/internal/descriptor/types"
8+
"github.com/kyma-project/lifecycle-manager/internal/descriptor/types/ocmidentity"
79
)
810

911
type DescriptorCache struct {
@@ -16,7 +18,7 @@ func NewDescriptorCache() *DescriptorCache {
1618
}
1719
}
1820

19-
func (d *DescriptorCache) Get(key string) *types.Descriptor {
21+
func (d *DescriptorCache) Get(key DescriptorKey) *types.Descriptor {
2022
value, ok := d.cache.Load(key)
2123
if !ok {
2224
return nil
@@ -29,6 +31,12 @@ func (d *DescriptorCache) Get(key string) *types.Descriptor {
2931
return &types.Descriptor{ComponentDescriptor: desc.Copy()}
3032
}
3133

32-
func (d *DescriptorCache) Set(key string, value *types.Descriptor) {
34+
func (d *DescriptorCache) Set(key DescriptorKey, value *types.Descriptor) {
3335
d.cache.Store(key, value)
3436
}
37+
38+
type DescriptorKey string
39+
40+
func GenerateDescriptorKey(ocmi ocmidentity.Component) DescriptorKey {
41+
return DescriptorKey(fmt.Sprintf("%s:%s", ocmi.Name(), ocmi.Version()))
42+
}

internal/descriptor/cache/cache_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ func TestGet_ForCacheWithoutEntry_ReturnsNoEntry(t *testing.T) {
1515
descriptorCache := cache.NewDescriptorCache()
1616
key := "key 1"
1717

18-
actual := descriptorCache.Get(key)
18+
actual := descriptorCache.Get(cache.DescriptorKey(key))
1919

2020
assert.Nil(t, actual)
2121
}
@@ -32,9 +32,9 @@ func TestGet_ForCacheWithAnEntry_ReturnsAnEntry(t *testing.T) {
3232
}
3333
desc1 := &types.Descriptor{ComponentDescriptor: ocmDesc1}
3434

35-
descriptorCache.Set(key1, desc1)
35+
descriptorCache.Set(cache.DescriptorKey(key1), desc1)
3636

37-
assertDescriptorEqual(t, desc1, descriptorCache.Get(key1))
37+
assertDescriptorEqual(t, desc1, descriptorCache.Get(cache.DescriptorKey(key1)))
3838
}
3939

4040
func TestGet_ForCacheWithOverwrittenEntry_ReturnsNewEntry(t *testing.T) {
@@ -53,15 +53,15 @@ func TestGet_ForCacheWithOverwrittenEntry_ReturnsNewEntry(t *testing.T) {
5353
},
5454
},
5555
}
56-
descriptorCache.Set(originalKey, originalValue)
57-
assertDescriptorNotEqual(t, newValue, descriptorCache.Get(originalKey))
58-
assert.Nil(t, descriptorCache.Get(newKey))
56+
descriptorCache.Set(cache.DescriptorKey(originalKey), originalValue)
57+
assertDescriptorNotEqual(t, newValue, descriptorCache.Get(cache.DescriptorKey(originalKey)))
58+
assert.Nil(t, descriptorCache.Get(cache.DescriptorKey(newKey)))
5959

60-
descriptorCache.Set(newKey, newValue)
61-
descriptorCache.Set(originalKey, newValue)
60+
descriptorCache.Set(cache.DescriptorKey(newKey), newValue)
61+
descriptorCache.Set(cache.DescriptorKey(originalKey), newValue)
6262

63-
assertDescriptorEqual(t, newValue, descriptorCache.Get(newKey))
64-
assertDescriptorEqual(t, newValue, descriptorCache.Get(originalKey))
63+
assertDescriptorEqual(t, newValue, descriptorCache.Get(cache.DescriptorKey(newKey)))
64+
assertDescriptorEqual(t, newValue, descriptorCache.Get(cache.DescriptorKey(originalKey)))
6565
}
6666

6767
func assertDescriptorEqual(t *testing.T, expected, actual *types.Descriptor) {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package cache_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
8+
"github.com/kyma-project/lifecycle-manager/internal/descriptor/cache"
9+
"github.com/kyma-project/lifecycle-manager/internal/descriptor/types/ocmidentity"
10+
)
11+
12+
func TestGenerateDescriptorCacheKey(t *testing.T) {
13+
testCases := []struct {
14+
name string
15+
moduleName string
16+
moduleVersion string
17+
want string
18+
}{
19+
{
20+
name: "with valid module name and version",
21+
moduleName: "name",
22+
moduleVersion: "1.0.0",
23+
want: "name:1.0.0",
24+
},
25+
}
26+
27+
for _, tc := range testCases {
28+
t.Run(tc.name, func(t *testing.T) {
29+
ocmi := ocmidentity.MustNew(tc.moduleName, tc.moduleVersion)
30+
got := cache.GenerateDescriptorKey(*ocmi)
31+
assert.Equal(t, tc.want, string(got))
32+
})
33+
}
34+
}

0 commit comments

Comments
 (0)