composer: add provisional multi-arch support

The pipeline generation now takes the architecture as an argument.
Currently only x86_64 is supported. The architecture is detected
at start-up, and passed down to each pipeline translation.

For osbuild-pipeline we now requrie the architecture to be passed
in.

Signed-off-by: Tom Gundersen <teg@jklm.no>
This commit is contained in:
Tom Gundersen 2019-12-10 03:10:10 +01:00 committed by Lars Karlitski
parent dcc9cdedee
commit d33fc5f010
11 changed files with 48 additions and 20 deletions

View file

@ -4,6 +4,7 @@ import (
"flag"
"log"
"os"
"runtime"
"github.com/osbuild/osbuild-composer/internal/distro"
"github.com/osbuild/osbuild-composer/internal/jobqueue"
@ -14,6 +15,20 @@ import (
"github.com/coreos/go-systemd/activation"
)
func currentArch() string {
if runtime.GOARCH == "amd64" {
return "x86_64"
} else if runtime.GOARCH == "arm64" {
return "aarch64"
} else if runtime.GOARCH == "ppc64le" {
return "ppc64le"
} else if runtime.GOARCH == "s390x" {
return "s390x"
} else {
panic("unsupported architecture")
}
}
func main() {
var verbose bool
flag.BoolVar(&verbose, "v", false, "Print access log")
@ -48,7 +63,7 @@ func main() {
store := store.New(&stateDir, distribution)
jobAPI := jobqueue.New(logger, store)
weldrAPI := weldr.New(rpm, distribution, logger, store)
weldrAPI := weldr.New(rpm, currentArch(), distribution, logger, store)
go jobAPI.Serve(jobListener)
weldrAPI.Serve(weldrListener)

View file

@ -14,9 +14,11 @@ import (
func main() {
var format string
var blueprintArg string
var archArg string
var distroArg string
flag.StringVar(&format, "output-format", "qcow2", "output format")
flag.StringVar(&format, "output-format", "", "output format")
flag.StringVar(&blueprintArg, "blueprint", "", "blueprint to translate")
flag.StringVar(&archArg, "arch", "", "architecture to create image for")
flag.StringVar(&distroArg, "distro", "", "distribution to create")
flag.Parse()
@ -55,7 +57,7 @@ func main() {
panic(err.Error())
}
pipeline, err := d.Pipeline(blueprint, checksums, format)
pipeline, err := d.Pipeline(blueprint, checksums, archArg, format)
if err != nil {
panic(err.Error())
}

View file

@ -30,7 +30,7 @@ type Distro interface {
// Returns an osbuild pipeline that generates an image in the given
// output format with all packages and customizations specified in the
// given blueprint.
Pipeline(b *blueprint.Blueprint, checksums map[string]string, outputFormat string) (*pipeline.Pipeline, error)
Pipeline(b *blueprint.Blueprint, checksums map[string]string, outputArchitecture, outputFormat string) (*pipeline.Pipeline, error)
// Returns a osbuild runner that can be used on this distro.
Runner() string
@ -41,7 +41,7 @@ var registered map[string]Distro
func init() {
registered = map[string]Distro{
"fedora-30": fedora30.New(),
"rhel-8.2": rhel82.New(),
"rhel-8.2": rhel82.New(),
}
}
@ -100,10 +100,10 @@ func readOSRelease(r io.Reader) (map[string]string, error) {
key := strings.TrimSpace(parts[0])
value := strings.TrimSpace(parts[1])
if value[0] == '"' {
if len(value) < 2 || value[len(value) - 1] != '"' {
if len(value) < 2 || value[len(value)-1] != '"' {
return nil, errors.New("readOSRelease: invalid input")
}
value = value[1:len(value) - 1]
value = value[1 : len(value)-1]
}
osrelease[key] = value

View file

@ -20,6 +20,7 @@ func TestDistro_Pipeline(t *testing.T) {
for _, fileInfo := range fileInfos {
type compose struct {
Distro string `json:"distro"`
Arch string `json:"arch"`
OutputFormat string `json:"output-format"`
Checksums map[string]string `json:"checksums"`
Blueprint *blueprint.Blueprint `json:"blueprint"`
@ -46,7 +47,7 @@ func TestDistro_Pipeline(t *testing.T) {
t.Errorf("unknown distro: %v", tt.Compose.Distro)
return
}
got, err := d.Pipeline(tt.Compose.Blueprint, tt.Compose.Checksums, tt.Compose.OutputFormat)
got, err := d.Pipeline(tt.Compose.Blueprint, tt.Compose.Checksums, tt.Compose.Arch, tt.Compose.OutputFormat)
if (err != nil) != (tt.Pipeline == nil) {
t.Errorf("distro.Pipeline() error = %v", err)
return

View file

@ -270,12 +270,16 @@ func (r *Fedora30) FilenameFromType(outputFormat string) (string, string, error)
return "", "", errors.New("invalid output format: " + outputFormat)
}
func (r *Fedora30) Pipeline(b *blueprint.Blueprint, checksums map[string]string, outputFormat string) (*pipeline.Pipeline, error) {
func (r *Fedora30) Pipeline(b *blueprint.Blueprint, checksums map[string]string, outputArchitecture, outputFormat string) (*pipeline.Pipeline, error) {
output, exists := r.outputs[outputFormat]
if !exists {
return nil, errors.New("invalid output format: " + outputFormat)
}
if outputArchitecture != "x86_64" {
return nil, errors.New("invalid output architecture: " + outputArchitecture)
}
p := &pipeline.Pipeline{}
p.SetBuild(r.buildPipeline(checksums), "org.osbuild.fedora30")

View file

@ -107,7 +107,7 @@ func New() *RHEL82 {
DefaultTarget: "multi-user.target",
IncludeFSTab: true,
KernelOptions: "ro console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto",
Assembler: r.qemuAssembler("raw.xz", "image.raw.xz", 6 * GigaByte),
Assembler: r.qemuAssembler("raw.xz", "image.raw.xz", 6*GigaByte),
}
r.outputs["ext4-filesystem"] = output{
@ -294,12 +294,16 @@ func (r *RHEL82) FilenameFromType(outputFormat string) (string, string, error) {
return "", "", errors.New("invalid output format: " + outputFormat)
}
func (r *RHEL82) Pipeline(b *blueprint.Blueprint, checksums map[string]string, outputFormat string) (*pipeline.Pipeline, error) {
func (r *RHEL82) Pipeline(b *blueprint.Blueprint, checksums map[string]string, outputArchitecture, outputFormat string) (*pipeline.Pipeline, error) {
output, exists := r.outputs[outputFormat]
if !exists {
return nil, errors.New("invalid output format: " + outputFormat)
}
if outputArchitecture != "x86_64" {
return nil, errors.New("invalid output architecture: " + outputArchitecture)
}
p := &pipeline.Pipeline{}
p.SetBuild(r.buildPipeline(checksums), "org.osbuild.rhel82")

View file

@ -33,8 +33,8 @@ func (d *TestDistro) FilenameFromType(outputFormat string) (string, string, erro
return "", "", errors.New("invalid output format: " + outputFormat)
}
func (d *TestDistro) Pipeline(b *blueprint.Blueprint, checksums map[string]string, outputFormat string) (*pipeline.Pipeline, error) {
return nil, errors.New("invalid output format: " + outputFormat)
func (d *TestDistro) Pipeline(b *blueprint.Blueprint, checksums map[string]string, outputArch, outputFormat string) (*pipeline.Pipeline, error) {
return nil, errors.New("invalid output format or arch: " + outputFormat + " @ " + outputArch)
}
func (d *TestDistro) Runner() string {

View file

@ -43,7 +43,7 @@ func TestCreate(t *testing.T) {
store := store.New(nil, distro.New("fedora-30"))
api := jobqueue.New(nil, store)
err := store.PushCompose(id, &blueprint.Blueprint{}, map[string]string{"fedora": "test:foo"}, "tar", nil)
err := store.PushCompose(id, &blueprint.Blueprint{}, map[string]string{"fedora": "test:foo"}, "x86_64", "tar", nil)
if err != nil {
t.Fatalf("error pushing compose: %v", err)
}
@ -58,7 +58,7 @@ func testUpdateTransition(t *testing.T, from, to string, expectedStatus int) {
api := jobqueue.New(nil, store)
if from != "VOID" {
err := store.PushCompose(id, &blueprint.Blueprint{}, map[string]string{"fedora": "test:foo"}, "tar", nil)
err := store.PushCompose(id, &blueprint.Blueprint{}, map[string]string{"fedora": "test:foo"}, "x86_64", "tar", nil)
if err != nil {
t.Fatalf("error pushing compose: %v", err)
}

View file

@ -415,7 +415,7 @@ func (s *Store) DeleteBlueprintFromWorkspace(name string) {
})
}
func (s *Store) PushCompose(composeID uuid.UUID, bp *blueprint.Blueprint, checksums map[string]string, composeType string, uploadTarget *target.Target) error {
func (s *Store) PushCompose(composeID uuid.UUID, bp *blueprint.Blueprint, checksums map[string]string, arch, composeType string, uploadTarget *target.Target) error {
targets := []*target.Target{}
if s.stateDir != nil {
@ -430,7 +430,7 @@ func (s *Store) PushCompose(composeID uuid.UUID, bp *blueprint.Blueprint, checks
targets = append(targets, uploadTarget)
}
pipeline, err := s.distro.Pipeline(bp, checksums, composeType)
pipeline, err := s.distro.Pipeline(bp, checksums, arch, composeType)
if err != nil {
return err
}

View file

@ -31,18 +31,20 @@ type API struct {
store *store.Store
rpmmd rpmmd.RPMMD
arch string
distro distro.Distro
logger *log.Logger
router *httprouter.Router
}
func New(rpmmd rpmmd.RPMMD, distro distro.Distro, logger *log.Logger, store *store.Store) *API {
func New(rpmmd rpmmd.RPMMD, arch string, distro distro.Distro, logger *log.Logger, store *store.Store) *API {
// This needs to be shared with the worker API so that they can communicate with each other
// builds := make(chan queue.Build, 200)
api := &API{
store: store,
rpmmd: rpmmd,
arch: arch,
distro: distro,
logger: logger,
}
@ -1221,7 +1223,7 @@ func (api *API) composeHandler(writer http.ResponseWriter, request *http.Request
return
}
err = api.store.PushCompose(reply.BuildID, bp, checksums, cr.ComposeType, uploadTarget)
err = api.store.PushCompose(reply.BuildID, bp, checksums, api.arch, cr.ComposeType, uploadTarget)
// TODO: we should probably do some kind of blueprint validation in future
// for now, let's just 500 and bail out

View file

@ -31,7 +31,7 @@ func createWeldrAPI(fixtureGenerator rpmmd_mock.FixtureGenerator) (*weldr.API, *
rpm := rpmmd_mock.NewRPMMDMock(fixture)
d := distro.New("test")
return weldr.New(rpm, d, nil, fixture.Store), fixture.Store
return weldr.New(rpm, "x86_64", d, nil, fixture.Store), fixture.Store
}
func TestBasic(t *testing.T) {