7bf831db43
Signed-off-by: Thomas Hipp <thomas.hipp@canonical.com>
148 lines
3.4 KiB
Go
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 ""
|
|
}
|