distro: add DetectHost
lorax-composer uses the host's repositories for building images. This is prone to accidental configuration errors and duplicates functionality (adding custom repositories via the source API is much more explicit). However, blueprints don't specify the distribution they're based on. This is something they should do in the future to enable cross-distro image builds. Until then, read `/etc/os-release` to detect the host OS and use that as the base distro for a blueprint. Detection works by concatenating the ID field with a `-` and the VERSION_ID field. This mandates how additional distributions should register themselves to the `distro` package. If composer cannot build the detected distro, fall back to fedora-30. Use this detection everywhere that fedora-30 was hard-coded before.
This commit is contained in:
parent
4d4da93240
commit
f9cbc8593f
5 changed files with 131 additions and 8 deletions
|
|
@ -31,8 +31,8 @@ func main() {
|
|||
}
|
||||
}
|
||||
|
||||
f30 := distro.New("fedora-30")
|
||||
pipeline, err := f30.Pipeline(blueprint, format)
|
||||
d := distro.New("")
|
||||
pipeline, err := d.Pipeline(blueprint, format)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,13 @@
|
|||
package distro
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/osbuild/osbuild-composer/internal/blueprint"
|
||||
"github.com/osbuild/osbuild-composer/internal/pipeline"
|
||||
)
|
||||
|
|
@ -33,16 +40,78 @@ func (e *InvalidOutputFormatError) Error() string {
|
|||
var registered = map[string]Distro{}
|
||||
|
||||
func New(name string) Distro {
|
||||
if name == "" {
|
||||
distro, err := FromHost()
|
||||
if err == nil {
|
||||
return distro
|
||||
} else {
|
||||
log.Println("cannot detect distro from host: " + err.Error())
|
||||
log.Println("falling back to 'fedora-30'")
|
||||
return New("fedora-30")
|
||||
}
|
||||
}
|
||||
|
||||
distro, ok := registered[name]
|
||||
if !ok {
|
||||
panic("unknown distro: " + name)
|
||||
}
|
||||
|
||||
return distro
|
||||
}
|
||||
|
||||
func FromHost() (Distro, error) {
|
||||
f, err := os.Open("/etc/os-release")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
osrelease, err := readOSRelease(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
name := osrelease["ID"] + "-" + osrelease["VERSION_ID"]
|
||||
|
||||
distro, ok := registered[name]
|
||||
if !ok {
|
||||
return nil, errors.New("unknown distro: " + name)
|
||||
}
|
||||
return distro, nil
|
||||
}
|
||||
|
||||
func Register(name string, distro Distro) {
|
||||
if _, exists := registered[name]; exists {
|
||||
panic("a distro with this name already exists: " + name)
|
||||
}
|
||||
registered[name] = distro
|
||||
}
|
||||
|
||||
func readOSRelease(r io.Reader) (map[string]string, error) {
|
||||
osrelease := make(map[string]string)
|
||||
scanner := bufio.NewScanner(r)
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
parts := strings.SplitN(line, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
return nil, errors.New("readOSRelease: invalid input")
|
||||
}
|
||||
|
||||
key := strings.TrimSpace(parts[0])
|
||||
value := strings.TrimSpace(parts[1])
|
||||
if value[0] == '"' {
|
||||
if len(value) < 2 || value[len(value) - 1] != '"' {
|
||||
return nil, errors.New("readOSRelease: invalid input")
|
||||
}
|
||||
value = value[1:len(value) - 1]
|
||||
}
|
||||
|
||||
osrelease[key] = value
|
||||
}
|
||||
|
||||
return osrelease, nil
|
||||
}
|
||||
|
|
|
|||
54
internal/distro/osrelease_test.go
Normal file
54
internal/distro/osrelease_test.go
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
package distro
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestOSRelease(t *testing.T) {
|
||||
var cases = []struct {
|
||||
Input string
|
||||
OSRelease map[string]string
|
||||
}{
|
||||
{
|
||||
``,
|
||||
map[string]string{},
|
||||
},
|
||||
{
|
||||
`NAME=Fedora
|
||||
VERSION="30 (Workstation Edition)"
|
||||
ID=fedora
|
||||
VERSION_ID=30
|
||||
VERSION_CODENAME=""
|
||||
PLATFORM_ID="platform:f30"
|
||||
PRETTY_NAME="Fedora 30 (Workstation Edition)"
|
||||
VARIANT="Workstation Edition"
|
||||
VARIANT_ID=workstation`,
|
||||
map[string]string{
|
||||
"NAME": "Fedora",
|
||||
"VERSION": "30 (Workstation Edition)",
|
||||
"ID": "fedora",
|
||||
"VERSION_ID": "30",
|
||||
"VERSION_CODENAME": "",
|
||||
"PLATFORM_ID": "platform:f30",
|
||||
"PRETTY_NAME": "Fedora 30 (Workstation Edition)",
|
||||
"VARIANT": "Workstation Edition",
|
||||
"VARIANT_ID": "workstation",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
r := strings.NewReader(c.Input)
|
||||
|
||||
osrelease, err := readOSRelease(r)
|
||||
if err != nil {
|
||||
t.Fatalf("%d: readOSRelease: %v", i, err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(osrelease, c.OSRelease) {
|
||||
t.Fatalf("%d: readOSRelease returned unexpected result: %#v", i, osrelease)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -396,8 +396,8 @@ func (s *Store) PushCompose(composeID uuid.UUID, bp *blueprint.Blueprint, compos
|
|||
targets := []*target.Target{
|
||||
target.NewLocalTarget(target.NewLocalTargetOptions("/var/lib/osbuild-composer/outputs/" + composeID.String())),
|
||||
}
|
||||
f30 := distro.New("fedora-30")
|
||||
pipeline, err := f30.Pipeline(bp, composeType)
|
||||
d := distro.New("")
|
||||
pipeline, err := d.Pipeline(bp, composeType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -475,8 +475,8 @@ func (s *Store) GetImage(composeID uuid.UUID) (*Image, error) {
|
|||
if compose.QueueStatus != "FINISHED" {
|
||||
return nil, &InvalidRequestError{"compose was not finished"}
|
||||
}
|
||||
f30 := distro.New("fedora-30")
|
||||
name, mime, err := f30.FilenameFromType(compose.OutputType)
|
||||
d := distro.New("")
|
||||
name, mime, err := d.FilenameFromType(compose.OutputType)
|
||||
if err != nil {
|
||||
panic("invalid output type")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -850,8 +850,8 @@ func (api *API) composeTypesHandler(writer http.ResponseWriter, request *http.Re
|
|||
Types []composeType `json:"types"`
|
||||
}
|
||||
|
||||
f30 := distro.New("fedora-30")
|
||||
for _, format := range f30.ListOutputFormats() {
|
||||
d := distro.New("")
|
||||
for _, format := range d.ListOutputFormats() {
|
||||
reply.Types = append(reply.Types, composeType{format, true})
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue