Merge branch 'cache-in-go' into 'main'

Convert the cache to golang

Closes #21

See merge request greg/vms!15
This commit is contained in:
Greg Hellings
2025-01-01 00:09:52 +00:00
8 changed files with 256 additions and 26 deletions
+1 -1
View File
@@ -12,7 +12,7 @@
{
version = "39";
arch = "amd64";
eol = false;
eol = true;
}
{
version = "40";
+1 -1
View File
@@ -77,7 +77,7 @@
env = {
EFI_DIR = "${pkgs.OVMF.fd}/FV/";
PACKER_CONFIG_DIR = "./packer_config";
STORAGE_URL = "http://s3.thehellings.lan:9000";
STORAGE_URL = "s3.thehellings.lan:9000";
};
};
+25 -23
View File
@@ -2,9 +2,10 @@
writeShellApplication,
active,
distroFile,
buildGoModule,
lib,
curl,
minio-client,
go,
packer,
...
@@ -12,36 +13,37 @@
let
inherit (builtins) concatStringsSep map;
bin = buildGoModule {
pname = "cache";
version = "0.0.0";
src = ./cache;
vendorHash = "sha256-Mtq6BIlBNxI28eoLPfayov5uUqC4gMK+4ib6VKjyAlU=";
#vendorHash = lib.fakeHash;
meta.mainProgram = "main";
};
in
writeShellApplication {
name = "cache-isos";
runtimeInputs = [
curl
minio-client
go
packer
];
text =
''
push="''${1:-yes}"
if [ "$push" == "yes" ]; then
mc alias set storage "$STORAGE_URL" root "$MINIO_SECRET"
fi
mkdir -p cache
set -o pipefail
function list_isos {
''
+ (concatStringsSep "\n" (
map (d: ''
url=$(echo var.iso.url | packer console -var-file="${distroFile d}" -config-type=hcl2 sources/)
sha=$(echo var.iso.checksum | packer console -var-file="${distroFile d}" -config-type=hcl2 sources/)
distro=$(echo var.distro | packer console -var-file="${distroFile d}" -config-type=hcl2 sources/)
# shellcheck disable=SC2143
if [ -z "$(mc ls "storage/isos/cache/$distro" | grep "$sha")" ]; then
curl -L --retry 3 --retry-all-errors -o "cache/$sha.iso" "$url"
if [ "$push" == "yes" ]; then
mc put "cache/$sha.iso" "storage/isos/cache/$distro/$sha.iso"
fi
else
echo "Skipping ${d.distro} - cache/$sha.iso"
fi
'') active
));
url=$(echo var.iso.url | packer console -var-file="${d}" -config-type=hcl2 sources/)
sha=$(echo var.iso.checksum | packer console -var-file="${d}" -config-type=hcl2 sources/)
distro=$(echo var.distro | packer console -var-file="${d}" -config-type=hcl2 sources/)
echo "$url" "$sha" "$distro"
'') (lib.unique (lib.map distroFile active))
))
+ ''
}
list_isos | ${lib.getExe bin}
'';
}
+166
View File
@@ -0,0 +1,166 @@
package main
import (
"bufio"
"context"
"io"
"log"
"net/http"
"os"
"strings"
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
)
func listBucketContents(minioClient *minio.Client, bucketName string) ([]string, error) {
var contents []string
// Create a done channel to control the listing
ctx := context.Background()
// List all objects from bucket
for object := range minioClient.ListObjects(ctx, bucketName, minio.ListObjectsOptions{
Recursive: true,
}) {
if object.Err != nil {
return nil, object.Err
}
contents = append(contents, object.Key)
}
return contents, nil
}
type IsoInfo struct {
Url string
Hash string
Distro string
}
func processStdin() []IsoInfo {
var isos []IsoInfo
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
parts := strings.Split(scanner.Text(), " ")
if len(parts) == 3 {
iso := IsoInfo{
Url: parts[0],
Hash: parts[1],
Distro: parts[2],
}
isos = append(isos, iso)
}
}
if err := scanner.Err(); err != nil {
log.Println("Error reading from stdin:", err)
}
return isos
}
func downloadAndUploadIso(minioClient *minio.Client, iso IsoInfo) error {
// Create the destination file path
destPath := "cache/" + iso.Hash + ".iso"
// Create cache directory if it doesn't exist
err := os.MkdirAll("cache", 0755)
if err != nil {
return err
}
log.Println("Downloading " + iso.Url)
// Download the ISO file
resp, err := http.Get(iso.Url)
if err != nil {
return err
}
defer resp.Body.Close()
// Create the destination file
destFile, err := os.Create(destPath)
if err != nil {
return err
}
defer destFile.Close()
// Copy the downloaded content to the file
_, err = io.Copy(destFile, resp.Body)
if err != nil {
return err
}
// Reopen file for uploading
uploadFile, err := os.Open(destPath)
if err != nil {
return err
}
defer uploadFile.Close()
// Get file info for content-length
fileInfo, err := uploadFile.Stat()
if err != nil {
return err
}
log.Println("Uploading " + destPath)
uploadPath := "cache/" + iso.Distro + "/" + iso.Hash + ".iso"
// Upload the file to MinIO
_, err = minioClient.PutObject(context.Background(), "isos", uploadPath, uploadFile, fileInfo.Size(), minio.PutObjectOptions{
ContentType: "application/x-iso9660-image",
})
if err != nil {
return err
}
return nil
}
func main() {
endpoint := os.Getenv("STORAGE_URL")
log.Println("Using endpoint:", endpoint)
accessKeyID := "root"
secretAccessKey := os.Getenv("MINIO_SECRET")
if secretAccessKey == "" {
log.Fatalln("MINIO_SECRET environment variable not set")
}
useSSL := false
// Initialize minio client
minioClient, err := minio.New(endpoint, &minio.Options{
Creds: credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
Secure: useSSL,
})
if err != nil {
log.Fatalln(err)
}
// List contents of the "isos" bucket
contents, err := listBucketContents(minioClient, "isos")
if err != nil {
log.Fatalln(err)
}
isos := processStdin()
for _, iso := range isos {
// Check if ISO exists in Minio
isoPath := "cache/" + iso.Distro + "/" + iso.Hash + ".iso"
exists := false
for _, item := range contents {
if item == isoPath {
exists = true
break
}
}
if !exists {
if err := downloadAndUploadIso(minioClient, iso); err != nil {
log.Println("Error downloading/uploading ISO:", err)
os.Exit(1)
}
}
}
}
+23
View File
@@ -0,0 +1,23 @@
module main
go 1.22
require (
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/go-ini/ini v1.67.0 // indirect
github.com/goccy/go-json v0.10.3 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/minio-go/v7 v7.0.82 // indirect
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rs/xid v1.6.0 // indirect
github.com/schollz/progressbar/v3 v3.17.1 // indirect
golang.org/x/crypto v0.28.0 // indirect
golang.org/x/net v0.30.0 // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/term v0.26.0 // indirect
golang.org/x/text v0.19.0 // indirect
)
+38
View File
@@ -0,0 +1,38 @@
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
github.com/minio/minio-go/v7 v7.0.82 h1:tWfICLhmp2aFPXL8Tli0XDTHj2VB/fNf0PC1f/i1gRo=
github.com/minio/minio-go/v7 v7.0.82/go.mod h1:84gmIilaX4zcvAWWzJ5Z1WI5axN+hAbM5w25xf8xvC0=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
github.com/schollz/progressbar/v3 v3.17.1 h1:bI1MTaoQO+v5kzklBjYNRQLoVpe0zbyRZNK6DFkVC5U=
github.com/schollz/progressbar/v3 v3.17.1/go.mod h1:RzqpnsPQNjUyIgdglUjRLgD7sVnxN1wpmBMV+UiEbL4=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+1
View File
@@ -70,6 +70,7 @@ let
variables = general.variables // {
COMMAND = "packer build -only=\"hyperv-iso.amd64\" -var-file=\"\${distro}\" -var build=\${BUILD} -var cpus=2 -var memory=4096 \${EXCEPT} sources";
};
rules = [ { "if" = "$CI_COMMIT_TAG"; } ];
script = [
"packer init sources"
"echo $env:COMMAND > build.ps1"
+1 -1
View File
@@ -127,7 +127,7 @@ locals {
version = var.version
build = var.build
})
iso_location = "s3::${var.storage_url}/isos/cache/${var.distro}/${var.iso.checksum}.iso?aws_access_key_id=root&aws_access_key_secret=${var.minio_secret}"
iso_location = "s3::http://${var.storage_url}/isos/cache/${var.distro}/${var.iso.checksum}.iso?aws_access_key_id=root&aws_access_key_secret=${var.minio_secret}"
cpus = var.cpus
memory = var.memory