mirror of
https://github.com/siderolabs/talos.git
synced 2025-12-25 19:31:20 +01:00
105 lines
2.4 KiB
Go
105 lines
2.4 KiB
Go
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"golang.org/x/sync/errgroup"
|
|
)
|
|
|
|
var extensions = map[string]string{
|
|
"aws": ".raw.zst",
|
|
"gcp": ".raw.tar.gz",
|
|
}
|
|
|
|
// FactoryDownloader is helper for downloading images from Image Factory.
|
|
type FactoryDownloader struct {
|
|
Target string
|
|
Options Options
|
|
}
|
|
|
|
func (f *FactoryDownloader) Download(ctx context.Context) error {
|
|
g, ctx := errgroup.WithContext(ctx)
|
|
|
|
for _, arch := range f.Options.Architectures {
|
|
g.Go(func() error {
|
|
artifact := fmt.Sprintf("%s-%s%s", f.Target, arch, extensions[f.Target])
|
|
|
|
r, err := f.getArtifact(ctx, artifact)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer r.Close() //nolint:errcheck
|
|
|
|
return f.saveArtifact(artifact, r)
|
|
})
|
|
}
|
|
|
|
return g.Wait()
|
|
}
|
|
|
|
func (f *FactoryDownloader) getArtifact(ctx context.Context, name string) (io.ReadCloser, error) {
|
|
url, err := url.JoinPath(
|
|
f.Options.FactoryHost,
|
|
"image",
|
|
f.Options.SchematicFor(f.Target),
|
|
f.Options.Tag,
|
|
name,
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to construct URL: %w", err)
|
|
}
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create request: %w", err)
|
|
}
|
|
|
|
log.Printf("requesting artifact: %s", url)
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to download image from %q: %w", url, err)
|
|
}
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
return nil, fmt.Errorf("unexpected status code %d when fetching %q", resp.StatusCode, url)
|
|
}
|
|
|
|
return resp.Body, nil
|
|
}
|
|
|
|
func (f *FactoryDownloader) saveArtifact(name string, r io.Reader) error {
|
|
artifact := filepath.Join(f.Options.ArtifactsPath, name)
|
|
|
|
err := os.MkdirAll(f.Options.ArtifactsPath, 0o755)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create artifacts directory %q: %w", f.Options.ArtifactsPath, err)
|
|
}
|
|
|
|
of, err := os.OpenFile(artifact, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o644)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create file %q: %w", artifact, err)
|
|
}
|
|
defer of.Close() //nolint:errcheck
|
|
|
|
log.Printf("saving artifact: %s", artifact)
|
|
|
|
_, err = io.Copy(of, r)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to write image to file %q: %w", artifact, err)
|
|
}
|
|
|
|
return nil
|
|
}
|