From ed9d0ac2e4644c55d04214e56488eb3ff3f27036 Mon Sep 17 00:00:00 2001 From: liamfallon Date: Mon, 7 Oct 2024 18:52:51 +0100 Subject: [PATCH] Repo deletion working now --- pkg/cache/cache.go | 13 ++++--- pkg/db/db.go | 24 ++++++++++--- pkg/db/dbconnection.go | 12 ------- pkg/db/dbpackage.go | 24 +++++++++++++ pkg/db/dbpackagerevision.go | 39 +++++++++++++++++++++ pkg/db/dbrepository.go | 69 ++++++++++++++++++++++++++++++++----- 6 files changed, 152 insertions(+), 29 deletions(-) diff --git a/pkg/cache/cache.go b/pkg/cache/cache.go index cabe5ffc..cf096520 100644 --- a/pkg/cache/cache.go +++ b/pkg/cache/cache.go @@ -159,17 +159,20 @@ func (c *Cache) OpenRepository(ctx context.Context, repositorySpec *configapi.Re } else { mbs = git.ErrorIfMissing } - if r, err := git.OpenRepository(ctx, repositorySpec.Name, repositorySpec.Namespace, gitSpec, repositorySpec.Spec.Deployment, filepath.Join(c.cacheDir, "git"), git.GitRepositoryOptions{ + + r, err := git.OpenRepository(ctx, repositorySpec.Name, repositorySpec.Namespace, gitSpec, repositorySpec.Spec.Deployment, filepath.Join(c.cacheDir, "git"), git.GitRepositoryOptions{ CredentialResolver: c.credentialResolver, UserInfoProvider: c.userInfoProvider, MainBranchStrategy: mbs, UseGitCaBundle: c.useGitCaBundle, - }); err != nil { + }) + + if err != nil { return nil, err - } else { - cachedRepo = newRepository(key, repositorySpec, r, c.objectNotifier, c.metadataStore, c.repoSyncFrequency) - c.repositories[key] = cachedRepo } + + cachedRepo = newRepository(key, repositorySpec, r, c.objectNotifier, c.metadataStore, c.repoSyncFrequency) + c.repositories[key] = cachedRepo } else { // If there is an error from the background refresh goroutine, return it. if err := cachedRepo.getRefreshError(); err != nil { diff --git a/pkg/db/db.go b/pkg/db/db.go index a2bdc94b..446df771 100644 --- a/pkg/db/db.go +++ b/pkg/db/db.go @@ -16,6 +16,9 @@ package db import ( "context" + "database/sql" + "errors" + "fmt" "os/user" "time" @@ -42,7 +45,7 @@ func OpenRepository(ctx context.Context, name, namespace string, spec *configapi currentUser.Username = "undefined" } - dbRepository := &dbRepository{ + dbRepo := &dbRepository{ name: name, namespace: namespace, dbConnection: dbConnection, @@ -51,10 +54,23 @@ func OpenRepository(ctx context.Context, name, namespace string, spec *configapi deployment: deployment, } - dbRepository.writeToDB() - if err != nil { + foundRepo, err := dbRepo.readFromDB() + if err == nil { + if DBRepoEqual(dbRepo, &foundRepo) { + return dbRepo, nil + } else { + errorMessage := fmt.Sprintf("another repository with namespace %s and name %s already exists in the database", namespace, name) + return nil, errors.New(errorMessage) + } + } + + if err != sql.ErrNoRows { + return nil, err + } + + if err := dbRepo.writeToDB(); err != nil { return nil, err } - return dbRepository, nil + return dbRepo, nil } diff --git a/pkg/db/dbconnection.go b/pkg/db/dbconnection.go index 2e202b0e..48a27676 100644 --- a/pkg/db/dbconnection.go +++ b/pkg/db/dbconnection.go @@ -54,15 +54,3 @@ func (c *DBConnection) close() error { klog.Infof("DB Connection: closed connection to database %s using driver %s", c.dataSource, c.driver) return c.db.Close() } - -func (c *DBConnection) QueryRow(query string, args ...any) error { - klog.Infof("DB Connection: running query [%q] with args (%q)", query, args) - - if returnedVal := c.db.QueryRow(query, args...); returnedVal.Err() == nil { - klog.Infof("DB Connection: query succeeded, row created") - return nil - } else { - klog.Infof("DB Connection: query failed %q", returnedVal.Err()) - return returnedVal.Err() - } -} diff --git a/pkg/db/dbpackage.go b/pkg/db/dbpackage.go index a129fac2..0c453492 100644 --- a/pkg/db/dbpackage.go +++ b/pkg/db/dbpackage.go @@ -17,6 +17,7 @@ package db import ( "bytes" "fmt" + "slices" "strconv" "strings" "time" @@ -118,6 +119,29 @@ func (p *dbPackage) uid() types.UID { return types.UID(uuid.NewSHA1(space, buff.Bytes()).String()) } +func (p *dbPackage) Close() error { + for i := range p.packageRevisions { + if err := p.packageRevisions[i].Close(); err != nil { + return err + } + } + + return nil +} + +func (p1 *dbPackage) ShallowEqual(p2 *dbPackage) bool { + if p1 == p2 { + return true + } + + return p1.ShallowEqual(p2) && + p1.packageName == p2.packageName +} + +func DBPackageEqual(p1 dbPackage, p2 dbPackage) bool { + return p1.ShallowEqual(&p2) && slices.EqualFunc(p1.packageRevisions, p2.packageRevisions, DBPackageRevisionEqual) +} + // TODO: Replace with DB solution func getNextRevision() string { gotRevision := nextRevision diff --git a/pkg/db/dbpackagerevision.go b/pkg/db/dbpackagerevision.go index 7cc9b6ad..2ddd28ec 100644 --- a/pkg/db/dbpackagerevision.go +++ b/pkg/db/dbpackagerevision.go @@ -237,3 +237,42 @@ func (pr *dbPackageRevision) uid() types.UID { buff.WriteString(strings.ToLower(pr.KubeObjectName())) return types.UID(uuid.NewSHA1(space, buff.Bytes()).String()) } + +func (pr *dbPackageRevision) Close() error { + return nil +} + +func (pr1 *dbPackageRevision) ShallowEqual(pr2 *dbPackageRevision) bool { + if pr1 == pr2 { + return true + } + + return pr1.porchPackage.ShallowEqual(&pr2.porchPackage) && + pr1.revision == pr2.revision && + pr1.workspaceName == pr2.workspaceName +} + +func DBPackageRevisionEqual(pr1 dbPackageRevision, pr2 dbPackageRevision) bool { + return pr1.ShallowEqual(&pr2) + + // Add comparison of tasks + // && slices.EqualFunc(r1.packages, r2.packages) +} + +/* +slices.EqualFunc(numbers, strings, func(n int, s string) bool { + sn, err := strconv.ParseInt(s, 0, 64) + if err != nil { + return false + } + return n == int(sn) +}) + + +porchPackage dbPackage +revision string +updated time.Time +updatedBy string +workspaceName v1alpha1.WorkspaceName +lifecycle v1alpha1.PackageRevisionLifecycle +*/ diff --git a/pkg/db/dbrepository.go b/pkg/db/dbrepository.go index 7eb9e46f..1616e4b8 100644 --- a/pkg/db/dbrepository.go +++ b/pkg/db/dbrepository.go @@ -16,7 +16,7 @@ package db import ( "context" - "sync" + "slices" "time" "github.com/nephio-project/porch/api/porch/v1alpha1" @@ -32,7 +32,6 @@ type dbRepository struct { updated time.Time updatedBy string deployment bool - mutex sync.Mutex packages []dbPackage } @@ -49,9 +48,6 @@ func (r *dbRepository) CreatePackageRevision(ctx context.Context, obj *v1alpha1. _, span := tracer.Start(ctx, "dbRepository::CreatePackageRevision", trace.WithAttributes()) defer span.End() - r.mutex.Lock() - defer r.mutex.Unlock() - return &dbPackageDraft{ repo: r, packageName: obj.Spec.PackageName, @@ -102,7 +98,16 @@ func (r *dbRepository) Version(ctx context.Context) (string, error) { // Close cleans up any resources associated with the repository func (r *dbRepository) Close() error { klog.Infof("DB Repo close: %s:%s", r.namespace, r.name) - return r.dbConnection.close() + + defer r.dbConnection.close() + + for i := range r.packages { + if err := r.packages[i].Close(); err != nil { + return err + } + } + + return r.deleteFromDB() } func (r *dbRepository) UpdateDraftResources(ctx context.Context, draft *dbPackageDraft, new *v1alpha1.PackageRevisionResources, change *v1alpha1.Task) error { @@ -129,11 +134,59 @@ func (r *dbRepository) CloseDraft(ctx context.Context, d *dbPackageDraft) (*dbPa }, nil } -func (r *dbRepository) writeToDB() error { +func (r *dbRepository) readFromDB() (dbRepository, error) { + sqlStatement := `SELECT * FROM repositories WHERE namespace=$1 AND repo_name=$2` + + var dbRepo dbRepository + + err := r.dbConnection.db.QueryRow(sqlStatement, r.namespace, r.name).Scan( + &dbRepo.namespace, + &dbRepo.name, + &dbRepo.updated, + &dbRepo.updatedBy, + &dbRepo.deployment) + + dbRepo.dbConnection = r.dbConnection + + return dbRepo, err +} +func (r *dbRepository) writeToDB() error { sqlStatement := ` INSERT INTO repositories (namespace, repo_name, updated, updatedby, deployment) VALUES ($1, $2, $3, $4, $5)` - return r.dbConnection.QueryRow(sqlStatement, r.namespace, r.name, r.updated, r.updatedBy, r.deployment) + klog.Infof("DB Connection: running query [%q] on repository (%#v)", sqlStatement, r) + + if returnedVal := r.dbConnection.db.QueryRow( + sqlStatement, + r.namespace, r.name, r.updated, r.updatedBy, r.deployment); returnedVal.Err() == nil { + klog.Infof("DB Connection: query succeeded, row created") + return nil + } else { + klog.Infof("DB Connection: query failed %q", returnedVal.Err()) + return returnedVal.Err() + } +} + +func (r *dbRepository) deleteFromDB() error { + sqlStatement := `DELETE FROM repositories WHERE namespace=$1 AND repo_name=$2` + + returnedVal := r.dbConnection.db.QueryRow(sqlStatement, r.namespace, r.name) + + return returnedVal.Err() +} + +func (r1 *dbRepository) ShallowEqual(r2 *dbRepository) bool { + if r1 == r2 { + return true + } + + return r1.namespace == r2.namespace && + r1.name == r2.name && + r1.deployment == r2.deployment +} + +func DBRepoEqual(r1 *dbRepository, r2 *dbRepository) bool { + return r1.ShallowEqual(r2) && slices.EqualFunc(r1.packages, r2.packages, DBPackageEqual) }