image: support zip sources and align class k3s versions
This commit is contained in:
parent
8f0d5389c2
commit
eb77c94db3
@ -24,7 +24,7 @@ classes:
|
|||||||
os: ubuntu-24.04-raspi
|
os: ubuntu-24.04-raspi
|
||||||
image: ${METIS_IMAGE_RPI5_UBUNTU_WORKER}
|
image: ${METIS_IMAGE_RPI5_UBUNTU_WORKER}
|
||||||
checksum: ${METIS_IMAGE_RPI5_UBUNTU_WORKER_SHA256}
|
checksum: ${METIS_IMAGE_RPI5_UBUNTU_WORKER_SHA256}
|
||||||
k3s_version: v1.31.5+k3s1
|
k3s_version: v1.33.3+k3s1
|
||||||
default_labels:
|
default_labels:
|
||||||
hardware: rpi5
|
hardware: rpi5
|
||||||
node-role.kubernetes.io/worker: "true"
|
node-role.kubernetes.io/worker: "true"
|
||||||
@ -33,7 +33,7 @@ classes:
|
|||||||
os: ubuntu-20.04-tegra
|
os: ubuntu-20.04-tegra
|
||||||
image: ${METIS_IMAGE_JETSON_UBUNTU_ACCELERATOR}
|
image: ${METIS_IMAGE_JETSON_UBUNTU_ACCELERATOR}
|
||||||
checksum: ${METIS_IMAGE_JETSON_UBUNTU_ACCELERATOR_SHA256}
|
checksum: ${METIS_IMAGE_JETSON_UBUNTU_ACCELERATOR_SHA256}
|
||||||
k3s_version: v1.31.5+k3s1
|
k3s_version: v1.33.3+k3s1
|
||||||
default_labels:
|
default_labels:
|
||||||
hardware: jetson
|
hardware: jetson
|
||||||
jetson: "true"
|
jetson: "true"
|
||||||
@ -43,7 +43,7 @@ classes:
|
|||||||
os: ubuntu-24.04-raspi
|
os: ubuntu-24.04-raspi
|
||||||
image: ${METIS_IMAGE_RPI5_UBUNTU_CONTROL}
|
image: ${METIS_IMAGE_RPI5_UBUNTU_CONTROL}
|
||||||
checksum: ${METIS_IMAGE_RPI5_UBUNTU_CONTROL_SHA256}
|
checksum: ${METIS_IMAGE_RPI5_UBUNTU_CONTROL_SHA256}
|
||||||
k3s_version: v1.31.5+k3s1
|
k3s_version: v1.33.3+k3s1
|
||||||
default_labels:
|
default_labels:
|
||||||
hardware: rpi5
|
hardware: rpi5
|
||||||
node-role.kubernetes.io/control-plane: "true"
|
node-role.kubernetes.io/control-plane: "true"
|
||||||
@ -54,7 +54,7 @@ classes:
|
|||||||
os: debian-13
|
os: debian-13
|
||||||
image: ${METIS_IMAGE_AMD64_DEBIAN_WORKER}
|
image: ${METIS_IMAGE_AMD64_DEBIAN_WORKER}
|
||||||
checksum: ${METIS_IMAGE_AMD64_DEBIAN_WORKER_SHA256}
|
checksum: ${METIS_IMAGE_AMD64_DEBIAN_WORKER_SHA256}
|
||||||
k3s_version: v1.31.5+k3s1
|
k3s_version: v1.33.3+k3s1
|
||||||
default_labels:
|
default_labels:
|
||||||
hardware: amd64
|
hardware: amd64
|
||||||
node-role.kubernetes.io/worker: "true"
|
node-role.kubernetes.io/worker: "true"
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package image
|
package image
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"archive/zip"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
@ -35,6 +36,16 @@ func DownloadAndVerify(url, dest, checksum string) (string, error) {
|
|||||||
}
|
}
|
||||||
return dest, nil
|
return dest, nil
|
||||||
}
|
}
|
||||||
|
if strings.HasSuffix(url, ".zip") {
|
||||||
|
archive := dest + ".zip"
|
||||||
|
if err := ensureVerifiedFile(url, archive, checksum); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if err := decompressZIP(archive, dest); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return dest, nil
|
||||||
|
}
|
||||||
if err := ensureVerifiedFile(url, dest, checksum); err != nil {
|
if err := ensureVerifiedFile(url, dest, checksum); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -107,6 +118,47 @@ func decompressXZ(src, dest string) error {
|
|||||||
return out.Sync()
|
return out.Sync()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func decompressZIP(src, dest string) error {
|
||||||
|
reader, err := zip.OpenReader(src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer reader.Close()
|
||||||
|
|
||||||
|
var target *zip.File
|
||||||
|
for _, file := range reader.File {
|
||||||
|
if file.FileInfo().IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(strings.ToLower(file.Name), ".img") {
|
||||||
|
target = file
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if target == nil {
|
||||||
|
target = file
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if target == nil {
|
||||||
|
return fmt.Errorf("zip archive %s does not contain a file entry", src)
|
||||||
|
}
|
||||||
|
|
||||||
|
in, err := target.Open()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer in.Close()
|
||||||
|
|
||||||
|
out, err := os.Create(dest)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer out.Close()
|
||||||
|
if _, err := io.Copy(out, in); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return out.Sync()
|
||||||
|
}
|
||||||
|
|
||||||
// VerifyChecksum checks sha256 in the form "sha256:<hex>".
|
// VerifyChecksum checks sha256 in the form "sha256:<hex>".
|
||||||
func VerifyChecksum(path, checksum string) error {
|
func VerifyChecksum(path, checksum string) error {
|
||||||
if checksum == "" {
|
if checksum == "" {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package image
|
package image
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"archive/zip"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"os"
|
"os"
|
||||||
@ -107,3 +108,78 @@ func TestDownloadAndVerifyReplacesStaleBadArchiveCache(t *testing.T) {
|
|||||||
t.Fatalf("unexpected decompressed content: %q", string(data))
|
t.Fatalf("unexpected decompressed content: %q", string(data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDownloadDecompressesZIPFileURLs(t *testing.T) {
|
||||||
|
dir := t.TempDir()
|
||||||
|
archive := filepath.Join(dir, "base.zip")
|
||||||
|
if err := writeTestZIP(archive, map[string]string{
|
||||||
|
"nested/base.img": "metis-zip-test",
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatalf("writeTestZIP: %v", err)
|
||||||
|
}
|
||||||
|
dest := filepath.Join(dir, "copy.img")
|
||||||
|
if err := Download("file://"+archive, dest); err != nil {
|
||||||
|
t.Fatalf("Download: %v", err)
|
||||||
|
}
|
||||||
|
data, err := os.ReadFile(dest)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ReadFile: %v", err)
|
||||||
|
}
|
||||||
|
if string(data) != "metis-zip-test" {
|
||||||
|
t.Fatalf("unexpected decompressed content: %q", string(data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDownloadAndVerifyUsesArchiveChecksumForZIP(t *testing.T) {
|
||||||
|
dir := t.TempDir()
|
||||||
|
archive := filepath.Join(dir, "base.zip")
|
||||||
|
if err := writeTestZIP(archive, map[string]string{
|
||||||
|
"base.img": "metis-zip-test",
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatalf("writeTestZIP: %v", err)
|
||||||
|
}
|
||||||
|
archiveBytes, err := os.ReadFile(archive)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ReadFile archive: %v", err)
|
||||||
|
}
|
||||||
|
archiveSum := sha256.Sum256(archiveBytes)
|
||||||
|
dest := filepath.Join(dir, "copy.img")
|
||||||
|
localPath, err := DownloadAndVerify("file://"+archive, dest, "sha256:"+hex.EncodeToString(archiveSum[:]))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("DownloadAndVerify: %v", err)
|
||||||
|
}
|
||||||
|
if localPath != dest {
|
||||||
|
t.Fatalf("expected local path %s, got %s", dest, localPath)
|
||||||
|
}
|
||||||
|
data, err := os.ReadFile(dest)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ReadFile dest: %v", err)
|
||||||
|
}
|
||||||
|
if string(data) != "metis-zip-test" {
|
||||||
|
t.Fatalf("unexpected decompressed content: %q", string(data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeTestZIP(path string, files map[string]string) error {
|
||||||
|
out, err := os.Create(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer out.Close()
|
||||||
|
zw := zip.NewWriter(out)
|
||||||
|
for name, content := range files {
|
||||||
|
w, err := zw.Create(name)
|
||||||
|
if err != nil {
|
||||||
|
_ = zw.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.Write([]byte(content)); err != nil {
|
||||||
|
_ = zw.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := zw.Close(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return out.Sync()
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user