sources: Add openSUSE

Signed-off-by: Thomas Hipp <thomas.hipp@canonical.com>
This commit is contained in:
Thomas Hipp 2019-02-27 16:30:47 +01:00
parent addeb7bc3e
commit 1609d38f61
No known key found for this signature in database
GPG Key ID: 993408D1137B7D51
2 changed files with 164 additions and 0 deletions

162
sources/opensuse-http.go Normal file
View File

@ -0,0 +1,162 @@
package sources
import (
"crypto/sha256"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"os"
"path"
"path/filepath"
"strings"
"github.com/lxc/distrobuilder/shared"
lxd "github.com/lxc/lxd/shared"
"gopkg.in/antchfx/htmlquery.v1"
)
// OpenSUSEHTTP represents the OpenSUSE HTTP downloader.
type OpenSUSEHTTP struct{}
// NewOpenSUSEHTTP creates a new OpenSUSEHTTP instance.
func NewOpenSUSEHTTP() *OpenSUSEHTTP {
return &OpenSUSEHTTP{}
}
// Run downloads an OpenSUSE tarball.
func (s *OpenSUSEHTTP) Run(definition shared.Definition, rootfsDir string) error {
var baseURL string
var fname string
tarballPath := s.getPathToTarball(definition.Source.URL, definition.Image.Release,
definition.Image.ArchitectureMapped)
resp, err := http.Head(tarballPath)
if err != nil {
return fmt.Errorf("Couldn't resolve URL: %v", err)
}
baseURL, fname = path.Split(resp.Request.URL.String())
url, err := url.Parse(fmt.Sprintf("%s/%s", baseURL, fname))
if err != nil {
return err
}
fpath, err := shared.DownloadHash(definition.Image, url.String(), "", nil)
if err != nil {
return fmt.Errorf("Error downloading openSUSE image: %s", err)
}
if definition.Source.SkipVerification {
// Unpack
return lxd.Unpack(filepath.Join(fpath, fname), rootfsDir, false, false, nil)
}
checksumPath := fmt.Sprintf("%s.sha256", tarballPath)
checksumFile := path.Base(checksumPath)
shared.DownloadHash(definition.Image, checksumPath, "", nil)
valid, err := shared.VerifyFile(filepath.Join(fpath, checksumFile), "",
definition.Source.Keys, definition.Source.Keyserver)
if err != nil {
return err
}
if !valid {
return errors.New("Failed to verify tarball")
}
// Manually verify the checksum
checksum, err := shared.GetSignedContent(filepath.Join(fpath, checksumFile),
definition.Source.Keys, definition.Source.Keyserver)
if err != nil {
return fmt.Errorf("Failed to read signed file: %v", err)
}
imagePath := filepath.Join(fpath, fname)
image, err := os.Open(imagePath)
if err != nil {
return fmt.Errorf("Failed to verify image: %v", err)
}
hash := sha256.New()
_, err = io.Copy(hash, image)
if err != nil {
image.Close()
return fmt.Errorf("Failed to verify image: %v", err)
}
image.Close()
result := fmt.Sprintf("%x", hash.Sum(nil))
checksumStr := strings.TrimSpace(string(checksum))
if result != checksumStr {
return fmt.Errorf("Hash mismatch for %s: %s != %s", imagePath, result, checksumStr)
}
// Unpack
return lxd.Unpack(filepath.Join(fpath, fname), rootfsDir, false, false, nil)
}
func (s *OpenSUSEHTTP) getLatestBuild(URL string) string {
doc, err := htmlquery.LoadURL(URL)
if err != nil {
return ""
}
if doc == nil {
return ""
}
nodes := htmlquery.Find(doc, `//a[starts-with(text(),'opensuse')][ends-with(text(), 'tar.xz')][@href]/text()`)
if nodes == nil {
return ""
}
return nodes[len(nodes)-1].Data
}
func (s *OpenSUSEHTTP) getPathToTarball(baseURL string, release string, arch string) string {
u, err := url.Parse(baseURL)
if err != nil {
return ""
}
u.Path = path.Join(u.Path, "repositories", "Virtualization:", "containers:", "images:")
if strings.ToLower(release) == "tumbleweed" {
u.Path = path.Join(u.Path, "openSUSE-Tumbleweed")
switch arch {
case "i686", "x86_64":
u.Path = path.Join(u.Path, "container")
case "aarch64":
u.Path = path.Join(u.Path, "container_ARM")
case "ppc64le":
u.Path = path.Join(u.Path, "container_PowerPC")
default:
return ""
}
u.Path = path.Join(u.Path, fmt.Sprintf("opensuse-tumbleweed-image.%s-lxc.tar.xz",
arch))
} else {
u.Path = path.Join(u.Path, fmt.Sprintf("openSUSE-Leap-%s", release))
switch arch {
case "x86_64":
u.Path = path.Join(u.Path, "containers")
case "aarch64", "ppc64le":
u.Path = path.Join(u.Path, "containers_ports")
}
u.Path = path.Join(u.Path, s.getLatestBuild(u.String()))
}
return u.String()
}

View File

@ -30,6 +30,8 @@ func Get(name string) Downloader {
return NewDockerHTTP()
case "oraclelinux-http":
return NewOracleLinuxHTTP()
case "opensuse-http":
return NewOpenSUSEHTTP()
}
return nil