Skip to content

Commit edba970

Browse files
oceanc80Per Goncalves da Silva
authored andcommitted
Clear cache on startup, use tempDir for unpacking
Signed-off-by: Per Goncalves da Silva <[email protected]>
1 parent 037b9e2 commit edba970

File tree

7 files changed

+155
-140
lines changed

7 files changed

+155
-140
lines changed

catalogd/cmd/catalogd/main.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ import (
6363
"github.com/operator-framework/operator-controller/catalogd/internal/storage"
6464
"github.com/operator-framework/operator-controller/catalogd/internal/version"
6565
"github.com/operator-framework/operator-controller/catalogd/internal/webhook"
66+
"github.com/operator-framework/operator-controller/internal/util"
6667
)
6768

6869
var (
@@ -257,8 +258,8 @@ func main() {
257258
systemNamespace = podNamespace()
258259
}
259260

260-
if err := os.MkdirAll(cacheDir, 0700); err != nil {
261-
setupLog.Error(err, "unable to create cache directory")
261+
if err := util.EnsureEmptyDirectory(cacheDir, 0700); err != nil {
262+
setupLog.Error(err, "unable to ensure empty cache directory")
262263
os.Exit(1)
263264
}
264265

catalogd/internal/source/containers_image.go

Lines changed: 13 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import (
3030
"sigs.k8s.io/controller-runtime/pkg/reconcile"
3131

3232
catalogdv1 "github.com/operator-framework/operator-controller/catalogd/api/v1"
33+
"github.com/operator-framework/operator-controller/internal/rukpak/source"
34+
"github.com/operator-framework/operator-controller/internal/util"
3335
)
3436

3537
const ConfigDirLabel = "operators.operatorframework.io.index.configs.v1"
@@ -76,12 +78,11 @@ func (i *ContainersImageRegistry) Unpack(ctx context.Context, catalog *catalogdv
7678
//
7779
//////////////////////////////////////////////////////
7880
unpackPath := i.unpackPath(catalog.Name, canonicalRef.Digest())
79-
if unpackStat, err := os.Stat(unpackPath); err == nil {
80-
if !unpackStat.IsDir() {
81-
panic(fmt.Sprintf("unexpected file at unpack path %q: expected a directory", unpackPath))
82-
}
81+
if isUnpacked, unpackTime, err := source.IsImageUnpacked(unpackPath); isUnpacked && err == nil {
8382
l.Info("image already unpacked", "ref", imgRef.String(), "digest", canonicalRef.Digest().String())
84-
return successResult(unpackPath, canonicalRef, unpackStat.ModTime()), nil
83+
return successResult(unpackPath, canonicalRef, unpackTime), nil
84+
} else if err != nil {
85+
return nil, fmt.Errorf("error checking image already unpacked: %w", err)
8586
}
8687

8788
//////////////////////////////////////////////////////
@@ -154,7 +155,7 @@ func (i *ContainersImageRegistry) Unpack(ctx context.Context, catalog *catalogdv
154155
//
155156
//////////////////////////////////////////////////////
156157
if err := i.unpackImage(ctx, unpackPath, layoutRef, specIsCanonical, srcCtx); err != nil {
157-
if cleanupErr := deleteRecursive(unpackPath); cleanupErr != nil {
158+
if cleanupErr := source.DeleteReadOnlyRecursive(unpackPath); cleanupErr != nil {
158159
err = errors.Join(err, cleanupErr)
159160
}
160161
return nil, fmt.Errorf("error unpacking image: %w", err)
@@ -195,7 +196,7 @@ func successResult(unpackPath string, canonicalRef reference.Canonical, lastUnpa
195196
}
196197

197198
func (i *ContainersImageRegistry) Cleanup(_ context.Context, catalog *catalogdv1.ClusterCatalog) error {
198-
if err := deleteRecursive(i.catalogPath(catalog.Name)); err != nil {
199+
if err := source.DeleteReadOnlyRecursive(i.catalogPath(catalog.Name)); err != nil {
199200
return fmt.Errorf("error deleting catalog cache: %w", err)
200201
}
201202
return nil
@@ -296,8 +297,8 @@ func (i *ContainersImageRegistry) unpackImage(ctx context.Context, unpackPath st
296297
return wrapTerminal(fmt.Errorf("catalog image is missing the required label %q", ConfigDirLabel), specIsCanonical)
297298
}
298299

299-
if err := os.MkdirAll(unpackPath, 0700); err != nil {
300-
return fmt.Errorf("error creating unpack directory: %w", err)
300+
if err := util.EnsureEmptyDirectory(unpackPath, 0700); err != nil {
301+
return fmt.Errorf("error ensuring empty unpack directory: %w", err)
301302
}
302303
l := log.FromContext(ctx)
303304
l.Info("unpacking image", "path", unpackPath)
@@ -315,10 +316,10 @@ func (i *ContainersImageRegistry) unpackImage(ctx context.Context, unpackPath st
315316
l.Info("applied layer", "layer", i)
316317
return nil
317318
}(); err != nil {
318-
return errors.Join(err, deleteRecursive(unpackPath))
319+
return errors.Join(err, source.DeleteReadOnlyRecursive(unpackPath))
319320
}
320321
}
321-
if err := setReadOnlyRecursive(unpackPath); err != nil {
322+
if err := source.SetReadOnlyRecursive(unpackPath); err != nil {
322323
return fmt.Errorf("error making unpack directory read-only: %w", err)
323324
}
324325
return nil
@@ -362,69 +363,13 @@ func (i *ContainersImageRegistry) deleteOtherImages(catalogName string, digestTo
362363
continue
363364
}
364365
imgDirPath := filepath.Join(catalogPath, imgDir.Name())
365-
if err := deleteRecursive(imgDirPath); err != nil {
366+
if err := source.DeleteReadOnlyRecursive(imgDirPath); err != nil {
366367
return fmt.Errorf("error removing image directory: %w", err)
367368
}
368369
}
369370
return nil
370371
}
371372

372-
func setReadOnlyRecursive(root string) error {
373-
if err := filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error {
374-
if err != nil {
375-
return err
376-
}
377-
378-
fi, err := d.Info()
379-
if err != nil {
380-
return err
381-
}
382-
383-
if err := func() error {
384-
switch typ := fi.Mode().Type(); typ {
385-
case os.ModeSymlink:
386-
// do not follow symlinks
387-
// 1. if they resolve to other locations in the root, we'll find them anyway
388-
// 2. if they resolve to other locations outside the root, we don't want to change their permissions
389-
return nil
390-
case os.ModeDir:
391-
return os.Chmod(path, 0500)
392-
case 0: // regular file
393-
return os.Chmod(path, 0400)
394-
default:
395-
return fmt.Errorf("refusing to change ownership of file %q with type %v", path, typ.String())
396-
}
397-
}(); err != nil {
398-
return err
399-
}
400-
return nil
401-
}); err != nil {
402-
return fmt.Errorf("error making catalog cache read-only: %w", err)
403-
}
404-
return nil
405-
}
406-
407-
func deleteRecursive(root string) error {
408-
if err := filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error {
409-
if os.IsNotExist(err) {
410-
return nil
411-
}
412-
if err != nil {
413-
return err
414-
}
415-
if !d.IsDir() {
416-
return nil
417-
}
418-
if err := os.Chmod(path, 0700); err != nil {
419-
return err
420-
}
421-
return nil
422-
}); err != nil {
423-
return fmt.Errorf("error making catalog cache writable for deletion: %w", err)
424-
}
425-
return os.RemoveAll(root)
426-
}
427-
428373
func wrapTerminal(err error, isTerminal bool) error {
429374
if !isTerminal {
430375
return err

cmd/operator-controller/main.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ import (
6868
"github.com/operator-framework/operator-controller/internal/rukpak/preflights/crdupgradesafety"
6969
"github.com/operator-framework/operator-controller/internal/rukpak/source"
7070
"github.com/operator-framework/operator-controller/internal/scheme"
71+
"github.com/operator-framework/operator-controller/internal/util"
7172
"github.com/operator-framework/operator-controller/internal/version"
7273
)
7374

@@ -297,6 +298,11 @@ func main() {
297298
}
298299
}
299300

301+
if err := util.EnsureEmptyDirectory(cachePath, 0700); err != nil {
302+
setupLog.Error(err, "unable to ensure empty cache directory")
303+
os.Exit(1)
304+
}
305+
300306
unpacker := &source.ContainersImageRegistry{
301307
BaseCachePath: filepath.Join(cachePath, "unpack"),
302308
SourceContextFunc: func(logger logr.Logger) (*types.SystemContext, error) {
@@ -362,7 +368,7 @@ func main() {
362368
crdupgradesafety.NewPreflight(aeClient.CustomResourceDefinitions()),
363369
}
364370

365-
applier := &applier.Helm{
371+
helmApplier := &applier.Helm{
366372
ActionClientGetter: acg,
367373
Preflights: preflights,
368374
}
@@ -382,7 +388,7 @@ func main() {
382388
Client: cl,
383389
Resolver: resolver,
384390
Unpacker: unpacker,
385-
Applier: applier,
391+
Applier: helmApplier,
386392
InstalledBundleGetter: &controllers.DefaultInstalledBundleGetter{ActionClientGetter: acg},
387393
Finalizers: clusterExtensionFinalizers,
388394
Manager: cm,

internal/rukpak/source/containers_image.go

Lines changed: 12 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import (
2424
"github.com/opencontainers/go-digest"
2525
"sigs.k8s.io/controller-runtime/pkg/log"
2626
"sigs.k8s.io/controller-runtime/pkg/reconcile"
27+
28+
"github.com/operator-framework/operator-controller/internal/util"
2729
)
2830

2931
var insecurePolicy = []byte(`{"default":[{"type":"insecureAcceptAnything"}]}`)
@@ -69,12 +71,11 @@ func (i *ContainersImageRegistry) Unpack(ctx context.Context, bundle *BundleSour
6971
//
7072
//////////////////////////////////////////////////////
7173
unpackPath := i.unpackPath(bundle.Name, canonicalRef.Digest())
72-
if unpackStat, err := os.Stat(unpackPath); err == nil {
73-
if !unpackStat.IsDir() {
74-
panic(fmt.Sprintf("unexpected file at unpack path %q: expected a directory", unpackPath))
75-
}
74+
if isUnpacked, _, err := IsImageUnpacked(unpackPath); isUnpacked && err == nil {
7675
l.Info("image already unpacked", "ref", imgRef.String(), "digest", canonicalRef.Digest().String())
7776
return successResult(bundle.Name, unpackPath, canonicalRef), nil
77+
} else if err != nil {
78+
return nil, fmt.Errorf("error checking bundle already unpacked: %w", err)
7879
}
7980

8081
//////////////////////////////////////////////////////
@@ -147,7 +148,7 @@ func (i *ContainersImageRegistry) Unpack(ctx context.Context, bundle *BundleSour
147148
//
148149
//////////////////////////////////////////////////////
149150
if err := i.unpackImage(ctx, unpackPath, layoutRef, srcCtx); err != nil {
150-
if cleanupErr := deleteRecursive(unpackPath); cleanupErr != nil {
151+
if cleanupErr := DeleteReadOnlyRecursive(unpackPath); cleanupErr != nil {
151152
err = errors.Join(err, cleanupErr)
152153
}
153154
return nil, fmt.Errorf("error unpacking image: %w", err)
@@ -175,7 +176,7 @@ func successResult(bundleName, unpackPath string, canonicalRef reference.Canonic
175176
}
176177

177178
func (i *ContainersImageRegistry) Cleanup(_ context.Context, bundle *BundleSource) error {
178-
return deleteRecursive(i.bundlePath(bundle.Name))
179+
return DeleteReadOnlyRecursive(i.bundlePath(bundle.Name))
179180
}
180181

181182
func (i *ContainersImageRegistry) bundlePath(bundleName string) string {
@@ -265,8 +266,8 @@ func (i *ContainersImageRegistry) unpackImage(ctx context.Context, unpackPath st
265266
}
266267
}()
267268

268-
if err := os.MkdirAll(unpackPath, 0700); err != nil {
269-
return fmt.Errorf("error creating unpack directory: %w", err)
269+
if err := util.EnsureEmptyDirectory(unpackPath, 0700); err != nil {
270+
return fmt.Errorf("error ensuring empty unpack directory: %w", err)
270271
}
271272
l := log.FromContext(ctx)
272273
l.Info("unpacking image", "path", unpackPath)
@@ -284,10 +285,10 @@ func (i *ContainersImageRegistry) unpackImage(ctx context.Context, unpackPath st
284285
l.Info("applied layer", "layer", i)
285286
return nil
286287
}(); err != nil {
287-
return errors.Join(err, deleteRecursive(unpackPath))
288+
return errors.Join(err, DeleteReadOnlyRecursive(unpackPath))
288289
}
289290
}
290-
if err := setReadOnlyRecursive(unpackPath); err != nil {
291+
if err := SetReadOnlyRecursive(unpackPath); err != nil {
291292
return fmt.Errorf("error making unpack directory read-only: %w", err)
292293
}
293294
return nil
@@ -324,65 +325,9 @@ func (i *ContainersImageRegistry) deleteOtherImages(bundleName string, digestToK
324325
continue
325326
}
326327
imgDirPath := filepath.Join(bundlePath, imgDir.Name())
327-
if err := deleteRecursive(imgDirPath); err != nil {
328+
if err := DeleteReadOnlyRecursive(imgDirPath); err != nil {
328329
return fmt.Errorf("error removing image directory: %w", err)
329330
}
330331
}
331332
return nil
332333
}
333-
334-
func setReadOnlyRecursive(root string) error {
335-
if err := filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error {
336-
if err != nil {
337-
return err
338-
}
339-
340-
fi, err := d.Info()
341-
if err != nil {
342-
return err
343-
}
344-
345-
if err := func() error {
346-
switch typ := fi.Mode().Type(); typ {
347-
case os.ModeSymlink:
348-
// do not follow symlinks
349-
// 1. if they resolve to other locations in the root, we'll find them anyway
350-
// 2. if they resolve to other locations outside the root, we don't want to change their permissions
351-
return nil
352-
case os.ModeDir:
353-
return os.Chmod(path, 0500)
354-
case 0: // regular file
355-
return os.Chmod(path, 0400)
356-
default:
357-
return fmt.Errorf("refusing to change ownership of file %q with type %v", path, typ.String())
358-
}
359-
}(); err != nil {
360-
return err
361-
}
362-
return nil
363-
}); err != nil {
364-
return fmt.Errorf("error making bundle cache read-only: %w", err)
365-
}
366-
return nil
367-
}
368-
369-
func deleteRecursive(root string) error {
370-
if err := filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error {
371-
if os.IsNotExist(err) {
372-
return nil
373-
}
374-
if err != nil {
375-
return err
376-
}
377-
if !d.IsDir() {
378-
return nil
379-
}
380-
if err := os.Chmod(path, 0700); err != nil {
381-
return err
382-
}
383-
return nil
384-
}); err != nil {
385-
return fmt.Errorf("error making bundle cache writable for deletion: %w", err)
386-
}
387-
return os.RemoveAll(root)
388-
}

internal/rukpak/source/containers_image_test.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,16 @@ func TestUnpackUnexpectedFile(t *testing.T) {
277277
require.NoError(t, os.WriteFile(unpackPath, []byte{}, 0600))
278278

279279
// Attempt to pull and unpack the image
280-
assert.Panics(t, func() { _, _ = unpacker.Unpack(context.Background(), bundleSource) })
280+
_, err := unpacker.Unpack(context.Background(), bundleSource)
281+
require.NoError(t, err)
282+
283+
// Ensure unpack path is now a directory
284+
stat, err := os.Stat(unpackPath)
285+
require.NoError(t, err)
286+
require.True(t, stat.IsDir())
287+
288+
// Unset read-only to allow cleanup
289+
require.NoError(t, source.UnsetReadOnlyRecursive(unpackPath))
281290
}
282291

283292
func TestUnpackCopySucceedsMountFails(t *testing.T) {

0 commit comments

Comments
 (0)