Skip to content

Commit 3c490da

Browse files
authored
Fix panic when listing packages with missing repository in cache (kptdev#459)
* Add robustness for nil objects to avoid panic * Add robustness for nil objects to avoid panic
1 parent 7ed0f9c commit 3c490da

5 files changed

Lines changed: 36 additions & 5 deletions

File tree

pkg/cache/dbcache/dbpackagerevision.go

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ func (pr *dbPackageRevision) UpdateLifecycle(ctx context.Context, newLifecycle p
125125
_, span := tracer.Start(ctx, "dbPackageRevision::UpdateLifecycle", trace.WithAttributes())
126126
defer span.End()
127127

128+
if pr.repo == nil {
129+
return fmt.Errorf("cannot update lifecycle for package revision %s: no associated repository", pr.KubeObjectName())
130+
}
131+
128132
if pr.lifecycle == porchapi.PackageRevisionLifecycleProposed && newLifecycle == porchapi.PackageRevisionLifecyclePublished {
129133
if err := pr.publishPR(ctx, newLifecycle); err != nil {
130134
pr.pkgRevKey.Revision = 0
@@ -142,6 +146,15 @@ func (pr *dbPackageRevision) GetPackageRevision(ctx context.Context) (*porchapi.
142146
_, span := tracer.Start(ctx, "dbPackageRevision::GetPackageRevision", trace.WithAttributes())
143147
defer span.End()
144148

149+
if pr == nil {
150+
return nil, fmt.Errorf("invalid package revision: nil object")
151+
}
152+
153+
if pr.repo == nil {
154+
klog.Warningf("package revision %+v has nil repository, skipping", pr.Key())
155+
return nil, fmt.Errorf("package revision %s has no associated repository (may be deleted or not yet cached)", pr.KubeObjectName())
156+
}
157+
145158
readPR, err := pkgRevReadFromDB(ctx, pr.Key(), false)
146159
if err != nil {
147160
if pr.GetMeta().DeletionTimestamp != nil || strings.Contains(err.Error(), "sql: no rows in result set") {
@@ -152,14 +165,14 @@ func (pr *dbPackageRevision) GetPackageRevision(ctx context.Context) (*porchapi.
152165
}
153166
}
154167

155-
_, upstreamLock, _ := pr.GetUpstreamLock(ctx)
156-
_, selfLock, _ := pr.GetLock(ctx)
168+
_, upstreamLock, _ := readPR.GetUpstreamLock(ctx)
169+
_, selfLock, _ := readPR.GetLock(ctx)
157170
kf, _ := readPR.GetKptfile(ctx)
158171

159172
status := porchapi.PackageRevisionStatus{
160173
UpstreamLock: repository.KptUpstreamLock2APIUpstreamLock(upstreamLock),
161174
SelfLock: repository.KptUpstreamLock2APIUpstreamLock(selfLock),
162-
Deployment: pr.repo.deployment,
175+
Deployment: readPR.repo.deployment,
163176
Conditions: repository.ToAPIConditions(kf),
164177
}
165178

pkg/cache/dbcache/dbpackagerevisionsql.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,18 @@ func pkgRevScanRowsFromDB(ctx context.Context, rows *sql.Rows) ([]*dbPackageRevi
305305
return nil, err
306306
}
307307

308-
pkgRev.repo = cachetypes.CacheInstance.GetRepository(pkgRev.pkgRevKey.PkgKey.RepoKey).(*dbRepository)
308+
repo := cachetypes.CacheInstance.GetRepository(pkgRev.pkgRevKey.PkgKey.RepoKey)
309+
if repo != nil {
310+
if dbRepo, ok := repo.(*dbRepository); ok {
311+
pkgRev.repo = dbRepo
312+
} else {
313+
klog.Warningf("pkgRevScanRowsFromDB: repository %+v is not a dbRepository for package revision %s", pkgRev.pkgRevKey.PkgKey.RepoKey, prK8SName)
314+
continue
315+
}
316+
} else {
317+
klog.V(4).Infof("pkgRevScanRowsFromDB: repository %+v not found in cache for package revision %s", pkgRev.pkgRevKey.PkgKey.RepoKey, prK8SName)
318+
continue
319+
}
309320
pkgRev.pkgRevKey.PkgKey.Package = repository.K8SName2PkgName(pkgK8SName)
310321
pkgRev.pkgRevKey.WorkspaceName = repository.K8SName2PkgRevWSName(pkgK8SName, prK8SName)
311322
setValueFromJSON(metaAsJSON, &pkgRev.meta)

pkg/cache/dbcache/dbrepository.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@ func (r *dbRepository) ListPackageRevisions(ctx context.Context, filter reposito
148148

149149
genericPkgRevs := make([]repository.PackageRevision, len(foundPkgRevs))
150150
for i, pkgRev := range foundPkgRevs {
151+
if pkgRev.repo == nil {
152+
klog.V(4).Infof("ListPackageRevisions: skipping package revision %+v with nil repository", pkgRev.Key())
153+
continue
154+
}
151155
genericPkgRev := repository.PackageRevision(pkgRev)
152156
if filter.MatchesLabels(ctx, genericPkgRev) {
153157
genericPkgRevs[i] = genericPkgRev

pkg/registry/porch/packagerevision.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,9 @@ func (r *packageRevisions) List(ctx context.Context, options *metainternalversio
8888
if err := r.listPackageRevisions(ctx, *filter, func(ctx context.Context, p repository.PackageRevision) error {
8989
item, err := p.GetPackageRevision(ctx)
9090
if err != nil {
91-
return err
91+
// Skip package revisions that fail to fetch (stale cache, deleted, etc.)
92+
klog.Warningf("Failed to fetch package revision %s during list, skipping: %v", p.KubeObjectName(), err)
93+
return nil
9294
}
9395
result.Items = append(result.Items, *item)
9496
return nil

pkg/registry/porch/packagerevision_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ func TestList(t *testing.T) {
150150
mockEngine.On("ListPackageRevisions", mock.Anything, mock.Anything, mock.Anything).Return([]repository.PackageRevision{
151151
mockPkgRev,
152152
}, nil)
153+
mockPkgRev.On("KubeObjectName").Return("test-package").Maybe()
153154
mockPkgRev.On("GetPackageRevision", mock.Anything).Return(nil, errors.New("error getting API package revision")).Once()
154155
result, err = packagerevisions.List(context.TODO(), &internalversion.ListOptions{})
155156
assert.NoError(t, err)

0 commit comments

Comments
 (0)