Skip to content

Commit

Permalink
Merge pull request nephio-project#171 from Nordix/refactor-git
Browse files Browse the repository at this point in the history
Place repositories (git/oci) behind the Repository interface and use a Factory to create instances of implementations
  • Loading branch information
nephio-prow[bot] authored Feb 25, 2025
2 parents 8303802 + 5130c1f commit adc3632
Show file tree
Hide file tree
Showing 70 changed files with 619 additions and 344 deletions.
2 changes: 1 addition & 1 deletion api/generated/openapi/zz_generated.openapi.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 22 additions & 12 deletions pkg/apiserver/apiserver.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2022,2024 The kpt and Nephio Authors
// Copyright 2022, 2024-2025 The kpt and Nephio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -27,8 +27,9 @@ import (
internalapi "github.com/nephio-project/porch/internal/api/porchinternal/v1alpha1"
"github.com/nephio-project/porch/internal/kpt/fnruntime"
"github.com/nephio-project/porch/pkg/cache"
memorycache "github.com/nephio-project/porch/pkg/cache/memory"
cachetypes "github.com/nephio-project/porch/pkg/cache/types"
"github.com/nephio-project/porch/pkg/engine"
externalrepotypes "github.com/nephio-project/porch/pkg/externalrepo/types"
"github.com/nephio-project/porch/pkg/meta"
"github.com/nephio-project/porch/pkg/registry/porch"
"google.golang.org/api/option"
Expand Down Expand Up @@ -94,7 +95,7 @@ type Config struct {
type PorchServer struct {
GenericAPIServer *genericapiserver.GenericAPIServer
coreClient client.WithWatch
cache cache.Cache
cache cachetypes.Cache
PeriodicRepoSyncFrequency time.Duration
}

Expand Down Expand Up @@ -227,13 +228,22 @@ func (c completedConfig) New() (*PorchServer, error) {
userInfoProvider := &porch.ApiserverUserInfoProvider{}

watcherMgr := engine.NewWatcherManager()

memoryCache := memorycache.NewCache(c.ExtraConfig.CacheDirectory, c.ExtraConfig.RepoSyncFrequency, c.ExtraConfig.UseUserDefinedCaBundle, memorycache.CacheOptions{
CredentialResolver: credentialResolver,
UserInfoProvider: userInfoProvider,
MetadataStore: metadataStore,
ObjectNotifier: watcherMgr,
})
cacheImpl, err := cache.CreateCacheImpl(
context.TODO(),
cachetypes.CacheOptions{
ExternalRepoOptions: externalrepotypes.ExternalRepoOptions{
LocalDirectory: c.ExtraConfig.CacheDirectory,
UseUserDefinedCaBundle: c.ExtraConfig.UseUserDefinedCaBundle,
CredentialResolver: credentialResolver,
UserInfoProvider: userInfoProvider,
},
RepoSyncFrequency: c.ExtraConfig.RepoSyncFrequency,
MetadataStore: metadataStore,
RepoPRChangeNotifier: watcherMgr,
})
if err != nil {
return nil, fmt.Errorf("failed to creeate repository cache: %w", err)
}

runnerOptionsResolver := func(namespace string) fnruntime.RunnerOptions {
runnerOptions := fnruntime.RunnerOptions{}
Expand All @@ -243,7 +253,7 @@ func (c completedConfig) New() (*PorchServer, error) {
}

cad, err := engine.NewCaDEngine(
engine.WithCache(memoryCache),
engine.WithCache(cacheImpl),
// The order of registering the function runtimes matters here. When
// evaluating a function, the runtimes will be tried in the same
// order as they are registered.
Expand All @@ -268,7 +278,7 @@ func (c completedConfig) New() (*PorchServer, error) {
s := &PorchServer{
GenericAPIServer: genericServer,
coreClient: coreClient,
cache: memoryCache,
cache: cacheImpl,
// Set background job periodic frequency the same as repo sync frequency.
PeriodicRepoSyncFrequency: c.ExtraConfig.RepoSyncFrequency,
}
Expand Down
19 changes: 13 additions & 6 deletions pkg/cache/cache.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2024 The Nephio Authors
// Copyright 2024-2025 The Nephio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -17,11 +17,18 @@ package cache
import (
"context"

configapi "github.com/nephio-project/porch/api/porchconfig/v1alpha1"
"github.com/nephio-project/porch/pkg/repository"
crcache "github.com/nephio-project/porch/pkg/cache/crcache"
cachetypes "github.com/nephio-project/porch/pkg/cache/types"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/trace"
)

type Cache interface {
OpenRepository(ctx context.Context, repositorySpec *configapi.Repository) (repository.Repository, error)
CloseRepository(ctx context.Context, repositorySpec *configapi.Repository, allRepos []configapi.Repository) error
var tracer = otel.Tracer("cache")

func CreateCacheImpl(ctx context.Context, options cachetypes.CacheOptions) (cachetypes.Cache, error) {
ctx, span := tracer.Start(ctx, "Repository::RepositoryFactory", trace.WithAttributes())
defer span.End()

var cacheFactory = new(crcache.CrCacheFactory)
return cacheFactory.NewCache(ctx, options)
}
134 changes: 134 additions & 0 deletions pkg/cache/crcache/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// Copyright 2022, 2024-2025 The kpt and Nephio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package crcache

import (
"context"
"errors"
"sync"

configapi "github.com/nephio-project/porch/api/porchconfig/v1alpha1"
cachetypes "github.com/nephio-project/porch/pkg/cache/types"
"github.com/nephio-project/porch/pkg/externalrepo"
"github.com/nephio-project/porch/pkg/repository"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/trace"
)

var tracer = otel.Tracer("crCache")

// Cache allows us to keep state for repositories, rather than querying them every time.
//
// Cache Structure:
// <cacheDir>/git/
// * Caches bare git repositories in directories named based on the repository address.
// <cacheDir>/oci/
// * Caches oci images with further hierarchy underneath
// * We Cache image layers in <cacheDir>/oci/layers/ (this might be obsolete with the flattened Cache)
// * We Cache flattened tar files in <cacheDir>/oci/ (so we don't need to pull to read resources)
// * We poll the repositories periodically (configurable) and cache the discovered images in a PackageRev CR.
type Cache struct {
mutex sync.Mutex
repositories map[string]*cachedRepository
options cachetypes.CacheOptions
}

var _ cachetypes.Cache = &Cache{}

func (c *Cache) OpenRepository(ctx context.Context, repositorySpec *configapi.Repository) (repository.Repository, error) {
ctx, span := tracer.Start(ctx, "Cache::OpenRepository", trace.WithAttributes())
defer span.End()

key, err := externalrepo.RepositoryKey(repositorySpec)
if err != nil {
return nil, err
}

c.mutex.Lock()
defer c.mutex.Unlock()

if cachedRepo := c.repositories[key]; cachedRepo != nil {
// If there is an error from the background refresh goroutine, return it.
if err := cachedRepo.getRefreshError(); err == nil {
return cachedRepo, nil
} else {
return nil, err
}
}

externalRepo, err := externalrepo.CreateRepositoryImpl(ctx, repositorySpec, c.options.ExternalRepoOptions)
if err != nil {
return nil, err
}

cachedRepo := newRepository(key, repositorySpec, externalRepo, c.options)
c.repositories[key] = cachedRepo

return cachedRepo, nil
}

func (c *Cache) UpdateRepository(ctx context.Context, repositorySpec *configapi.Repository) error {
return errors.New("update on CR cached repositories is not supported")
}

func (c *Cache) CloseRepository(ctx context.Context, repositorySpec *configapi.Repository, allRepos []configapi.Repository) error {
_, span := tracer.Start(ctx, "Cache::CloseRepository", trace.WithAttributes())
defer span.End()

key, err := externalrepo.RepositoryKey(repositorySpec)
if err != nil {
return err
}

// check if repositorySpec shares the underlying cached repo with another repository
for _, r := range allRepos {
if r.Name == repositorySpec.Name && r.Namespace == repositorySpec.Namespace {
continue
}
otherKey, err := externalrepo.RepositoryKey(&r)
if err != nil {
return err
}
if otherKey == key {
// do not close cached repo if it is shared
return nil
}
}

var repository *cachedRepository
{
c.mutex.Lock()
if r, ok := c.repositories[key]; ok {
delete(c.repositories, key)
repository = r
}
c.mutex.Unlock()
}

if repository != nil {
return repository.Close()
} else {
return nil
}
}

func (c *Cache) GetRepositories(ctx context.Context) []configapi.Repository {
repoSlice := []configapi.Repository{}

for _, repo := range c.repositories {
repoSlice = append(repoSlice, *repo.repoSpec)
}
return repoSlice
}
29 changes: 18 additions & 11 deletions pkg/cache/memory/cache_test.go → pkg/cache/crcache/cache_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2022, 2024 The kpt and Nephio Authors
// Copyright 2022, 2024-2025 The kpt and Nephio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package memory
package crcache

import (
"context"
Expand All @@ -27,7 +27,9 @@ import (
"github.com/nephio-project/porch/api/porchconfig/v1alpha1"

fakecache "github.com/nephio-project/porch/pkg/cache/fake"
"github.com/nephio-project/porch/pkg/git"
cachetypes "github.com/nephio-project/porch/pkg/cache/types"
"github.com/nephio-project/porch/pkg/externalrepo/git"
externalrepotypes "github.com/nephio-project/porch/pkg/externalrepo/types"
"github.com/nephio-project/porch/pkg/meta"
fakemeta "github.com/nephio-project/porch/pkg/meta/fake"
"github.com/nephio-project/porch/pkg/repository"
Expand All @@ -37,7 +39,7 @@ import (

func TestLatestPackages(t *testing.T) {
ctx := context.Background()
testPath := filepath.Join("..", "..", "git", "testdata")
testPath := filepath.Join("..", "..", "externalrepo", "git", "testdata")

cachedRepo := openRepositoryFromArchive(t, ctx, testPath, "nested")

Expand Down Expand Up @@ -83,7 +85,7 @@ func TestLatestPackages(t *testing.T) {

func TestPublishedLatest(t *testing.T) {
ctx := context.Background()
testPath := filepath.Join("..", "..", "git", "testdata")
testPath := filepath.Join("..", "..", "externalrepo", "git", "testdata")
cachedRepo := openRepositoryFromArchive(t, ctx, testPath, "nested")

revisions, err := cachedRepo.ListPackageRevisions(ctx, repository.ListPackageRevisionFilter{
Expand Down Expand Up @@ -129,7 +131,7 @@ func TestPublishedLatest(t *testing.T) {

func TestDeletePublishedMain(t *testing.T) {
ctx := context.Background()
testPath := filepath.Join("../..", "git", "testdata")
testPath := filepath.Join("../..", "externalrepo", "git", "testdata")
cachedRepo := openRepositoryFromArchive(t, ctx, testPath, "nested")

revisions, err := cachedRepo.ListPackageRevisions(ctx, repository.ListPackageRevisionFilter{
Expand Down Expand Up @@ -223,10 +225,15 @@ func openRepositoryFromArchive(t *testing.T, ctx context.Context, testPath, name
_, address := git.ServeGitRepository(t, tarfile, tempdir)
metadataStore := createMetadataStoreFromArchive(t, fmt.Sprintf("%s-metadata.yaml", name), name)

cache := NewCache(t.TempDir(), 60*time.Second, true, CacheOptions{
MetadataStore: metadataStore,
ObjectNotifier: &fakecache.ObjectNotifier{},
CredentialResolver: &fakecache.CredentialResolver{},
cache, _ := new(CrCacheFactory).NewCache(ctx, cachetypes.CacheOptions{
ExternalRepoOptions: externalrepotypes.ExternalRepoOptions{
LocalDirectory: t.TempDir(),
UseUserDefinedCaBundle: true,
CredentialResolver: &fakecache.CredentialResolver{},
},
RepoSyncFrequency: 60 * time.Second,
MetadataStore: metadataStore,
RepoPRChangeNotifier: &fakecache.ObjectNotifier{},
})
apiRepo := &v1alpha1.Repository{
TypeMeta: metav1.TypeMeta{
Expand Down Expand Up @@ -255,7 +262,7 @@ func openRepositoryFromArchive(t *testing.T, ctx context.Context, testPath, name
if err != nil {
t.Errorf("CloseRepository(%q) failed: %v", address, err)
}
if len(cache.repositories) != 0 {
if len(cache.GetRepositories(ctx)) != 0 {
t.Errorf("CloseRepository hasn't deleted repository from cache")
}
})
Expand Down
33 changes: 33 additions & 0 deletions pkg/cache/crcache/crcachefactory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright 2025 The kpt and Nephio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package crcache

import (
"context"

cachetypes "github.com/nephio-project/porch/pkg/cache/types"
)

var _ cachetypes.CacheFactory = &CrCacheFactory{}

type CrCacheFactory struct {
}

func (f *CrCacheFactory) NewCache(_ context.Context, options cachetypes.CacheOptions) (cachetypes.Cache, error) {
return &Cache{
repositories: make(map[string]*cachedRepository),
options: options,
}, nil
}
4 changes: 2 additions & 2 deletions pkg/cache/memory/package.go → pkg/cache/crcache/package.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2022, 2024 The kpt and Nephio Authors
// Copyright 2022, 2024-2025 The kpt and Nephio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package memory
package crcache

import (
"github.com/nephio-project/porch/pkg/repository"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2022, 2024 The kpt and Nephio Authors
// Copyright 2022, 2024-2025 The kpt and Nephio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package memory
package crcache

import (
"context"
Expand Down
Loading

0 comments on commit adc3632

Please sign in to comment.