package proxmox import ( "bytes" "context" "errors" "fmt" "github.com/go-logr/logr" "gitea.home.hrajfrisbee.cz/kacerr/egress-proxies-operator/internal/provider" "gitea.home.hrajfrisbee.cz/kacerr/egress-proxies-operator/internal/provider/nocloud" ) // seedISOName is the seed's file name on the ISO storage. Upload refuses a // name without the .iso suffix (F12), and GC's blind spot is documented by // this pattern (spec entry 11). func seedISOName(name string) string { return name + "-seed.iso" } // seedVolID is the seed's volume id, as ide2 references it and as the // storage content delete takes it. func seedVolID(storage, name string) string { return storage + ":iso/" + seedISOName(name) } // buildSeed renders the NoCloud seed for req in memory (spec entry 5): a // seed is tens of KiB. Nothing about its content is logged or put in an // error. Only an empty name is Permanent; a staging failure (no /tmp, a // full emptyDir) is left unclassified, so classify makes it Transient and // the reconciler retries instead of latching the Proxy. func (p *Provider) buildSeed(req provider.CreateRequest) (*bytes.Buffer, error) { vendorData, err := nocloud.BuildVendorData(p.cfg.VendorData, *p.cfg.InstallGuestAgent) if err != nil { return nil, fmt.Errorf("building vendor-data for %s: %w", req.Name, err) } var iso bytes.Buffer if err := nocloud.BuildSeedISO(req.Name, req.CloudInit, vendorData, &iso); err != nil { if errors.Is(err, nocloud.ErrEmptyName) { return nil, permanentf("building seed ISO: %v", err) } return nil, fmt.Errorf("building seed ISO for %s: %w", req.Name, err) } return &iso, nil } // uploadSeed puts a freshly built seed on the VM's node and waits for the // copy (spec entry 5). An upload overwrites a file of the same name (F12), // so what a cut-off attempt left is replaced without a delete first. func (p *Provider) uploadSeed(ctx context.Context, log logr.Logger, node string, req provider.CreateRequest) error { iso, err := p.buildSeed(req) if err != nil { return err } volid := seedVolID(p.cfg.ISOStorage, req.Name) upid, err := p.api.UploadISO(ctx, node, p.cfg.ISOStorage, seedISOName(req.Name), iso, int64(iso.Len())) if err != nil { return fmt.Errorf("uploading seed %s: %w", volid, err) } if err := p.waitTask(ctx, log, upid, p.budgets.upload); err != nil { return fmt.Errorf("uploading seed %s: %w", volid, err) } return nil }