runner: introduce runner abstraction

For now all it does is represent the name of the runner and what requirements
it has of the build pipeline.

Move some package definitions from the runner package set to where it belongs.
This commit is contained in:
Tom Gundersen 2022-07-08 01:34:38 +01:00
parent 33fe2da25c
commit 529bc803db
22 changed files with 101 additions and 40 deletions

View file

@ -14,13 +14,14 @@ import (
"github.com/osbuild/osbuild-composer/internal/distroregistry" "github.com/osbuild/osbuild-composer/internal/distroregistry"
"github.com/osbuild/osbuild-composer/internal/manifest" "github.com/osbuild/osbuild-composer/internal/manifest"
"github.com/osbuild/osbuild-composer/internal/rpmmd" "github.com/osbuild/osbuild-composer/internal/rpmmd"
"github.com/osbuild/osbuild-composer/internal/runner"
) )
var ImageTypes = make(map[string]ImageType) var ImageTypes = make(map[string]ImageType)
type ImageType interface { type ImageType interface {
Name() string Name() string
InstantiateManifest(m *manifest.Manifest, repos []rpmmd.RepoConfig, runner string) error InstantiateManifest(m *manifest.Manifest, repos []rpmmd.RepoConfig, runner runner.Runner) error
GetExports() []string GetExports() []string
GetCheckpoints() []string GetCheckpoints() []string
} }

View file

