94 lines
3.2 KiB
Go
94 lines
3.2 KiB
Go
//go:build !remote
|
|
|
|
package libimage
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/containers/common/pkg/config"
|
|
"github.com/containers/storage"
|
|
"github.com/containers/storage/pkg/ioutils"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestCorruptedLayers(t *testing.T) {
|
|
// Regression tests for https://bugzilla.redhat.com/show_bug.cgi?id=1966872.
|
|
runtime := testNewRuntime(t)
|
|
ctx := context.Background()
|
|
pullOptions := &PullOptions{}
|
|
pullOptions.Writer = os.Stdout
|
|
|
|
imageName := "quay.io/libpod/alpine_nginx:latest"
|
|
|
|
exists, err := runtime.Exists(imageName)
|
|
require.NoError(t, err, "image does not exist yet")
|
|
require.False(t, exists, "image does not exist yet")
|
|
|
|
pulledImages, err := runtime.Pull(ctx, imageName, config.PullPolicyAlways, pullOptions)
|
|
require.NoError(t, err)
|
|
require.Len(t, pulledImages, 1)
|
|
image := pulledImages[0]
|
|
|
|
// Inspecting a healthy image should work.
|
|
_, err = image.Inspect(ctx, nil)
|
|
require.NoError(t, err, "inspecting healthy image should work")
|
|
|
|
exists, err = runtime.Exists(imageName)
|
|
require.NoError(t, err, "healthy image exists")
|
|
require.True(t, exists, "healthy image exists")
|
|
|
|
// Disk usage works.
|
|
_, _, err = runtime.DiskUsage(ctx)
|
|
require.NoError(t, err, "disk usage works on healthy image")
|
|
|
|
// Now remove one layer from the layers.json index in the storage. The
|
|
// image will still be listed in the container storage but attempting
|
|
// to use it will yield "layer not known" errors.
|
|
indexPath := filepath.Join(runtime.store.GraphRoot(), "vfs-layers/layers.json")
|
|
data, err := os.ReadFile(indexPath)
|
|
require.NoError(t, err, "loading layers.json")
|
|
layers := []*storage.Layer{}
|
|
err = json.Unmarshal(data, &layers)
|
|
require.NoError(t, err, "unmarshaling layers.json")
|
|
require.LessOrEqual(t, 1, len(layers), "at least one layer must be present")
|
|
|
|
// Now write back the layers without the first layer!
|
|
data, err = json.Marshal(layers[1:])
|
|
require.NoError(t, err, "unmarshaling layers.json")
|
|
err = ioutils.AtomicWriteFile(indexPath, data, 0o600) // nolint
|
|
require.NoError(t, err, "writing back layers.json")
|
|
|
|
err = image.reload() // clear the cached data
|
|
require.NoError(t, err)
|
|
|
|
// Now inspecting the image must fail!
|
|
_, err = image.Inspect(ctx, nil)
|
|
require.Error(t, err, "inspecting corrupted image should fail")
|
|
|
|
err = image.isCorrupted(ctx, imageName)
|
|
require.Error(t, err, "image is corrupted")
|
|
|
|
exists, err = runtime.Exists(imageName)
|
|
require.NoError(t, err, "corrupted image exists should not fail")
|
|
require.False(t, exists, "corrupted image should not be marked to exist")
|
|
|
|
// Disk usage does not work.
|
|
_, _, err = runtime.DiskUsage(ctx)
|
|
require.Error(t, err, "disk usage does not work on corrupted image")
|
|
require.Contains(t, err.Error(), "exists in local storage but may be corrupted", "disk usage reports corrupted image")
|
|
|
|
// Now make sure that pull will detect the corrupted image and repulls
|
|
// if needed which will repair the data corruption.
|
|
pulledImages, err = runtime.Pull(ctx, imageName, config.PullPolicyNewer, pullOptions)
|
|
require.NoError(t, err)
|
|
require.Len(t, pulledImages, 1)
|
|
image = pulledImages[0]
|
|
|
|
// Inspecting a repaired image should work.
|
|
_, err = image.Inspect(ctx, nil)
|
|
require.NoError(t, err, "inspecting repaired image should work")
|
|
}
|