pipelines: add Fedora IoT commit and container pipelines

This commit is contained in:
Tom Gundersen 2022-06-25 22:25:54 +01:00
parent 1243f84cb0
commit 0f015801d7
5 changed files with 225 additions and 102 deletions

View file

@ -4,7 +4,6 @@ import (
"fmt"
"math/rand"
"path"
"path/filepath"
"github.com/osbuild/osbuild-composer/internal/blueprint"
"github.com/osbuild/osbuild-composer/internal/disk"
@ -44,17 +43,6 @@ func qcow2Pipelines(t *imageType, customizations *blueprint.Customizations, opti
return pipelines, nil
}
func prependKernelCmdlineStage(pipeline *osbuild.Pipeline, kernelOptions string, pt *disk.PartitionTable) *osbuild.Pipeline {
rootFs := pt.FindMountable("/")
if rootFs == nil {
panic("root filesystem must be defined for kernel-cmdline stage, this is a programming error")
}
rootFsUUID := rootFs.GetFSSpec().UUID
kernelStage := osbuild.NewKernelCmdlineStage(osbuild.NewKernelCmdlineStageOptions(rootFsUUID, kernelOptions))
pipeline.Stages = append([]*osbuild.Stage{kernelStage}, pipeline.Stages...)
return pipeline
}
func vhdPipelines(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, rng *rand.Rand) ([]osbuild.Pipeline, error) {
pipelines := make([]osbuild.Pipeline, 0)
@ -210,50 +198,46 @@ func iotInstallerPipelines(t *imageType, customizations *blueprint.Customization
return pipelines, nil
}
func iotCorePipelines(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec) ([]osbuild.Pipeline, error) {
pipelines := make([]osbuild.Pipeline, 0)
func iotCorePipelines(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec) (*pipeline.BuildPipeline, *pipeline.OSPipeline, *pipeline.OSTreeCommitPipeline, error) {
buildPipeline := pipeline.NewBuildPipeline(t.arch.distro.runner)
buildPipeline.Repos = repos
buildPipeline.PackageSpecs = packageSetSpecs[buildPkgsKey]
pipelines = append(pipelines, buildPipeline.Serialize())
treePipeline, err := osPipeline(&buildPipeline, t, repos, packageSetSpecs[osPkgsKey], customizations, options, nil)
if err != nil {
return nil, err
return nil, nil, nil, err
}
commitPipeline := ostreeCommitPipeline(&buildPipeline, &treePipeline, options, t.arch.distro.osVersion)
pipelines = append(pipelines, treePipeline.Serialize())
pipelines = append(pipelines, *ostreeCommitPipeline(options, t.arch.distro.osVersion))
return pipelines, nil
return &buildPipeline, &treePipeline, &commitPipeline, nil
}
func iotCommitPipelines(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, rng *rand.Rand) ([]osbuild.Pipeline, error) {
pipelines, err := iotCorePipelines(t, customizations, options, repos, packageSetSpecs)
pipelines := make([]osbuild.Pipeline, 0)
buildPipeline, treePipeline, commitPipeline, err := iotCorePipelines(t, customizations, options, repos, packageSetSpecs)
if err != nil {
return nil, err
}
tarPipeline := osbuild.Pipeline{
Name: "commit-archive",
Build: "name:build",
}
tarPipeline.AddStage(tarStage("ostree-commit", t.Filename()))
pipelines = append(pipelines, tarPipeline)
tarPipeline := pipeline.NewTarPipeline(buildPipeline, &commitPipeline.Pipeline, "commit-archive")
tarPipeline.Filename = t.Filename()
pipelines = append(pipelines, buildPipeline.Serialize(), treePipeline.Serialize(), commitPipeline.Serialize(), tarPipeline.Serialize())
return pipelines, nil
}
func iotContainerPipelines(t *imageType, customizations *blueprint.Customizations, options distro.ImageOptions, repos []rpmmd.RepoConfig, packageSetSpecs map[string][]rpmmd.PackageSpec, rng *rand.Rand) ([]osbuild.Pipeline, error) {
pipelines, err := iotCorePipelines(t, customizations, options, repos, packageSetSpecs)
pipelines := make([]osbuild.Pipeline, 0)
buildPipeline, treePipeline, commitPipeline, err := iotCorePipelines(t, customizations, options, repos, packageSetSpecs)
if err != nil {
return nil, err
}
nginxConfigPath := "/etc/nginx.conf"
httpPort := "8080"
pipelines = append(pipelines, *containerTreePipeline(repos, packageSetSpecs[containerPkgsKey], options, customizations, nginxConfigPath, httpPort))
pipelines = append(pipelines, *containerPipeline(t, nginxConfigPath, httpPort))
containerTreePipeline := containerTreePipeline(buildPipeline, commitPipeline, repos, packageSetSpecs[containerPkgsKey], options, customizations, nginxConfigPath, httpPort)
containerPipeline := containerPipeline(buildPipeline, &containerTreePipeline.Pipeline, t, nginxConfigPath, httpPort)
pipelines = append(pipelines, buildPipeline.Serialize(), treePipeline.Serialize(), commitPipeline.Serialize(), containerTreePipeline.Serialize(), containerPipeline.Serialize())
return pipelines, nil
}
@ -370,84 +354,33 @@ func osPipeline(buildPipeline *pipeline.BuildPipeline,
return pl, nil
}
func ostreeCommitPipeline(options distro.ImageOptions, osVersion string) *osbuild.Pipeline {
p := new(osbuild.Pipeline)
p.Name = "ostree-commit"
p.Build = "name:build"
p.AddStage(osbuild.NewOSTreeInitStage(&osbuild.OSTreeInitStageOptions{Path: "/repo"}))
commitStageInput := new(osbuild.OSTreeCommitStageInput)
commitStageInput.Type = "org.osbuild.tree"
commitStageInput.Origin = "org.osbuild.pipeline"
commitStageInput.References = osbuild.OSTreeCommitStageReferences{"name:ostree-tree"}
p.AddStage(osbuild.NewOSTreeCommitStage(
&osbuild.OSTreeCommitStageOptions{
Ref: options.OSTree.Ref,
OSVersion: osVersion,
Parent: options.OSTree.Parent,
},
&osbuild.OSTreeCommitStageInputs{Tree: commitStageInput}),
)
func ostreeCommitPipeline(buildPipeline *pipeline.BuildPipeline, treePipeline *pipeline.OSPipeline, options distro.ImageOptions, osVersion string) pipeline.OSTreeCommitPipeline {
p := pipeline.NewOSTreeCommitPipeline(buildPipeline, treePipeline)
p.Ref = options.OSTree.Ref
p.OSVersion = osVersion
p.Parent = options.OSTree.Parent
return p
}
func tarStage(source, filename string) *osbuild.Stage {
tree := new(osbuild.TarStageInput)
tree.Type = "org.osbuild.tree"
tree.Origin = "org.osbuild.pipeline"
tree.References = []string{"name:" + source}
return osbuild.NewTarStage(&osbuild.TarStageOptions{Filename: filename}, &osbuild.TarStageInputs{Tree: tree})
}
func containerTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, options distro.ImageOptions, c *blueprint.Customizations, nginxConfigPath, listenPort string) *osbuild.Pipeline {
p := new(osbuild.Pipeline)
p.Name = "container-tree"
p.Build = "name:build"
p.AddStage(osbuild.NewRPMStage(osbuild.NewRPMStageOptions(repos), osbuild.NewRpmStageSourceFilesInputs(packages)))
func containerTreePipeline(buildPipeline *pipeline.BuildPipeline, commitPipeline *pipeline.OSTreeCommitPipeline, repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec, options distro.ImageOptions, c *blueprint.Customizations, nginxConfigPath, listenPort string) pipeline.OSTreeCommitServerTreePipeline {
p := pipeline.NewOSTreeCommitServerTreePipeline(buildPipeline, commitPipeline)
p.Repos = repos
p.PackageSpecs = packages
p.NginxConfigPath = nginxConfigPath
p.ListenPort = listenPort
language, _ := c.GetPrimaryLocale()
if language != nil {
p.AddStage(osbuild.NewLocaleStage(&osbuild.LocaleStageOptions{Language: *language}))
} else {
p.AddStage(osbuild.NewLocaleStage(&osbuild.LocaleStageOptions{Language: "en_US"}))
p.Language = *language
}
htmlRoot := "/usr/share/nginx/html"
repoPath := filepath.Join(htmlRoot, "repo")
p.AddStage(osbuild.NewOSTreeInitStage(&osbuild.OSTreeInitStageOptions{Path: repoPath}))
p.AddStage(osbuild.NewOSTreePullStage(
&osbuild.OSTreePullStageOptions{Repo: repoPath},
osbuild.NewOstreePullStageInputs("org.osbuild.pipeline", "name:ostree-commit", options.OSTree.Ref),
))
// make nginx log and lib directories world writeable, otherwise nginx can't start in
// an unprivileged container
p.AddStage(osbuild.NewChmodStage(chmodStageOptions("/var/log/nginx", "a+rwX", true)))
p.AddStage(osbuild.NewChmodStage(chmodStageOptions("/var/lib/nginx", "a+rwX", true)))
p.AddStage(osbuild.NewNginxConfigStage(nginxConfigStageOptions(nginxConfigPath, htmlRoot, listenPort)))
return p
}
func containerPipeline(t *imageType, nginxConfigPath, listenPort string) *osbuild.Pipeline {
p := new(osbuild.Pipeline)
p.Name = "container"
p.Build = "name:build"
options := &osbuild.OCIArchiveStageOptions{
Architecture: t.Arch().Name(),
Filename: t.Filename(),
Config: &osbuild.OCIArchiveConfig{
Cmd: []string{"nginx", "-c", nginxConfigPath},
ExposedPorts: []string{listenPort},
},
}
baseInput := new(osbuild.OCIArchiveStageInput)
baseInput.Type = "org.osbuild.tree"
baseInput.Origin = "org.osbuild.pipeline"
baseInput.References = []string{"name:container-tree"}
inputs := &osbuild.OCIArchiveStageInputs{Base: baseInput}
p.AddStage(osbuild.NewOCIArchiveStage(options, inputs))
func containerPipeline(buildPipeline *pipeline.BuildPipeline, treePipeline *pipeline.Pipeline, t *imageType, nginxConfigPath, listenPort string) pipeline.OCIContainerPipeline {
p := pipeline.NewOCIContainerPipeline(buildPipeline, treePipeline)
p.Architecture = t.Arch().Name()
p.Filename = t.Filename()
p.Cmd = []string{"nginx", "-c", nginxConfigPath}
p.ExposedPorts = []string{listenPort}
return p
}

View file

@ -0,0 +1,42 @@
package pipeline
import (
"github.com/osbuild/osbuild-composer/internal/osbuild2"
)
type OSTreeCommitPipeline struct {
Pipeline
treePipeline *OSPipeline
Ref string
OSVersion string
Parent string
}
func NewOSTreeCommitPipeline(buildPipeline *BuildPipeline, treePipeline *OSPipeline) OSTreeCommitPipeline {
return OSTreeCommitPipeline{
Pipeline: New("ostree-commit", &buildPipeline.Pipeline),
treePipeline: treePipeline,
}
}
func (p OSTreeCommitPipeline) Serialize() osbuild2.Pipeline {
pipeline := p.Pipeline.Serialize()
pipeline.AddStage(osbuild2.NewOSTreeInitStage(&osbuild2.OSTreeInitStageOptions{Path: "/repo"}))
commitStageInput := new(osbuild2.OSTreeCommitStageInput)
commitStageInput.Type = "org.osbuild.tree"
commitStageInput.Origin = "org.osbuild.pipeline"
commitStageInput.References = osbuild2.OSTreeCommitStageReferences{"name:" + p.treePipeline.Name()}
pipeline.AddStage(osbuild2.NewOSTreeCommitStage(
&osbuild2.OSTreeCommitStageOptions{
Ref: p.Ref,
OSVersion: p.OSVersion,
Parent: p.Parent,
},
&osbuild2.OSTreeCommitStageInputs{Tree: commitStageInput}),
)
return pipeline
}

View file

@ -0,0 +1,74 @@
package pipeline
import (
"path/filepath"
"github.com/osbuild/osbuild-composer/internal/common"
"github.com/osbuild/osbuild-composer/internal/osbuild2"
"github.com/osbuild/osbuild-composer/internal/rpmmd"
)
type OSTreeCommitServerTreePipeline struct {
Pipeline
commitPipeline *OSTreeCommitPipeline
Repos []rpmmd.RepoConfig
PackageSpecs []rpmmd.PackageSpec
Language string
NginxConfigPath string
ListenPort string
}
func NewOSTreeCommitServerTreePipeline(buildPipeline *BuildPipeline, commitPipeline *OSTreeCommitPipeline) OSTreeCommitServerTreePipeline {
return OSTreeCommitServerTreePipeline{
Pipeline: New("container-tree", &buildPipeline.Pipeline),
commitPipeline: commitPipeline,
Language: "en_US",
}
}
func (p OSTreeCommitServerTreePipeline) Serialize() osbuild2.Pipeline {
pipeline := p.Pipeline.Serialize()
pipeline.AddStage(osbuild2.NewRPMStage(osbuild2.NewRPMStageOptions(p.Repos), osbuild2.NewRpmStageSourceFilesInputs(p.PackageSpecs)))
pipeline.AddStage(osbuild2.NewLocaleStage(&osbuild2.LocaleStageOptions{Language: p.Language}))
htmlRoot := "/usr/share/nginx/html"
repoPath := filepath.Join(htmlRoot, "repo")
pipeline.AddStage(osbuild2.NewOSTreeInitStage(&osbuild2.OSTreeInitStageOptions{Path: repoPath}))
pipeline.AddStage(osbuild2.NewOSTreePullStage(
&osbuild2.OSTreePullStageOptions{Repo: repoPath},
osbuild2.NewOstreePullStageInputs("org.osbuild.pipeline", "name:"+p.commitPipeline.Name(), p.commitPipeline.Ref),
))
// make nginx log and lib directories world writeable, otherwise nginx can't start in
// an unprivileged container
pipeline.AddStage(osbuild2.NewChmodStage(chmodStageOptions("/var/log/nginx", "a+rwX", true)))
pipeline.AddStage(osbuild2.NewChmodStage(chmodStageOptions("/var/lib/nginx", "a+rwX", true)))
pipeline.AddStage(osbuild2.NewNginxConfigStage(nginxConfigStageOptions(p.NginxConfigPath, htmlRoot, p.ListenPort)))
return pipeline
}
func nginxConfigStageOptions(path, htmlRoot, listen string) *osbuild2.NginxConfigStageOptions {
// configure nginx to work in an unprivileged container
cfg := &osbuild2.NginxConfig{
Listen: listen,
Root: htmlRoot,
Daemon: common.BoolToPtr(false),
PID: "/tmp/nginx.pid",
}
return &osbuild2.NginxConfigStageOptions{
Path: path,
Config: cfg,
}
}
func chmodStageOptions(path, mode string, recursive bool) *osbuild2.ChmodStageOptions {
return &osbuild2.ChmodStageOptions{
Items: map[string]osbuild2.ChmodStagePathOptions{
path: {Mode: mode, Recursive: recursive},
},
}
}

View file

@ -0,0 +1,42 @@
package pipeline
import (
"github.com/osbuild/osbuild-composer/internal/osbuild2"
)
type OCIContainerPipeline struct {
Pipeline
treePipeline *Pipeline
Architecture string
Filename string
Cmd []string
ExposedPorts []string
}
func NewOCIContainerPipeline(buildPipeline *BuildPipeline, treePipeline *Pipeline) OCIContainerPipeline {
return OCIContainerPipeline{
Pipeline: New("container", &buildPipeline.Pipeline),
treePipeline: treePipeline,
}
}
func (p OCIContainerPipeline) Serialize() osbuild2.Pipeline {
pipeline := p.Pipeline.Serialize()
options := &osbuild2.OCIArchiveStageOptions{
Architecture: p.Architecture,
Filename: p.Filename,
Config: &osbuild2.OCIArchiveConfig{
Cmd: p.Cmd,
ExposedPorts: p.ExposedPorts,
},
}
baseInput := new(osbuild2.OCIArchiveStageInput)
baseInput.Type = "org.osbuild.tree"
baseInput.Origin = "org.osbuild.pipeline"
baseInput.References = []string{"name:" + p.treePipeline.Name()}
inputs := &osbuild2.OCIArchiveStageInputs{Base: baseInput}
pipeline.AddStage(osbuild2.NewOCIArchiveStage(options, inputs))
return pipeline
}

View file

@ -0,0 +1,32 @@
package pipeline
import (
"github.com/osbuild/osbuild-composer/internal/osbuild2"
)
type TarPipeline struct {
Pipeline
inputPipeline *Pipeline
Filename string
}
func NewTarPipeline(buildPipeline *BuildPipeline, inputPipeline *Pipeline, name string) TarPipeline {
return TarPipeline{
Pipeline: New(name, &buildPipeline.Pipeline),
inputPipeline: inputPipeline,
}
}
func (p TarPipeline) Serialize() osbuild2.Pipeline {
pipeline := p.Pipeline.Serialize()
tree := new(osbuild2.TarStageInput)
tree.Type = "org.osbuild.tree"
tree.Origin = "org.osbuild.pipeline"
tree.References = []string{"name:" + p.inputPipeline.Name()}
tarStage := osbuild2.NewTarStage(&osbuild2.TarStageOptions{Filename: p.Filename}, &osbuild2.TarStageInputs{Tree: tree})
pipeline.AddStage(tarStage)
return pipeline
}