mirror of
https://github.com/kairos-io/kairos-sdk.git
synced 2025-04-27 19:15:23 +00:00
176 lines
5.3 KiB
Go
176 lines
5.3 KiB
Go
package sysext
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
dockerImage "github.com/docker/docker/api/types/image"
|
|
"github.com/docker/docker/client"
|
|
"github.com/google/go-containerregistry/pkg/crane"
|
|
"github.com/google/go-containerregistry/pkg/name"
|
|
v1 "github.com/google/go-containerregistry/pkg/v1"
|
|
"github.com/google/go-containerregistry/pkg/v1/daemon"
|
|
"github.com/google/go-containerregistry/pkg/v1/empty"
|
|
"github.com/google/go-containerregistry/pkg/v1/mutate"
|
|
"github.com/google/go-containerregistry/pkg/v1/tarball"
|
|
"github.com/kairos-io/kairos-sdk/types"
|
|
"github.com/kairos-io/kairos-sdk/utils"
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
"math/rand"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"testing"
|
|
)
|
|
|
|
func TestSuite(t *testing.T) {
|
|
RegisterFailHandler(Fail)
|
|
RunSpecs(t, "sysext Test Suite")
|
|
}
|
|
|
|
var _ = Describe("sysext", Label("sysext"), Ordered, func() {
|
|
var dest string
|
|
var image v1.Image
|
|
var imageTag string
|
|
var buf bytes.Buffer
|
|
var log types.KairosLogger
|
|
var err error
|
|
|
|
BeforeEach(func() {
|
|
buf = bytes.Buffer{}
|
|
log = types.NewBufferLogger(&buf)
|
|
dest, err = os.MkdirTemp("", "")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
})
|
|
|
|
AfterEach(func() {
|
|
if CurrentSpecReport().Failed() {
|
|
_, _ = GinkgoWriter.Write(buf.Bytes())
|
|
}
|
|
Expect(os.RemoveAll(dest)).To(Succeed())
|
|
})
|
|
|
|
When("Using a normal image", func() {
|
|
BeforeEach(func() {
|
|
imageTag = createTestDockerImage()
|
|
By(fmt.Sprintf("Created image %s", imageTag))
|
|
image, err = utils.GetImage(imageTag, utils.GetCurrentPlatform(), nil, nil)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
})
|
|
AfterEach(func() {
|
|
cli, _ := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
|
|
_, _ = cli.ImageRemove(context.Background(), imageTag, dockerImage.RemoveOptions{Force: true})
|
|
By(fmt.Sprintf("Removed image %s", imageTag))
|
|
})
|
|
It("should extract the files into the dir", func() {
|
|
err = ExtractFilesFromLastLayer(image, dest, log, DefaultAllowListRegex)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
_, err := os.Stat(filepath.Join(dest, "usr", "yes"))
|
|
Expect(err).ToNot(HaveOccurred())
|
|
_, err = os.Stat(filepath.Join(dest, "etc", "yes"))
|
|
Expect(err).ToNot(HaveOccurred())
|
|
_, err = os.Stat(filepath.Join(dest, "opt", "nope"))
|
|
Expect(err).To(HaveOccurred())
|
|
_, err = os.Stat(filepath.Join(dest, "var", "nope"))
|
|
Expect(err).To(HaveOccurred())
|
|
})
|
|
It("properly uses the allowList", func() {
|
|
allowList := regexp.MustCompile(`^var|^/var`)
|
|
err = ExtractFilesFromLastLayer(image, dest, log, allowList)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
_, err := os.Stat(filepath.Join(dest, "usr", "yes"))
|
|
Expect(err).To(HaveOccurred())
|
|
_, err = os.Stat(filepath.Join(dest, "etc", "yes"))
|
|
Expect(err).To(HaveOccurred())
|
|
_, err = os.Stat(filepath.Join(dest, "opt", "nope"))
|
|
Expect(err).To(HaveOccurred())
|
|
_, err = os.Stat(filepath.Join(dest, "var", "nope"))
|
|
Expect(err).ToNot(HaveOccurred())
|
|
})
|
|
})
|
|
|
|
When("Using an empty image", func() {
|
|
BeforeEach(func() {
|
|
imageTag = createEmptyDockerImage()
|
|
By(fmt.Sprintf("Created image %s", imageTag))
|
|
image, err = utils.GetImage(imageTag, utils.GetCurrentPlatform(), nil, nil)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
})
|
|
AfterEach(func() {
|
|
cli, _ := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
|
|
_, _ = cli.ImageRemove(context.Background(), imageTag, dockerImage.RemoveOptions{Force: true})
|
|
By(fmt.Sprintf("Removed image %s", imageTag))
|
|
})
|
|
It("Fails with no layers image", func() {
|
|
// Cleanup existing image before creating a new one
|
|
|
|
err = ExtractFilesFromLastLayer(image, dest, log, DefaultAllowListRegex)
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(err).To(Equal(ErrorImageNoLayers))
|
|
})
|
|
})
|
|
})
|
|
|
|
func createEmptyDockerImage() string {
|
|
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyz0123456789")
|
|
|
|
b := make([]rune, 8)
|
|
for i := range b {
|
|
b[i] = letterRunes[rand.Intn(len(letterRunes))]
|
|
}
|
|
|
|
img, err := mutate.AppendLayers(empty.Image)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
// Set the platform to AMD64
|
|
cfg, err := img.ConfigFile()
|
|
Expect(err).ToNot(HaveOccurred())
|
|
cfg.Architecture = "amd64"
|
|
cfg.OS = "linux"
|
|
img, err = mutate.ConfigFile(img, cfg)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
tag, err := name.NewTag(fmt.Sprintf("kairos-empty-%s:latest", string(b)))
|
|
Expect(err).ToNot(HaveOccurred())
|
|
_, err = daemon.Write(tag, img)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
return tag.String()
|
|
}
|
|
|
|
func createTestDockerImage() string {
|
|
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyz0123456789")
|
|
|
|
b := make([]rune, 8)
|
|
for i := range b {
|
|
b[i] = letterRunes[rand.Intn(len(letterRunes))]
|
|
}
|
|
|
|
// We don't care about this layer so make it a bit fake
|
|
fistLayer, _ := crane.Layer(map[string][]byte{
|
|
"/etc/one": []byte("hello"),
|
|
"/etc/another": []byte("world"),
|
|
})
|
|
|
|
secondLayer, err := tarball.LayerFromFile("testdata/test.tar")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
img, err := mutate.AppendLayers(empty.Image, fistLayer, secondLayer)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
// Set the platform to AMD64
|
|
cfg, err := img.ConfigFile()
|
|
Expect(err).ToNot(HaveOccurred())
|
|
cfg.Architecture = "amd64"
|
|
cfg.OS = "linux"
|
|
img, err = mutate.ConfigFile(img, cfg)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
tag, err := name.NewTag(fmt.Sprintf("kairos-test-%s:latest", string(b)))
|
|
Expect(err).ToNot(HaveOccurred())
|
|
_, err = daemon.Write(tag, img)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
return tag.String()
|
|
}
|