@ -4,6 +4,7 @@ import (
"github.com/osbuild/osbuild-composer/internal/manifest" "github.com/osbuild/osbuild-composer/internal/manifest"
"github.com/osbuild/osbuild-composer/internal/platform" "github.com/osbuild/osbuild-composer/internal/platform"
"github.com/osbuild/osbuild-composer/internal/rpmmd" "github.com/osbuild/osbuild-composer/internal/rpmmd"
"github.com/osbuild/osbuild-composer/internal/runner"
) )
func init() { func init() {
@ -35,7 +36,7 @@ func (img *MyImage) Name() string {
// Return nil when you are done, or an error if something // Return nil when you are done, or an error if something
// went wrong. Your manifest will be streamed to osbuild // went wrong. Your manifest will be streamed to osbuild
// for building. // for building.
func (img *MyImage) InstantiateManifest(m *manifest.Manifest, repos []rpmmd.RepoConfig, runner string) error { func (img *MyImage) InstantiateManifest(m *manifest.Manifest, repos []rpmmd.RepoConfig, runner runner.Runner) error {
// Let's create a simple OCI container! // Let's create a simple OCI container!
// configure a build pipeline // configure a build pipeline

View file

@ -10,6 +10,7 @@ import (
"github.com/osbuild/osbuild-composer/internal/manifest" "github.com/osbuild/osbuild-composer/internal/manifest"
"github.com/osbuild/osbuild-composer/internal/osbuild2" "github.com/osbuild/osbuild-composer/internal/osbuild2"
"github.com/osbuild/osbuild-composer/internal/rpmmd" "github.com/osbuild/osbuild-composer/internal/rpmmd"
"github.com/osbuild/osbuild-composer/internal/runner"
) )
func RunPlayground(img ImageType, d distro.Distro, arch distro.Arch, repos map[string][]rpmmd.RepoConfig, state_dir string) { func RunPlayground(img ImageType, d distro.Distro, arch distro.Arch, repos map[string][]rpmmd.RepoConfig, state_dir string) {
@ -22,8 +23,8 @@ func RunPlayground(img ImageType, d distro.Distro, arch distro.Arch, repos map[s
manifest := manifest.New() manifest := manifest.New()
// TODO: figure out the runner situation // TODO: query distro for runner
err := img.InstantiateManifest(&manifest, repos[arch.Name()], "org.osbuild.fedora36") err := img.InstantiateManifest(&manifest, repos[arch.Name()], &runner.Fedora{Version: 36})
if err != nil { if err != nil {
panic("InstantiateManifest() failed: " + err.Error()) panic("InstantiateManifest() failed: " + err.Error())
} }

View file

@ -14,6 +14,7 @@ import (
"github.com/osbuild/osbuild-composer/internal/manifest" "github.com/osbuild/osbuild-composer/internal/manifest"
"github.com/osbuild/osbuild-composer/internal/platform" "github.com/osbuild/osbuild-composer/internal/platform"
"github.com/osbuild/osbuild-composer/internal/rpmmd" "github.com/osbuild/osbuild-composer/internal/rpmmd"
"github.com/osbuild/osbuild-composer/internal/runner"
"github.com/osbuild/osbuild-composer/internal/workload" "github.com/osbuild/osbuild-composer/internal/workload"
) )
@ -289,7 +290,7 @@ type distribution struct {
vendor string vendor string
ostreeRefTmpl string ostreeRefTmpl string
isolabelTmpl string isolabelTmpl string
runner string runner runner.Runner
arches map[string]distro.Arch arches map[string]distro.Arch
defaultImageConfig *distro.ImageConfig defaultImageConfig *distro.ImageConfig
} }
@ -311,7 +312,7 @@ var distroMap = map[string]distribution{
vendor: "fedora", vendor: "fedora",
ostreeRefTmpl: "fedora/34/%s/iot", ostreeRefTmpl: "fedora/34/%s/iot",
isolabelTmpl: "Fedora-34-BaseOS-%s", isolabelTmpl: "Fedora-34-BaseOS-%s",
runner: "org.osbuild.fedora34", runner: &runner.Fedora{Version: 34},
defaultImageConfig: defaultDistroImageConfig, defaultImageConfig: defaultDistroImageConfig,
}, },
fedora35Distribution: { fedora35Distribution: {
@ -323,7 +324,7 @@ var distroMap = map[string]distribution{
vendor: "fedora", vendor: "fedora",
ostreeRefTmpl: "fedora/35/%s/iot", ostreeRefTmpl: "fedora/35/%s/iot",
isolabelTmpl: "Fedora-35-BaseOS-%s", isolabelTmpl: "Fedora-35-BaseOS-%s",
runner: "org.osbuild.fedora35", runner: &runner.Fedora{Version: 35},
defaultImageConfig: defaultDistroImageConfig, defaultImageConfig: defaultDistroImageConfig,
}, },
fedora36Distribution: { fedora36Distribution: {
@ -335,7 +336,7 @@ var distroMap = map[string]distribution{
vendor: "fedora", vendor: "fedora",
ostreeRefTmpl: "fedora/36/%s/iot", ostreeRefTmpl: "fedora/36/%s/iot",
isolabelTmpl: "Fedora-36-BaseOS-%s", isolabelTmpl: "Fedora-36-BaseOS-%s",
runner: "org.osbuild.fedora36", runner: &runner.Fedora{Version: 36},
defaultImageConfig: defaultDistroImageConfig, defaultImageConfig: defaultDistroImageConfig,
}, },
} }

View file

@ -52,7 +52,7 @@ func NewAnacondaPipeline(m *Manifest,
product, product,
version string) *AnacondaPipeline { version string) *AnacondaPipeline {
p := &AnacondaPipeline{ p := &AnacondaPipeline{
BasePipeline: NewBasePipeline(m, "anaconda-tree", buildPipeline, nil), BasePipeline: NewBasePipeline(m, "anaconda-tree", buildPipeline),
repos: repos, repos: repos,
kernelName: kernelName, kernelName: kernelName,
arch: arch, arch: arch,

View file

@ -3,6 +3,7 @@ package manifest
import ( import (
"github.com/osbuild/osbuild-composer/internal/osbuild2" "github.com/osbuild/osbuild-composer/internal/osbuild2"
"github.com/osbuild/osbuild-composer/internal/rpmmd" "github.com/osbuild/osbuild-composer/internal/rpmmd"
"github.com/osbuild/osbuild-composer/internal/runner"
) )
// A BuildPipeline represents the build environment for other pipelines. As a // A BuildPipeline represents the build environment for other pipelines. As a
@ -15,6 +16,7 @@ import (
type BuildPipeline struct { type BuildPipeline struct {
BasePipeline BasePipeline
runner runner.Runner
dependents []Pipeline dependents []Pipeline
repos []rpmmd.RepoConfig repos []rpmmd.RepoConfig
packageSpecs []rpmmd.PackageSpec packageSpecs []rpmmd.PackageSpec
@ -22,9 +24,10 @@ type BuildPipeline struct {
// NewBuildPipeline creates a new build pipeline from the repositories in repos // NewBuildPipeline creates a new build pipeline from the repositories in repos
// and the specified packages. // and the specified packages.
func NewBuildPipeline(m *Manifest, runner string, repos []rpmmd.RepoConfig) *BuildPipeline { func NewBuildPipeline(m *Manifest, runner runner.Runner, repos []rpmmd.RepoConfig) *BuildPipeline {
pipeline := &BuildPipeline{ pipeline := &BuildPipeline{
BasePipeline: NewBasePipeline(m, "build", nil, &runner), BasePipeline: NewBasePipeline(m, "build", nil),
runner: runner,
dependents: make([]Pipeline, 0), dependents: make([]Pipeline, 0),
repos: repos, repos: repos,
} }
@ -37,17 +40,16 @@ func (p *BuildPipeline) addDependent(dep Pipeline) {
} }
func (p *BuildPipeline) getPackageSetChain() []rpmmd.PackageSet { func (p *BuildPipeline) getPackageSetChain() []rpmmd.PackageSet {
// TODO: have a runner abstraction that provides the necessary packages
// TODO: make the /usr/bin/cp dependency conditional // TODO: make the /usr/bin/cp dependency conditional
// TODO: make the /usr/bin/xz dependency conditional // TODO: make the /usr/bin/xz dependency conditional
packages := []string{ packages := []string{
"selinux-policy-targeted", // needed to build the build pipeline "selinux-policy-targeted", // needed to build the build pipeline
"coreutils", // /usr/bin/cp - used all over "coreutils", // /usr/bin/cp - used all over
"glibc", // ldconfig - used in the runner
"systemd", // systemd-tmpfiles and systemd-sysusers - used in the runner
"xz", // usage unclear "xz", // usage unclear
} }
packages = append(packages, p.runner.GetBuildPackages()...)
for _, pipeline := range p.dependents { for _, pipeline := range p.dependents {
packages = append(packages, pipeline.getBuildPackages()...) packages = append(packages, pipeline.getBuildPackages()...)
} }
@ -83,6 +85,7 @@ func (p *BuildPipeline) serialize() osbuild2.Pipeline {
panic("serialization not started") panic("serialization not started")
} }
pipeline := p.BasePipeline.serialize() pipeline := p.BasePipeline.serialize()
pipeline.Runner = p.runner.String()
pipeline.AddStage(osbuild2.NewRPMStage(osbuild2.NewRPMStageOptions(p.repos), osbuild2.NewRpmStageSourceFilesInputs(p.packageSpecs))) pipeline.AddStage(osbuild2.NewRPMStage(osbuild2.NewRPMStageOptions(p.repos), osbuild2.NewRpmStageSourceFilesInputs(p.packageSpecs)))
pipeline.AddStage(osbuild2.NewSELinuxStage(&osbuild2.SELinuxStageOptions{ pipeline.AddStage(osbuild2.NewSELinuxStage(&osbuild2.SELinuxStageOptions{

View file

@ -21,7 +21,7 @@ func NewOSTreeCommitPipeline(m *Manifest,
treePipeline *OSPipeline, treePipeline *OSPipeline,
ref string) *OSTreeCommitPipeline { ref string) *OSTreeCommitPipeline {
p := &OSTreeCommitPipeline{ p := &OSTreeCommitPipeline{
BasePipeline: NewBasePipeline(m, "ostree-commit", buildPipeline, nil), BasePipeline: NewBasePipeline(m, "ostree-commit", buildPipeline),
treePipeline: treePipeline, treePipeline: treePipeline,
ref: ref, ref: ref,
} }

View file

@ -39,7 +39,7 @@ func NewOSTreeCommitServerTreePipeline(m *Manifest,
nginxConfigPath, nginxConfigPath,
listenPort string) *OSTreeCommitServerTreePipeline { listenPort string) *OSTreeCommitServerTreePipeline {
p := &OSTreeCommitServerTreePipeline{ p := &OSTreeCommitServerTreePipeline{
BasePipeline: NewBasePipeline(m, "container-tree", buildPipeline, nil), BasePipeline: NewBasePipeline(m, "container-tree", buildPipeline),
repos: repos, repos: repos,
commitPipeline: commitPipeline, commitPipeline: commitPipeline,
nginxConfigPath: nginxConfigPath, nginxConfigPath: nginxConfigPath,

View file

@ -19,7 +19,7 @@ func NewISOPipeline(m *Manifest,
treePipeline *ISOTreePipeline, treePipeline *ISOTreePipeline,
filename string) *ISOPipeline { filename string) *ISOPipeline {
p := &ISOPipeline{ p := &ISOPipeline{
BasePipeline: NewBasePipeline(m, "bootiso", buildPipeline, nil), BasePipeline: NewBasePipeline(m, "bootiso", buildPipeline),
treePipeline: treePipeline, treePipeline: treePipeline,
filename: filename, filename: filename,
} }

View file

@ -39,7 +39,7 @@ func NewISOTreePipeline(m *Manifest,
isoLabel := fmt.Sprintf(isoLabelTmpl, anacondaPipeline.arch) isoLabel := fmt.Sprintf(isoLabelTmpl, anacondaPipeline.arch)
p := &ISOTreePipeline{ p := &ISOTreePipeline{
BasePipeline: NewBasePipeline(m, "bootiso-tree", buildPipeline, nil), BasePipeline: NewBasePipeline(m, "bootiso-tree", buildPipeline),
anacondaPipeline: anacondaPipeline, anacondaPipeline: anacondaPipeline,
isoLabel: isoLabel, isoLabel: isoLabel,
osTreeCommit: osTreeCommit, osTreeCommit: osTreeCommit,

View file

@ -19,7 +19,7 @@ func NewLiveImgPipeline(m *Manifest,
treePipeline *OSPipeline, treePipeline *OSPipeline,
filename string) *LiveImgPipeline { filename string) *LiveImgPipeline {
p := &LiveImgPipeline{ p := &LiveImgPipeline{
BasePipeline: NewBasePipeline(m, "image", buildPipeline, nil), BasePipeline: NewBasePipeline(m, "image", buildPipeline),
treePipeline: treePipeline, treePipeline: treePipeline,
filename: filename, filename: filename,
} }

View file

@ -22,7 +22,7 @@ func NewOCIContainerPipeline(m *Manifest,
architecture, architecture,
filename string) *OCIContainerPipeline { filename string) *OCIContainerPipeline {
p := &OCIContainerPipeline{ p := &OCIContainerPipeline{
BasePipeline: NewBasePipeline(m, "container", buildPipeline, nil), BasePipeline: NewBasePipeline(m, "container", buildPipeline),
treePipeline: treePipeline, treePipeline: treePipeline,
architecture: architecture, architecture: architecture,
filename: filename, filename: filename,

View file

@ -110,7 +110,7 @@ func NewOSPipeline(m *Manifest,
platform platform.Platform, platform platform.Platform,
repos []rpmmd.RepoConfig) *OSPipeline { repos []rpmmd.RepoConfig) *OSPipeline {
p := &OSPipeline{ p := &OSPipeline{
BasePipeline: NewBasePipeline(m, "os", buildPipeline, nil), BasePipeline: NewBasePipeline(m, "os", buildPipeline),
repos: repos, repos: repos,
platform: platform, platform: platform,
Language: "C.UTF-8", Language: "C.UTF-8",

View file

@ -28,7 +28,6 @@ type Pipeline interface {
type BasePipeline struct { type BasePipeline struct {
manifest *Manifest manifest *Manifest
name string name string
runner string
build *BuildPipeline build *BuildPipeline
} }
@ -67,7 +66,7 @@ func (p BasePipeline) getInline() []string {
// the build host's filesystem is used as the build root. The runner specifies how to use this // the build host's filesystem is used as the build root. The runner specifies how to use this
// pipeline as a build pipeline, by naming the distro it contains. When the host system is used // pipeline as a build pipeline, by naming the distro it contains. When the host system is used
// as a build root, then the necessary runner is autodetected. // as a build root, then the necessary runner is autodetected.
func NewBasePipeline(m *Manifest, name string, build *BuildPipeline, runner *string) BasePipeline { func NewBasePipeline(m *Manifest, name string, build *BuildPipeline) BasePipeline {
p := BasePipeline{ p := BasePipeline{
manifest: m, manifest: m,
name: name, name: name,
@ -77,12 +76,6 @@ func NewBasePipeline(m *Manifest, name string, build *BuildPipeline, runner *str
if build.BasePipeline.manifest != m { if build.BasePipeline.manifest != m {
panic("build pipeline from a different manifest") panic("build pipeline from a different manifest")
} }
if build.BasePipeline.runner == "" {
panic("build pipeline does not have runner")
}
}
if runner != nil {
p.runner = *runner
} }
return p return p
} }
@ -101,13 +94,11 @@ func (p BasePipeline) serializeEnd() {
// meant to be treated as opaque and not to be modified further outside of the pipeline // meant to be treated as opaque and not to be modified further outside of the pipeline
// package. // package.
func (p BasePipeline) serialize() osbuild2.Pipeline { func (p BasePipeline) serialize() osbuild2.Pipeline {
var buildName string pipeline := osbuild2.Pipeline{
Name: p.name,
}
if p.build != nil { if p.build != nil {
buildName = "name:" + p.build.Name() pipeline.Build = "name:" + p.build.Name()
}
return osbuild2.Pipeline{
Name: p.name,
Runner: p.runner,
Build: buildName,
} }
return pipeline
} }

View file

@ -21,7 +21,7 @@ func NewQCOW2Pipeline(m *Manifest,
imgPipeline *LiveImgPipeline, imgPipeline *LiveImgPipeline,
filename string) *QCOW2Pipeline { filename string) *QCOW2Pipeline {
p := &QCOW2Pipeline{ p := &QCOW2Pipeline{
BasePipeline: NewBasePipeline(m, "qcow2", buildPipeline, nil), BasePipeline: NewBasePipeline(m, "qcow2", buildPipeline),
imgPipeline: imgPipeline, imgPipeline: imgPipeline,
filename: filename, filename: filename,
} }

View file

@ -20,7 +20,7 @@ func NewTarPipeline(m *Manifest,
pipelinename, pipelinename,
filename string) *TarPipeline { filename string) *TarPipeline {
p := &TarPipeline{ p := &TarPipeline{
BasePipeline: NewBasePipeline(m, pipelinename, buildPipeline, nil), BasePipeline: NewBasePipeline(m, pipelinename, buildPipeline),
inputPipeline: inputPipeline, inputPipeline: inputPipeline,
filename: filename, filename: filename,
} }

View file

@ -19,7 +19,7 @@ func NewVMDKPipeline(m *Manifest,
imgPipeline *LiveImgPipeline, imgPipeline *LiveImgPipeline,
filename string) *VMDKPipeline { filename string) *VMDKPipeline {
p := &VMDKPipeline{ p := &VMDKPipeline{
BasePipeline: NewBasePipeline(m, "vmdk", buildPipeline, nil), BasePipeline: NewBasePipeline(m, "vmdk", buildPipeline),
imgPipeline: imgPipeline, imgPipeline: imgPipeline,
filename: filename, filename: filename,
} }

View file

@ -20,7 +20,7 @@ func NewVPCPipeline(m *Manifest,
imgPipeline *LiveImgPipeline, imgPipeline *LiveImgPipeline,
filename string) *VPCPipeline { filename string) *VPCPipeline {
p := &VPCPipeline{ p := &VPCPipeline{
BasePipeline: NewBasePipeline(m, "vpc", buildPipeline, nil), BasePipeline: NewBasePipeline(m, "vpc", buildPipeline),
imgPipeline: imgPipeline, imgPipeline: imgPipeline,
filename: filename, filename: filename,
} }

18
internal/runner/fedora.go Normal file
View file

@ -0,0 +1,18 @@
package runner
import "fmt"
type Fedora struct {
Version uint64
}
func (r *Fedora) String() string {
return fmt.Sprintf("org.osbuild.fedora%d", r.Version)
}
func (p *Fedora) GetBuildPackages() []string {
return []string{
"glibc", // ldconfig
"systemd", // systemd-tmpfiles and systemd-sysusers
}
}

15
internal/runner/linux.go Normal file
View file

@ -0,0 +1,15 @@
package runner
type Linux struct {
}
func (r *Linux) String() string {
return "org.osbuild.linux"
}
func (p *Linux) GetBuildPackages() []string {
return []string{
"glibc", // ldconfig
"systemd", // systemd-tmpfiles and systemd-sysusers
}
}

24
internal/runner/rhel.go Normal file
View file

@ -0,0 +1,24 @@
package runner
import "fmt"
type RHEL struct {
Major uint64
Minor uint64
}
func (r *RHEL) String() string {
return fmt.Sprintf("org.osbuild.fedora%d%d", r.Major, r.Minor)
}
func (p *RHEL) GetBuildPackages() []string {
packages := []string{
"glibc", // ldconfig
}
if p.Major >= 8 {
packages = append(packages,
"systemd", // systemd-tmpfiles and systemd-sysusers
)
}
return packages
}

View file

@ -0,0 +1,6 @@
package runner
type Runner interface {
String() string
GetBuildPackages() []string
}