distrobuilder/sources/ubuntu-http.go
Thomas Hipp 7bf831db43
*: Download to specific directory
Signed-off-by: Thomas Hipp <thomas.hipp@canonical.com>
2019-02-27 10:54:02 +01:00

148 lines
3.4 KiB
Go

package sources
import (
"crypto/sha256"
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"os"
"path"
"path/filepath"
"regexp"
"strings"
lxd "github.com/lxc/lxd/shared"
"github.com/lxc/distrobuilder/shared"
)
// UbuntuHTTP represents the Ubuntu HTTP downloader.
type UbuntuHTTP struct {
fname string
}
// NewUbuntuHTTP creates a new UbuntuHTTP instance.
func NewUbuntuHTTP() *UbuntuHTTP {
return &UbuntuHTTP{}
}
// Run downloads the tarball and unpacks it.
func (s *UbuntuHTTP) Run(definition shared.Definition, rootfsDir string) error {
baseURL := fmt.Sprintf("%s/releases/%s/release/", definition.Source.URL,
definition.Image.Release)
if strings.ContainsAny(definition.Image.Release, "0123456789") {
s.fname = fmt.Sprintf("ubuntu-base-%s-base-%s.tar.gz",
definition.Image.Release, definition.Image.ArchitectureMapped)
} else {
// if release is non-numerical, find the latest release
s.fname = getLatestRelease(definition.Source.URL,
definition.Image.Release, definition.Image.ArchitectureMapped)
if s.fname == "" {
return fmt.Errorf("Couldn't find latest release")
}
}
url, err := url.Parse(baseURL)
if err != nil {
return err
}
var fpath string
checksumFile := ""
// Force gpg checks when using http
if !definition.Source.SkipVerification && url.Scheme != "https" {
if len(definition.Source.Keys) == 0 {
return errors.New("GPG keys are required if downloading from HTTP")
}
checksumFile = baseURL + "SHA256SUMS"
fpath, err = shared.DownloadHash(definition.Image, baseURL+"SHA256SUMS.gpg", "", nil)
if err != nil {
return err
}
shared.DownloadHash(definition.Image, checksumFile, "", nil)
valid, err := shared.VerifyFile(
filepath.Join(fpath, "SHA256SUMS"),
filepath.Join(fpath, "SHA256SUMS.gpg"),
definition.Source.Keys,
definition.Source.Keyserver)
if err != nil {
return err
}
if !valid {
return fmt.Errorf("Failed to validate tarball")
}
}
fpath, err = shared.DownloadHash(definition.Image, baseURL+s.fname, checksumFile, sha256.New())
if err != nil {
return fmt.Errorf("Error downloading Ubuntu image: %s", err)
}
err = s.unpack(filepath.Join(fpath, s.fname), rootfsDir)
if err != nil {
return err
}
if definition.Source.AptSources != "" {
// Run the template
out, err := shared.RenderTemplate(definition.Source.AptSources, definition)
if err != nil {
return err
}
// Append final new line if missing
if !strings.HasSuffix(out, "\n") {
out += "\n"
}
// Replace content of sources.list with the templated content.
file, err := os.Create(filepath.Join(rootfsDir, "etc", "apt", "sources.list"))
if err != nil {
return err
}
defer file.Close()
file.WriteString(out)
}
return nil
}
func (s UbuntuHTTP) unpack(filePath, rootDir string) error {
os.RemoveAll(rootDir)
os.MkdirAll(rootDir, 0755)
err := lxd.Unpack(filePath, rootDir, false, false, nil)
if err != nil {
return fmt.Errorf("Failed to unpack tarball: %s", err)
}
return nil
}
func getLatestRelease(URL, release, arch string) string {
resp, err := http.Get(URL + path.Join("/", "releases", release, "release"))
if err != nil {
fmt.Fprintln(os.Stderr, err)
return ""
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
regex := regexp.MustCompile(fmt.Sprintf("ubuntu-base-\\d{2}\\.\\d{2}(\\.\\d+)?-base-%s.tar.gz", arch))
releases := regex.FindAllString(string(body), -1)
if len(releases) > 1 {
return string(releases[len(releases)-1])
}
return ""
}