Repository: osbuild/osbuild-composer
Pull request #121 (2019-11-26 16:24:49)

Make images boot on AWS


Patch:
diff --git a/internal/blueprint/blueprint.go b/internal/blueprint/blueprint.go
index a7f9a0477..b7edfe074 100644
--- a/internal/blueprint/blueprint.go
+++ b/internal/blueprint/blueprint.go
@@ -49,6 +49,22 @@ func (b *Blueprint) GetKernelCustomization() *KernelCustomization {
 	return b.Customizations.Kernel
 }
 
+func (b *Blueprint) GetFirewallCustomization() *FirewallCustomization {
+	if b.Customizations == nil {
+		return nil
+	}
+
+	return b.Customizations.Firewall
+}
+
+func (b *Blueprint) GetServicesCustomization() *ServicesCustomization {
+	if b.Customizations == nil {
+		return nil
+	}
+
+	return b.Customizations.Services
+}
+
 func (p Package) ToNameVersion() string {
 	// Omit version to prevent all packages with prefix of name to be installed
 	if p.Version == "*" {
diff --git a/internal/distro/fedora30/ami.go b/internal/distro/fedora30/ami.go
index 1dd34a45d..ed17f4c45 100644
--- a/internal/distro/fedora30/ami.go
+++ b/internal/distro/fedora30/ami.go
@@ -24,20 +24,17 @@ func (t *amiOutput) translate(b *blueprint.Blueprint) (*pipeline.Pipeline, error
 	excludedPackages := [...]string{
 		"dracut-config-rescue",
 	}
-	p := getCustomF30PackageSet(packages[:], excludedPackages[:], b)
-	addF30FixBlsStage(p)
-	addF30LocaleStage(p)
-	addF30FSTabStage(p)
-	addF30GRUB2Stage(p, nil)
-	addF30SELinuxStage(p)
-	addF30QemuAssembler(p, "raw", t.getName())
-
-	if b.Customizations != nil {
-		err := customizeAll(p, b.Customizations)
-		if err != nil {
-			return nil, err
-		}
+	p := newF30Pipeline(packages[:], excludedPackages[:], b)
+	err := customizeAll(p, b.Customizations)
+	if err != nil {
+		return nil, err
 	}
+	setFilesystems(p)
+	setBootloader(p, "ro no_timer_check console=ttyS0,115200n8 console=tty1 biosdevname=0 net.ifnames=0 console=ttyS0,115200", b)
+	setFirewall(p, nil, nil, b)
+	setServices(p, []string{"cloud-init.service"}, nil, b)
+	setQemuAssembler(p, "raw", t.getName())
+
 	return p, nil
 }
 
diff --git a/internal/distro/fedora30/customizations.go b/internal/distro/fedora30/customizations.go
index 7d0277d55..e2362e3dd 100644
--- a/internal/distro/fedora30/customizations.go
+++ b/internal/distro/fedora30/customizations.go
@@ -1,15 +1,19 @@
 package fedora30
 
 import (
-	"github.com/osbuild/osbuild-composer/internal/blueprint"
-	"github.com/osbuild/osbuild-composer/internal/crypt"
-	"github.com/osbuild/osbuild-composer/internal/pipeline"
 	"log"
 	"strconv"
 	"strings"
+
+	"github.com/osbuild/osbuild-composer/internal/blueprint"
+	"github.com/osbuild/osbuild-composer/internal/crypt"
+	"github.com/osbuild/osbuild-composer/internal/pipeline"
 )
 
 func customizeAll(p *pipeline.Pipeline, c *blueprint.Customizations) error {
+	if c == nil {
+		c = &blueprint.Customizations{}
+	}
 	customizeHostname(p, c)
 	customizeGroup(p, c)
 	if err := customizeUserAndSSHKey(p, c); err != nil {
@@ -17,10 +21,8 @@ func customizeAll(p *pipeline.Pipeline, c *blueprint.Customizations) error {
 	}
 	customizeTimezone(p, c)
 	customizeNTPServers(p, c)
-	customizeLanguages(p, c)
+	customizeLocale(p, c)
 	customizeKeyboard(p, c)
-	customizeFirewall(p, c)
-	customizeServices(p, c)
 
 	return nil
 }
@@ -177,9 +179,14 @@ func customizeNTPServers(p *pipeline.Pipeline, c *blueprint.Customizations) {
 	)
 }
 
-func customizeLanguages(p *pipeline.Pipeline, c *blueprint.Customizations) {
-	if c.Locale == nil || len(c.Locale.Languages) == 0 {
-		return
+func customizeLocale(p *pipeline.Pipeline, c *blueprint.Customizations) {
+	locale := c.Locale
+	if locale == nil {
+		locale = &blueprint.LocaleCustomization{
+			Languages: []string{
+				"en_US",
+			},
+		}
 	}
 
 	// TODO: you can specify more languages in customization
@@ -190,7 +197,7 @@ func customizeLanguages(p *pipeline.Pipeline, c *blueprint.Customizations) {
 
 	p.AddStage(
 		pipeline.NewLocaleStage(&pipeline.LocaleStageOptions{
-			Language: c.Locale.Languages[0],
+			Language: locale.Languages[0],
 		}),
 	)
 }
@@ -207,40 +214,6 @@ func customizeKeyboard(p *pipeline.Pipeline, c *blueprint.Customizations) {
 	)
 }
 
-func customizeFirewall(p *pipeline.Pipeline, c *blueprint.Customizations) {
-	if c.Firewall == nil {
-		return
-	}
-
-	var enabledServices, disabledServices []string
-
-	if c.Firewall.Services != nil {
-		enabledServices = c.Firewall.Services.Enabled
-		disabledServices = c.Firewall.Services.Disabled
-	}
-
-	p.AddStage(
-		pipeline.NewFirewallStage(&pipeline.FirewallStageOptions{
-			Ports:            c.Firewall.Ports,
-			EnabledServices:  enabledServices,
-			DisabledServices: disabledServices,
-		}),
-	)
-}
-
-func customizeServices(p *pipeline.Pipeline, c *blueprint.Customizations) {
-	if c.Services == nil {
-		return
-	}
-
-	p.AddStage(
-		pipeline.NewSystemdStage(&pipeline.SystemdStageOptions{
-			EnabledServices:  c.Services.Enabled,
-			DisabledServices: c.Services.Disabled,
-		}),
-	)
-}
-
 func findKeysForUser(sshKeyCustomizations []blueprint.SSHKeyCustomization, user string) (keys []string) {
 	for _, sshKey := range sshKeyCustomizations {
 		if sshKey.User == user {
diff --git a/internal/distro/fedora30/disk.go b/internal/distro/fedora30/disk.go
index d3a87bc84..617f77f72 100644
--- a/internal/distro/fedora30/disk.go
+++ b/internal/distro/fedora30/disk.go
@@ -20,20 +20,17 @@ func (t *diskOutput) translate(b *blueprint.Blueprint) (*pipeline.Pipeline, erro
 	excludedPackages := [...]string{
 		"dracut-config-rescue",
 	}
-	p := getCustomF30PackageSet(packages[:], excludedPackages[:], b)
-	addF30LocaleStage(p)
-	addF30FSTabStage(p)
-	addF30GRUB2Stage(p, b.GetKernelCustomization())
-	addF30FixBlsStage(p)
-	addF30SELinuxStage(p)
-	addF30QemuAssembler(p, "raw", t.getName())
-
-	if b.Customizations != nil {
-		err := customizeAll(p, b.Customizations)
-		if err != nil {
-			return nil, err
-		}
+	p := newF30Pipeline(packages[:], excludedPackages[:], b)
+	err := customizeAll(p, b.Customizations)
+	if err != nil {
+		return nil, err
 	}
+	setFilesystems(p)
+	setBootloader(p, "ro biosdevname=0 net.ifnames=0", b)
+	setFirewall(p, nil, nil, b)
+	setServices(p, nil, nil, b)
+	setQemuAssembler(p, "raw", t.getName())
+
 	return p, nil
 }
 
diff --git a/internal/distro/fedora30/ext4.go b/internal/distro/fedora30/ext4.go
index b9e728d14..ffa381e64 100644
--- a/internal/distro/fedora30/ext4.go
+++ b/internal/distro/fedora30/ext4.go
@@ -19,19 +19,16 @@ func (t *ext4Output) translate(b *blueprint.Blueprint) (*pipeline.Pipeline, erro
 	excludedPackages := [...]string{
 		"dracut-config-rescue",
 	}
-	p := getCustomF30PackageSet(packages[:], excludedPackages[:], b)
-	addF30LocaleStage(p)
-	addF30GRUB2Stage(p, b.GetKernelCustomization())
-	addF30FixBlsStage(p)
-	addF30SELinuxStage(p)
-	addF30RawFSAssembler(p, t.getName())
-
-	if b.Customizations != nil {
-		err := customizeAll(p, b.Customizations)
-		if err != nil {
-			return nil, err
-		}
+	p := newF30Pipeline(packages[:], excludedPackages[:], b)
+	err := customizeAll(p, b.Customizations)
+	if err != nil {
+		return nil, err
 	}
+	setBootloader(p, "ro biosdevname=0 net.ifnames=0", b)
+	setFirewall(p, nil, nil, b)
+	setServices(p, nil, nil, b)
+	setRawFSAssembler(p, t.getName())
+
 	return p, nil
 }
 
diff --git a/internal/distro/fedora30/helpers.go b/internal/distro/fedora30/helpers.go
index aec371174..49b0a2479 100644
--- a/internal/distro/fedora30/helpers.go
+++ b/internal/distro/fedora30/helpers.go
@@ -62,35 +62,7 @@ func getF30BuildPipeline() *pipeline.Pipeline {
 	return p
 }
 
-func getF30Pipeline() *pipeline.Pipeline {
-	p := &pipeline.Pipeline{
-		BuildPipeline: getF30BuildPipeline(),
-	}
-	options := &pipeline.DNFStageOptions{
-		ReleaseVersion:   "30",
-		BaseArchitecture: "x86_64",
-	}
-	options.AddRepository(getF30Repository())
-	options.AddPackage("@Core")
-	options.AddPackage("chrony")
-	options.AddPackage("kernel")
-	options.AddPackage("selinux-policy-targeted")
-	options.AddPackage("grub2-pc")
-	options.AddPackage("spice-vdagent")
-	options.AddPackage("qemu-guest-agent")
-	options.AddPackage("xen-libs")
-	options.AddPackage("langpacks-en")
-	p.AddStage(pipeline.NewDNFStage(options))
-	p.AddStage(pipeline.NewFixBLSStage())
-	p.AddStage(pipeline.NewLocaleStage(
-		&pipeline.LocaleStageOptions{
-			Language: "en_US",
-		}))
-
-	return p
-}
-
-func getCustomF30PackageSet(packages []string, excludedPackages []string, blueprint *blueprint.Blueprint) *pipeline.Pipeline {
+func newF30Pipeline(packages []string, excludedPackages []string, blueprint *blueprint.Blueprint) *pipeline.Pipeline {
 	p := &pipeline.Pipeline{
 		BuildPipeline: getF30BuildPipeline(),
 	}
@@ -106,7 +78,6 @@ func getCustomF30PackageSet(packages []string, excludedPackages []string, bluepr
 		options.ExcludePackage(pkg)
 	}
 
-	// handle extra packages, modules (currently synonym to packages) and groups
 	for _, pkg := range blueprint.Packages {
 		options.AddPackage(pkg.ToNameVersion())
 	}
@@ -120,16 +91,20 @@ func getCustomF30PackageSet(packages []string, excludedPackages []string, bluepr
 	}
 
 	p.AddStage(pipeline.NewDNFStage(options))
+
+	/* grub2 mangles the BLS snippets, we must fix them manually */
+	p.AddStage(pipeline.NewFixBLSStage())
+
 	return p
 }
 
-func addF30GRUB2Stage(p *pipeline.Pipeline, kernelCustomization *blueprint.KernelCustomization) {
+func setBootloader(p *pipeline.Pipeline, kernelOptions string, blueprint *blueprint.Blueprint) {
 	id, err := uuid.Parse("76a22bf4-f153-4541-b6c7-0332c0dfaeac")
 	if err != nil {
 		panic("invalid UUID")
 	}
-	kernelOptions := "ro biosdevname=0 net.ifnames=0"
 
+	kernelCustomization := blueprint.GetKernelCustomization()
 	if kernelCustomization != nil {
 		kernelOptions += " " + kernelCustomization.Append
 	}
@@ -142,7 +117,7 @@ func addF30GRUB2Stage(p *pipeline.Pipeline, kernelCustomization *blueprint.Kerne
 	))
 }
 
-func addF30FSTabStage(p *pipeline.Pipeline) {
+func setFilesystems(p *pipeline.Pipeline) {
 	id, err := uuid.Parse("76a22bf4-f153-4541-b6c7-0332c0dfaeac")
 	if err != nil {
 		panic("invalid UUID")
@@ -152,25 +127,56 @@ func addF30FSTabStage(p *pipeline.Pipeline) {
 	p.AddStage(pipeline.NewFSTabStage(options))
 }
 
-func addF30SELinuxStage(p *pipeline.Pipeline) {
-	p.AddStage(pipeline.NewSELinuxStage(
-		&pipeline.SELinuxStageOptions{
-			FileContexts: "etc/selinux/targeted/contexts/files/file_contexts",
-		}))
-}
+func setFirewall(p *pipeline.Pipeline, enabledServices []string, disabledServices []string, b *blueprint.Blueprint) {
+	f := b.GetFirewallCustomization()
+	ports := []string{}
 
-func addF30LocaleStage(p *pipeline.Pipeline) {
-	p.AddStage(pipeline.NewLocaleStage(
-		&pipeline.LocaleStageOptions{
-			Language: "en_US",
-		}))
+	if f != nil {
+		if f.Services != nil {
+			enabledServices = append(enabledServices, f.Services.Enabled...)
+			disabledServices = append(disabledServices, f.Services.Disabled...)
+		}
+		ports = f.Ports
+	}
+
+	if len(enabledServices) == 0 && len(disabledServices) == 0 && len(ports) == 0 {
+		return
+	}
+
+	p.AddStage(
+		pipeline.NewFirewallStage(&pipeline.FirewallStageOptions{
+			Ports:            ports,
+			EnabledServices:  enabledServices,
+			DisabledServices: disabledServices,
+		}),
+	)
 }
 
-func addF30FixBlsStage(p *pipeline.Pipeline) {
-	p.AddStage(pipeline.NewFixBLSStage())
+func setServices(p *pipeline.Pipeline, enabledServices []string, disabledServices []string, b *blueprint.Blueprint) {
+	s := b.GetServicesCustomization()
+
+	if s != nil {
+		enabledServices = append(enabledServices, s.Enabled...)
+		disabledServices = append(disabledServices, s.Enabled...)
+	}
+
+	if len(enabledServices) == 0 && len(disabledServices) == 0 {
+		return
+	}
+
+	p.AddStage(
+		pipeline.NewSystemdStage(&pipeline.SystemdStageOptions{
+			EnabledServices:  enabledServices,
+			DisabledServices: disabledServices,
+		}),
+	)
 }
 
-func addF30QemuAssembler(p *pipeline.Pipeline, format string, filename string) {
+func setQemuAssembler(p *pipeline.Pipeline, format string, filename string) {
+	p.AddStage(pipeline.NewSELinuxStage(
+		&pipeline.SELinuxStageOptions{
+			FileContexts: "etc/selinux/targeted/contexts/files/file_contexts",
+		}))
 	id, err := uuid.Parse("76a22bf4-f153-4541-b6c7-0332c0dfaeac")
 	if err != nil {
 		panic("invalid UUID")
@@ -187,14 +193,22 @@ func addF30QemuAssembler(p *pipeline.Pipeline, format string, filename string) {
 		})
 }
 
-func addF30TarAssembler(p *pipeline.Pipeline, filename, compression string) {
+func setTarAssembler(p *pipeline.Pipeline, filename, compression string) {
+	p.AddStage(pipeline.NewSELinuxStage(
+		&pipeline.SELinuxStageOptions{
+			FileContexts: "etc/selinux/targeted/contexts/files/file_contexts",
+		}))
 	p.Assembler = pipeline.NewTarAssembler(
 		&pipeline.TarAssemblerOptions{
 			Filename: filename,
 		})
 }
 
-func addF30RawFSAssembler(p *pipeline.Pipeline, filename string) {
+func setRawFSAssembler(p *pipeline.Pipeline, filename string) {
+	p.AddStage(pipeline.NewSELinuxStage(
+		&pipeline.SELinuxStageOptions{
+			FileContexts: "etc/selinux/targeted/contexts/files/file_contexts",
+		}))
 	id, err := uuid.Parse("76a22bf4-f153-4541-b6c7-0332c0dfaeac")
 	if err != nil {
 		panic("invalid UUID")
diff --git a/internal/distro/fedora30/liveiso.go b/internal/distro/fedora30/liveiso.go
deleted file mode 100644
index b4ac01c4b..000000000
--- a/internal/distro/fedora30/liveiso.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package fedora30
-
-import (
-	"github.com/osbuild/osbuild-composer/internal/blueprint"
-	"github.com/osbuild/osbuild-composer/internal/pipeline"
-)
-
-type liveIsoOutput struct{}
-
-func (t *liveIsoOutput) translate(b *blueprint.Blueprint) (*pipeline.Pipeline, error) {
-	// TODO!
-	p := getF30Pipeline()
-	addF30SELinuxStage(p)
-	addF30QemuAssembler(p, "raw", t.getName())
-
-	if b.Customizations != nil {
-		err := customizeAll(p, b.Customizations)
-		if err != nil {
-			return nil, err
-		}
-	}
-	return p, nil
-}
-
-func (t *liveIsoOutput) getName() string {
-	return "image.iso"
-}
-
-func (t *liveIsoOutput) getMime() string {
-	return "application/x-iso9660-image"
-}
diff --git a/internal/distro/fedora30/openstack.go b/internal/distro/fedora30/openstack.go
index 876503817..1b56e469f 100644
--- a/internal/distro/fedora30/openstack.go
+++ b/internal/distro/fedora30/openstack.go
@@ -24,20 +24,17 @@ func (t *openstackOutput) translate(b *blueprint.Blueprint) (*pipeline.Pipeline,
 	excludedPackages := [...]string{
 		"dracut-config-rescue",
 	}
-	p := getCustomF30PackageSet(packages[:], excludedPackages[:], b)
-	addF30LocaleStage(p)
-	addF30FSTabStage(p)
-	addF30GRUB2Stage(p, b.GetKernelCustomization())
-	addF30FixBlsStage(p)
-	addF30SELinuxStage(p)
-	addF30QemuAssembler(p, "qcow2", t.getName())
-
-	if b.Customizations != nil {
-		err := customizeAll(p, b.Customizations)
-		if err != nil {
-			return nil, err
-		}
+	p := newF30Pipeline(packages[:], excludedPackages[:], b)
+	err := customizeAll(p, b.Customizations)
+	if err != nil {
+		return nil, err
 	}
+	setFilesystems(p)
+	setBootloader(p, "ro biosdevname=0 net.ifnames=0", b)
+	setFirewall(p, nil, nil, b)
+	setServices(p, nil, nil, b)
+	setQemuAssembler(p, "qcow2", t.getName())
+
 	return p, nil
 }
 
diff --git a/internal/distro/fedora30/os.go b/internal/distro/fedora30/os.go
index 949da07b2..5bc504659 100644
--- a/internal/distro/fedora30/os.go
+++ b/internal/distro/fedora30/os.go
@@ -24,7 +24,6 @@ func init() {
 		outputs: map[string]output{
 			"ami":              &amiOutput{},
 			"ext4-filesystem":  &ext4Output{},
-			"live-iso":         &liveIsoOutput{},
 			"partitioned-disk": &diskOutput{},
 			"qcow2":            &qcow2Output{},
 			"openstack":        &openstackOutput{},
diff --git a/internal/distro/fedora30/qcow2.go b/internal/distro/fedora30/qcow2.go
index 0aacf8409..2d3f83fce 100644
--- a/internal/distro/fedora30/qcow2.go
+++ b/internal/distro/fedora30/qcow2.go
@@ -25,20 +25,17 @@ func (t *qcow2Output) translate(b *blueprint.Blueprint) (*pipeline.Pipeline, err
 		"gobject-introspection",
 		"plymouth",
 	}
-	p := getCustomF30PackageSet(packages[:], excludedPackages[:], b)
-	addF30LocaleStage(p)
-	addF30FSTabStage(p)
-	addF30GRUB2Stage(p, b.GetKernelCustomization())
-	addF30FixBlsStage(p)
-	addF30SELinuxStage(p)
-	addF30QemuAssembler(p, "qcow2", t.getName())
-
-	if b.Customizations != nil {
-		err := customizeAll(p, b.Customizations)
-		if err != nil {
-			return nil, err
-		}
+	p := newF30Pipeline(packages[:], excludedPackages[:], b)
+	err := customizeAll(p, b.Customizations)
+	if err != nil {
+		return nil, err
 	}
+	setFilesystems(p)
+	setBootloader(p, "ro biosdevname=0 net.ifnames=0", b)
+	setFirewall(p, nil, nil, b)
+	setServices(p, nil, nil, b)
+	setQemuAssembler(p, "qcow2", t.getName())
+
 	return p, nil
 }
 
diff --git a/internal/distro/fedora30/tar.go b/internal/distro/fedora30/tar.go
index 145d278fb..d469abcb4 100644
--- a/internal/distro/fedora30/tar.go
+++ b/internal/distro/fedora30/tar.go
@@ -19,19 +19,16 @@ func (t *tarOutput) translate(b *blueprint.Blueprint) (*pipeline.Pipeline, error
 	excludedPackages := [...]string{
 		"dracut-config-rescue",
 	}
-	p := getCustomF30PackageSet(packages[:], excludedPackages[:], b)
-	addF30LocaleStage(p)
-	addF30GRUB2Stage(p, b.GetKernelCustomization())
-	addF30FixBlsStage(p)
-	addF30SELinuxStage(p)
-	addF30TarAssembler(p, t.getName(), "xz")
-
-	if b.Customizations != nil {
-		err := customizeAll(p, b.Customizations)
-		if err != nil {
-			return nil, err
-		}
+	p := newF30Pipeline(packages[:], excludedPackages[:], b)
+	err := customizeAll(p, b.Customizations)
+	if err != nil {
+		return nil, err
 	}
+	setBootloader(p, "ro biosdevname=0 net.ifnames=0", b)
+	setFirewall(p, nil, nil, b)
+	setServices(p, nil, nil, b)
+	setTarAssembler(p, t.getName(), "xz")
+
 	return p, nil
 }
 
diff --git a/internal/distro/fedora30/vhd.go b/internal/distro/fedora30/vhd.go
index 9f09f5148..5fb7239a4 100644
--- a/internal/distro/fedora30/vhd.go
+++ b/internal/distro/fedora30/vhd.go
@@ -23,20 +23,17 @@ func (t *vhdOutput) translate(b *blueprint.Blueprint) (*pipeline.Pipeline, error
 	excludedPackages := [...]string{
 		"dracut-config-rescue",
 	}
-	p := getCustomF30PackageSet(packages[:], excludedPackages[:], b)
-	addF30LocaleStage(p)
-	addF30FSTabStage(p)
-	addF30GRUB2Stage(p, b.GetKernelCustomization())
-	addF30FixBlsStage(p)
-	addF30SELinuxStage(p)
-	addF30QemuAssembler(p, "vpc", t.getName())
-
-	if b.Customizations != nil {
-		err := customizeAll(p, b.Customizations)
-		if err != nil {
-			return nil, err
-		}
+	p := newF30Pipeline(packages[:], excludedPackages[:], b)
+	err := customizeAll(p, b.Customizations)
+	if err != nil {
+		return nil, err
 	}
+	setFilesystems(p)
+	setBootloader(p, "ro biosdevname=0 net.ifnames=0", b)
+	setFirewall(p, nil, nil, b)
+	setServices(p, nil, nil, b)
+	setQemuAssembler(p, "vpc", t.getName())
+
 	return p, nil
 }
 
diff --git a/internal/distro/fedora30/vmdk.go b/internal/distro/fedora30/vmdk.go
index dec148da1..adb7e8cb7 100644
--- a/internal/distro/fedora30/vmdk.go
+++ b/internal/distro/fedora30/vmdk.go
@@ -21,20 +21,17 @@ func (t *vmdkOutput) translate(b *blueprint.Blueprint) (*pipeline.Pipeline, erro
 	excludedPackages := [...]string{
 		"dracut-config-rescue",
 	}
-	p := getCustomF30PackageSet(packages[:], excludedPackages[:], b)
-	addF30LocaleStage(p)
-	addF30FSTabStage(p)
-	addF30GRUB2Stage(p, b.GetKernelCustomization())
-	addF30FixBlsStage(p)
-	addF30SELinuxStage(p)
-	addF30QemuAssembler(p, "vmdk", t.getName())
-
-	if b.Customizations != nil {
-		err := customizeAll(p, b.Customizations)
-		if err != nil {
-			return nil, err
-		}
+	p := newF30Pipeline(packages[:], excludedPackages[:], b)
+	err := customizeAll(p, b.Customizations)
+	if err != nil {
+		return nil, err
 	}
+	setFilesystems(p)
+	setBootloader(p, "ro biosdevname=0 net.ifnames=0", b)
+	setFirewall(p, nil, nil, b)
+	setServices(p, nil, nil, b)
+	setQemuAssembler(p, "vmdk", t.getName())
+
 	return p, nil
 }
 


Test patch:
diff --git a/internal/distro/fedora30/os_test.go b/internal/distro/fedora30/os_test.go
index f74a95678..032053b00 100644
--- a/internal/distro/fedora30/os_test.go
+++ b/internal/distro/fedora30/os_test.go
@@ -12,7 +12,6 @@ func TestListOutputFormats(t *testing.T) {
 	want := []string{
 		"ami",
 		"ext4-filesystem",
-		"live-iso",
 		"openstack",
 		"partitioned-disk",
 		"qcow2",
@@ -50,12 +49,6 @@ func TestFilenameFromType(t *testing.T) {
 			want:  "filesystem.img",
 			want1: "application/octet-stream",
 		},
-		{
-			name:  "live-iso",
-			args:  args{"live-iso"},
-			want:  "image.iso",
-			want1: "application/x-iso9660-image",
-		},
 		{
 			name:  "openstack",
 			args:  args{"openstack"},
diff --git a/internal/jobqueue/api_test.go b/internal/jobqueue/api_test.go
index 3de18f145..980b9bea6 100644
--- a/internal/jobqueue/api_test.go
+++ b/internal/jobqueue/api_test.go
@@ -107,7 +107,7 @@ func TestCreate(t *testing.T) {
 	}
 
 	testRoute(t, api, "POST", "/job-queue/v1/jobs", `{}`, http.StatusCreated,
-		`{"id":"ffffffff-ffff-ffff-ffff-ffffffffffff","pipeline":{"build":{"stages":[{"name":"org.osbuild.dnf","options":{"repos":[{"metalink":"https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever&arch=$basearch","gpgkey":"-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFturGcBEACv0xBo91V2n0uEC2vh69ywCiSyvUgN/AQH8EZpCVtM7NyjKgKm\nbbY4G3R0M3ir1xXmvUDvK0493/qOiFrjkplvzXFTGpPTi0ypqGgxc5d0ohRA1M75\nL+0AIlXoOgHQ358/c4uO8X0JAA1NYxCkAW1KSJgFJ3RjukrfqSHWthS1d4o8fhHy\nKJKEnirE5hHqB50dafXrBfgZdaOs3C6ppRIePFe2o4vUEapMTCHFw0woQR8Ah4/R\nn7Z9G9Ln+0Cinmy0nbIDiZJ+pgLAXCOWBfDUzcOjDGKvcpoZharA07c0q1/5ojzO\n4F0Fh4g/BUmtrASwHfcIbjHyCSr1j/3Iz883iy07gJY5Yhiuaqmp0o0f9fgHkG53\n2xCU1owmACqaIBNQMukvXRDtB2GJMuKa/asTZDP6R5re+iXs7+s9ohcRRAKGyAyc\nYKIQKcaA+6M8T7/G+TPHZX6HJWqJJiYB+EC2ERblpvq9TPlLguEWcmvjbVc31nyq\nSDoO3ncFWKFmVsbQPTbP+pKUmlLfJwtb5XqxNR5GEXSwVv4I7IqBmJz1MmRafnBZ\ng0FJUtH668GnldO20XbnSVBr820F5SISMXVwCXDXEvGwwiB8Lt8PvqzXnGIFDAu3\nDlQI5sxSqpPVWSyw08ppKT2Tpmy8adiBotLfaCFl2VTHwOae48X2dMPBvQARAQAB\ntDFGZWRvcmEgKDMwKSA8ZmVkb3JhLTMwLXByaW1hcnlAZmVkb3JhcHJvamVjdC5v\ncmc+iQI4BBMBAgAiBQJbbqxnAhsPBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAK\nCRDvPBEfz8ZZudTnD/9170LL3nyTVUCFmBjT9wZ4gYnpwtKVPa/pKnxbbS+Bmmac\ng9TrT9pZbqOHrNJLiZ3Zx1Hp+8uxr3Lo6kbYwImLhkOEDrf4aP17HfQ6VYFbQZI8\nf79OFxWJ7si9+3gfzeh9UYFEqOQfzIjLWFyfnas0OnV/P+RMQ1Zr+vPRqO7AR2va\nN9wg+Xl7157dhXPCGYnGMNSoxCbpRs0JNlzvJMuAea5nTTznRaJZtK/xKsqLn51D\nK07k9MHVFXakOH8QtMCUglbwfTfIpO5YRq5imxlWbqsYWVQy1WGJFyW6hWC0+RcJ\nOx5zGtOfi4/dN+xJ+ibnbyvy/il7Qm+vyFhCYqIPyS5m2UVJUuao3eApE38k78/o\n8aQOTnFQZ+U1Sw+6woFTxjqRQBXlQm2+7Bt3bqGATg4sXXWPbmwdL87Ic+mxn/ml\nSMfQux/5k6iAu1kQhwkO2YJn9eII6HIPkW+2m5N1JsUyJQe4cbtZE5Yh3TRA0dm7\n+zoBRfCXkOW4krchbgww/ptVmzMMP7GINJdROrJnsGl5FVeid9qHzV7aZycWSma7\nCxBYB1J8HCbty5NjtD6XMYRrMLxXugvX6Q4NPPH+2NKjzX4SIDejS6JjgrP3KA3O\npMuo7ZHMfveBngv8yP+ZD/1sS6l+dfExvdaJdOdgFCnp4p3gPbw5+Lv70HrMjA==\n=BfZ/\n-----END PGP PUBLIC KEY BLOCK-----\n","checksum":"sha256:9f596e18f585bee30ac41c11fb11a83ed6b11d5b341c1cb56ca4015d7717cb97"}],"packages":["dnf","e2fsprogs","policycoreutils","qemu-img","systemd","grub2-pc","tar"],"releasever":"30","basearch":"x86_64"}}]},"stages":[{"name":"org.osbuild.dnf","options":{"repos":[{"metalink":"https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever&arch=$basearch","gpgkey":"-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFturGcBEACv0xBo91V2n0uEC2vh69ywCiSyvUgN/AQH8EZpCVtM7NyjKgKm\nbbY4G3R0M3ir1xXmvUDvK0493/qOiFrjkplvzXFTGpPTi0ypqGgxc5d0ohRA1M75\nL+0AIlXoOgHQ358/c4uO8X0JAA1NYxCkAW1KSJgFJ3RjukrfqSHWthS1d4o8fhHy\nKJKEnirE5hHqB50dafXrBfgZdaOs3C6ppRIePFe2o4vUEapMTCHFw0woQR8Ah4/R\nn7Z9G9Ln+0Cinmy0nbIDiZJ+pgLAXCOWBfDUzcOjDGKvcpoZharA07c0q1/5ojzO\n4F0Fh4g/BUmtrASwHfcIbjHyCSr1j/3Iz883iy07gJY5Yhiuaqmp0o0f9fgHkG53\n2xCU1owmACqaIBNQMukvXRDtB2GJMuKa/asTZDP6R5re+iXs7+s9ohcRRAKGyAyc\nYKIQKcaA+6M8T7/G+TPHZX6HJWqJJiYB+EC2ERblpvq9TPlLguEWcmvjbVc31nyq\nSDoO3ncFWKFmVsbQPTbP+pKUmlLfJwtb5XqxNR5GEXSwVv4I7IqBmJz1MmRafnBZ\ng0FJUtH668GnldO20XbnSVBr820F5SISMXVwCXDXEvGwwiB8Lt8PvqzXnGIFDAu3\nDlQI5sxSqpPVWSyw08ppKT2Tpmy8adiBotLfaCFl2VTHwOae48X2dMPBvQARAQAB\ntDFGZWRvcmEgKDMwKSA8ZmVkb3JhLTMwLXByaW1hcnlAZmVkb3JhcHJvamVjdC5v\ncmc+iQI4BBMBAgAiBQJbbqxnAhsPBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAK\nCRDvPBEfz8ZZudTnD/9170LL3nyTVUCFmBjT9wZ4gYnpwtKVPa/pKnxbbS+Bmmac\ng9TrT9pZbqOHrNJLiZ3Zx1Hp+8uxr3Lo6kbYwImLhkOEDrf4aP17HfQ6VYFbQZI8\nf79OFxWJ7si9+3gfzeh9UYFEqOQfzIjLWFyfnas0OnV/P+RMQ1Zr+vPRqO7AR2va\nN9wg+Xl7157dhXPCGYnGMNSoxCbpRs0JNlzvJMuAea5nTTznRaJZtK/xKsqLn51D\nK07k9MHVFXakOH8QtMCUglbwfTfIpO5YRq5imxlWbqsYWVQy1WGJFyW6hWC0+RcJ\nOx5zGtOfi4/dN+xJ+ibnbyvy/il7Qm+vyFhCYqIPyS5m2UVJUuao3eApE38k78/o\n8aQOTnFQZ+U1Sw+6woFTxjqRQBXlQm2+7Bt3bqGATg4sXXWPbmwdL87Ic+mxn/ml\nSMfQux/5k6iAu1kQhwkO2YJn9eII6HIPkW+2m5N1JsUyJQe4cbtZE5Yh3TRA0dm7\n+zoBRfCXkOW4krchbgww/ptVmzMMP7GINJdROrJnsGl5FVeid9qHzV7aZycWSma7\nCxBYB1J8HCbty5NjtD6XMYRrMLxXugvX6Q4NPPH+2NKjzX4SIDejS6JjgrP3KA3O\npMuo7ZHMfveBngv8yP+ZD/1sS6l+dfExvdaJdOdgFCnp4p3gPbw5+Lv70HrMjA==\n=BfZ/\n-----END PGP PUBLIC KEY BLOCK-----\n","checksum":"sha256:9f596e18f585bee30ac41c11fb11a83ed6b11d5b341c1cb56ca4015d7717cb97"}],"packages":["policycoreutils","selinux-policy-targeted","kernel","firewalld","chrony","langpacks-en"],"exclude_packages":["dracut-config-rescue"],"releasever":"30","basearch":"x86_64"}},{"name":"org.osbuild.locale","options":{"language":"en_US"}},{"name":"org.osbuild.grub2","options":{"root_fs_uuid":"76a22bf4-f153-4541-b6c7-0332c0dfaeac","boot_fs_uuid":"00000000-0000-0000-0000-000000000000","kernel_opts":"ro biosdevname=0 net.ifnames=0"}},{"name":"org.osbuild.fix-bls","options":{}},{"name":"org.osbuild.selinux","options":{"file_contexts":"etc/selinux/targeted/contexts/files/file_contexts"}}],"assembler":{"name":"org.osbuild.tar","options":{"filename":"root.tar.xz"}}},"targets":[{"name":"org.osbuild.local","options":{"location":"/var/lib/osbuild-composer/outputs/ffffffff-ffff-ffff-ffff-ffffffffffff"}}]}`)
+		`{"id":"ffffffff-ffff-ffff-ffff-ffffffffffff","pipeline":{"build":{"stages":[{"name":"org.osbuild.dnf","options":{"repos":[{"metalink":"https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever\u0026arch=$basearch","gpgkey":"-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFturGcBEACv0xBo91V2n0uEC2vh69ywCiSyvUgN/AQH8EZpCVtM7NyjKgKm\nbbY4G3R0M3ir1xXmvUDvK0493/qOiFrjkplvzXFTGpPTi0ypqGgxc5d0ohRA1M75\nL+0AIlXoOgHQ358/c4uO8X0JAA1NYxCkAW1KSJgFJ3RjukrfqSHWthS1d4o8fhHy\nKJKEnirE5hHqB50dafXrBfgZdaOs3C6ppRIePFe2o4vUEapMTCHFw0woQR8Ah4/R\nn7Z9G9Ln+0Cinmy0nbIDiZJ+pgLAXCOWBfDUzcOjDGKvcpoZharA07c0q1/5ojzO\n4F0Fh4g/BUmtrASwHfcIbjHyCSr1j/3Iz883iy07gJY5Yhiuaqmp0o0f9fgHkG53\n2xCU1owmACqaIBNQMukvXRDtB2GJMuKa/asTZDP6R5re+iXs7+s9ohcRRAKGyAyc\nYKIQKcaA+6M8T7/G+TPHZX6HJWqJJiYB+EC2ERblpvq9TPlLguEWcmvjbVc31nyq\nSDoO3ncFWKFmVsbQPTbP+pKUmlLfJwtb5XqxNR5GEXSwVv4I7IqBmJz1MmRafnBZ\ng0FJUtH668GnldO20XbnSVBr820F5SISMXVwCXDXEvGwwiB8Lt8PvqzXnGIFDAu3\nDlQI5sxSqpPVWSyw08ppKT2Tpmy8adiBotLfaCFl2VTHwOae48X2dMPBvQARAQAB\ntDFGZWRvcmEgKDMwKSA8ZmVkb3JhLTMwLXByaW1hcnlAZmVkb3JhcHJvamVjdC5v\ncmc+iQI4BBMBAgAiBQJbbqxnAhsPBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAK\nCRDvPBEfz8ZZudTnD/9170LL3nyTVUCFmBjT9wZ4gYnpwtKVPa/pKnxbbS+Bmmac\ng9TrT9pZbqOHrNJLiZ3Zx1Hp+8uxr3Lo6kbYwImLhkOEDrf4aP17HfQ6VYFbQZI8\nf79OFxWJ7si9+3gfzeh9UYFEqOQfzIjLWFyfnas0OnV/P+RMQ1Zr+vPRqO7AR2va\nN9wg+Xl7157dhXPCGYnGMNSoxCbpRs0JNlzvJMuAea5nTTznRaJZtK/xKsqLn51D\nK07k9MHVFXakOH8QtMCUglbwfTfIpO5YRq5imxlWbqsYWVQy1WGJFyW6hWC0+RcJ\nOx5zGtOfi4/dN+xJ+ibnbyvy/il7Qm+vyFhCYqIPyS5m2UVJUuao3eApE38k78/o\n8aQOTnFQZ+U1Sw+6woFTxjqRQBXlQm2+7Bt3bqGATg4sXXWPbmwdL87Ic+mxn/ml\nSMfQux/5k6iAu1kQhwkO2YJn9eII6HIPkW+2m5N1JsUyJQe4cbtZE5Yh3TRA0dm7\n+zoBRfCXkOW4krchbgww/ptVmzMMP7GINJdROrJnsGl5FVeid9qHzV7aZycWSma7\nCxBYB1J8HCbty5NjtD6XMYRrMLxXugvX6Q4NPPH+2NKjzX4SIDejS6JjgrP3KA3O\npMuo7ZHMfveBngv8yP+ZD/1sS6l+dfExvdaJdOdgFCnp4p3gPbw5+Lv70HrMjA==\n=BfZ/\n-----END PGP PUBLIC KEY BLOCK-----\n","checksum":"sha256:9f596e18f585bee30ac41c11fb11a83ed6b11d5b341c1cb56ca4015d7717cb97"}],"packages":["dnf","e2fsprogs","policycoreutils","qemu-img","systemd","grub2-pc","tar"],"releasever":"30","basearch":"x86_64"}}]},"stages":[{"name":"org.osbuild.dnf","options":{"repos":[{"metalink":"https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever\u0026arch=$basearch","gpgkey":"-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFturGcBEACv0xBo91V2n0uEC2vh69ywCiSyvUgN/AQH8EZpCVtM7NyjKgKm\nbbY4G3R0M3ir1xXmvUDvK0493/qOiFrjkplvzXFTGpPTi0ypqGgxc5d0ohRA1M75\nL+0AIlXoOgHQ358/c4uO8X0JAA1NYxCkAW1KSJgFJ3RjukrfqSHWthS1d4o8fhHy\nKJKEnirE5hHqB50dafXrBfgZdaOs3C6ppRIePFe2o4vUEapMTCHFw0woQR8Ah4/R\nn7Z9G9Ln+0Cinmy0nbIDiZJ+pgLAXCOWBfDUzcOjDGKvcpoZharA07c0q1/5ojzO\n4F0Fh4g/BUmtrASwHfcIbjHyCSr1j/3Iz883iy07gJY5Yhiuaqmp0o0f9fgHkG53\n2xCU1owmACqaIBNQMukvXRDtB2GJMuKa/asTZDP6R5re+iXs7+s9ohcRRAKGyAyc\nYKIQKcaA+6M8T7/G+TPHZX6HJWqJJiYB+EC2ERblpvq9TPlLguEWcmvjbVc31nyq\nSDoO3ncFWKFmVsbQPTbP+pKUmlLfJwtb5XqxNR5GEXSwVv4I7IqBmJz1MmRafnBZ\ng0FJUtH668GnldO20XbnSVBr820F5SISMXVwCXDXEvGwwiB8Lt8PvqzXnGIFDAu3\nDlQI5sxSqpPVWSyw08ppKT2Tpmy8adiBotLfaCFl2VTHwOae48X2dMPBvQARAQAB\ntDFGZWRvcmEgKDMwKSA8ZmVkb3JhLTMwLXByaW1hcnlAZmVkb3JhcHJvamVjdC5v\ncmc+iQI4BBMBAgAiBQJbbqxnAhsPBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAK\nCRDvPBEfz8ZZudTnD/9170LL3nyTVUCFmBjT9wZ4gYnpwtKVPa/pKnxbbS+Bmmac\ng9TrT9pZbqOHrNJLiZ3Zx1Hp+8uxr3Lo6kbYwImLhkOEDrf4aP17HfQ6VYFbQZI8\nf79OFxWJ7si9+3gfzeh9UYFEqOQfzIjLWFyfnas0OnV/P+RMQ1Zr+vPRqO7AR2va\nN9wg+Xl7157dhXPCGYnGMNSoxCbpRs0JNlzvJMuAea5nTTznRaJZtK/xKsqLn51D\nK07k9MHVFXakOH8QtMCUglbwfTfIpO5YRq5imxlWbqsYWVQy1WGJFyW6hWC0+RcJ\nOx5zGtOfi4/dN+xJ+ibnbyvy/il7Qm+vyFhCYqIPyS5m2UVJUuao3eApE38k78/o\n8aQOTnFQZ+U1Sw+6woFTxjqRQBXlQm2+7Bt3bqGATg4sXXWPbmwdL87Ic+mxn/ml\nSMfQux/5k6iAu1kQhwkO2YJn9eII6HIPkW+2m5N1JsUyJQe4cbtZE5Yh3TRA0dm7\n+zoBRfCXkOW4krchbgww/ptVmzMMP7GINJdROrJnsGl5FVeid9qHzV7aZycWSma7\nCxBYB1J8HCbty5NjtD6XMYRrMLxXugvX6Q4NPPH+2NKjzX4SIDejS6JjgrP3KA3O\npMuo7ZHMfveBngv8yP+ZD/1sS6l+dfExvdaJdOdgFCnp4p3gPbw5+Lv70HrMjA==\n=BfZ/\n-----END PGP PUBLIC KEY BLOCK-----\n","checksum":"sha256:9f596e18f585bee30ac41c11fb11a83ed6b11d5b341c1cb56ca4015d7717cb97"}],"packages":["policycoreutils","selinux-policy-targeted","kernel","firewalld","chrony","langpacks-en"],"exclude_packages":["dracut-config-rescue"],"releasever":"30","basearch":"x86_64"}},{"name":"org.osbuild.fix-bls","options":{}},{"name":"org.osbuild.locale","options":{"language":"en_US"}},{"name":"org.osbuild.grub2","options":{"root_fs_uuid":"76a22bf4-f153-4541-b6c7-0332c0dfaeac","boot_fs_uuid":"00000000-0000-0000-0000-000000000000","kernel_opts":"ro biosdevname=0 net.ifnames=0"}},{"name":"org.osbuild.selinux","options":{"file_contexts":"etc/selinux/targeted/contexts/files/file_contexts"}}],"assembler":{"name":"org.osbuild.tar","options":{"filename":"root.tar.xz"}}},"targets":[{"name":"org.osbuild.local","options":{"location":"/var/lib/osbuild-composer/outputs/ffffffff-ffff-ffff-ffff-ffffffffffff"}}]}`)
 }
 
 func testUpdateTransition(t *testing.T, from, to string, expectedStatus int) {
diff --git a/test/cases/ami_empty_blueprint.json b/test/cases/ami_empty_blueprint.json
index 233e4cd15..acb4d750f 100644
--- a/test/cases/ami_empty_blueprint.json
+++ b/test/cases/ami_empty_blueprint.json
@@ -94,7 +94,15 @@
         "options": {
           "root_fs_uuid": "76a22bf4-f153-4541-b6c7-0332c0dfaeac",
           "boot_fs_uuid": "00000000-0000-0000-0000-000000000000",
-          "kernel_opts": "ro biosdevname=0 net.ifnames=0"
+          "kernel_opts": "ro no_timer_check console=ttyS0,115200n8 console=tty1 biosdevname=0 net.ifnames=0 console=ttyS0,115200"
+        }
+      },
+      {
+        "name": "org.osbuild.systemd",
+        "options": {
+          "enabled_services": [
+            "cloud-init.service"
+          ]
         }
       },
       {
@@ -119,7 +127,7 @@
     "boot-environment": {
       "GRUB2_BOOT_FS_UUID": "76a22bf4-f153-4541-b6c7-0332c0dfaeac",
       "GRUB2_ROOT_FS_UUID": "76a22bf4-f153-4541-b6c7-0332c0dfaeac",
-      "kernelopts": "root=UUID=76a22bf4-f153-4541-b6c7-0332c0dfaeac ro biosdevname=0 net.ifnames=0"
+      "kernelopts": "root=UUID=76a22bf4-f153-4541-b6c7-0332c0dfaeac ro no_timer_check console=ttyS0,115200n8 console=tty1 biosdevname=0 net.ifnames=0 console=ttyS0,115200"
     },
     "bootloader": "grub",
     "bootmenu": [
@@ -621,7 +629,6 @@
       "cloud-config.service",
       "cloud-final.service",
       "cloud-init-local.service",
-      "cloud-init.service",
       "console-getty.service",
       "debug-shell.service",
       "ebtables.service",
@@ -664,6 +671,7 @@
       "auditd.service",
       "autovt@.service",
       "chronyd.service",
+      "cloud-init.service",
       "dbus-broker.service",
       "dbus-org.fedoraproject.FirewallD1.service",
       "dbus-org.freedesktop.nm-dispatcher.service",
diff --git a/test/cases/ami_local_boot.json b/test/cases/ami_local_boot.json
index e2a70070b..b7ac22981 100644
--- a/test/cases/ami_local_boot.json
+++ b/test/cases/ami_local_boot.json
@@ -102,6 +102,28 @@
           "language": "en_US"
         }
       },
+      {
+        "name": "org.osbuild.systemd",
+        "options": {
+          "enabled_services": [
+            "sshd"
+          ]
+        }
+      },
+      {
+        "name": "org.osbuild.users",
+        "options": {
+          "users": {
+            "redhat": {
+              "groups": [
+                "wheel"
+              ],
+              "password": "$6$IR7O7z56ouB/OInP$.hscD6dQqPQGwMuQ.idumixSHI/JEyaUfiCAHVSpGO/iNLEvvVZVOQL23zBzQbc2.yJ25xAZD75H0tXqKJpEE/",
+              "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC61wMCjOSHwbVb4VfVyl5sn497qW4PsdQ7Ty7aD6wDNZ/QjjULkDV/yW5WjDlDQ7UqFH0Sr7vywjqDizUAqK7zM5FsUKsUXWHWwg/ehKg8j9xKcMv11AkFoUoujtfAujnKODkk58XSA9whPr7qcw3vPrmog680pnMSzf9LC7J6kXfs6lkoKfBh9VnlxusCrw2yg0qI1fHAZBLPx7mW6+me71QZsS6sVz8v8KXyrXsKTdnF50FjzHcK9HXDBtSJS5wA3fkcRYymJe0o6WMWNdgSRVpoSiWaHHmFgdMUJaYoCfhXzyl7LtNb3Q+Sveg+tJK7JaRXBLMUllOlJ6ll5Hod root@localhost"
+            }
+          }
+        }
+      },
       {
         "name": "org.osbuild.fstab",
         "options": {
@@ -125,37 +147,11 @@
           "kernel_opts": "ro biosdevname=0 net.ifnames=0"
         }
       },
-      {
-        "name": "org.osbuild.systemd",
-        "options": {
-          "enabled_services": [
-            "sshd"
-          ]
-        }
-      },
-      {
-        "name": "org.osbuild.users",
-        "options": {
-          "users": {
-            "redhat": {
-              "groups": [
-                "wheel"
-              ],
-              "password": "$6$IR7O7z56ouB/OInP$.hscD6dQqPQGwMuQ.idumixSHI/JEyaUfiCAHVSpGO/iNLEvvVZVOQL23zBzQbc2.yJ25xAZD75H0tXqKJpEE/",
-              "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC61wMCjOSHwbVb4VfVyl5sn497qW4PsdQ7Ty7aD6wDNZ/QjjULkDV/yW5WjDlDQ7UqFH0Sr7vywjqDizUAqK7zM5FsUKsUXWHWwg/ehKg8j9xKcMv11AkFoUoujtfAujnKODkk58XSA9whPr7qcw3vPrmog680pnMSzf9LC7J6kXfs6lkoKfBh9VnlxusCrw2yg0qI1fHAZBLPx7mW6+me71QZsS6sVz8v8KXyrXsKTdnF50FjzHcK9HXDBtSJS5wA3fkcRYymJe0o6WMWNdgSRVpoSiWaHHmFgdMUJaYoCfhXzyl7LtNb3Q+Sveg+tJK7JaRXBLMUllOlJ6ll5Hod root@localhost"
-            }
-          }
-        }
-      },
       {
         "name": "org.osbuild.selinux",
         "options": {
           "file_contexts": "etc/selinux/targeted/contexts/files/file_contexts"
         }
-      },
-      {
-        "name": "org.osbuild.fix-bls",
-        "options": {}
       }
     ],
     "assembler": {
diff --git a/test/cases/disk_empty_blueprint.json b/test/cases/disk_empty_blueprint.json
index e1f3027f5..4844d69e3 100644
--- a/test/cases/disk_empty_blueprint.json
+++ b/test/cases/disk_empty_blueprint.json
@@ -60,6 +60,10 @@
           "basearch": "x86_64"
         }
       },
+      {
+        "name": "org.osbuild.fix-bls",
+        "options": {}
+      },
       {
         "name": "org.osbuild.locale",
         "options": {
@@ -89,10 +93,6 @@
           "kernel_opts": "ro biosdevname=0 net.ifnames=0"
         }
       },
-      {
-        "name": "org.osbuild.fix-bls",
-        "options": {}
-      },
       {
         "name": "org.osbuild.selinux",
         "options": {
diff --git a/test/cases/ext4_empty_blueprint.json b/test/cases/ext4_empty_blueprint.json
index 2bcebc809..6268ab842 100644
--- a/test/cases/ext4_empty_blueprint.json
+++ b/test/cases/ext4_empty_blueprint.json
@@ -59,6 +59,10 @@
           "basearch": "x86_64"
         }
       },
+      {
+        "name": "org.osbuild.fix-bls",
+        "options": {}
+      },
       {
         "name": "org.osbuild.locale",
         "options": {
@@ -73,10 +77,6 @@
           "kernel_opts": "ro biosdevname=0 net.ifnames=0"
         }
       },
-      {
-        "name": "org.osbuild.fix-bls",
-        "options": {}
-      },
       {
         "name": "org.osbuild.selinux",
         "options": {
diff --git a/test/cases/openstack_empty_blueprint.json b/test/cases/openstack_empty_blueprint.json
index b43d310a2..f94aa8a9c 100644
--- a/test/cases/openstack_empty_blueprint.json
+++ b/test/cases/openstack_empty_blueprint.json
@@ -64,6 +64,10 @@
           "basearch": "x86_64"
         }
       },
+      {
+        "name": "org.osbuild.fix-bls",
+        "options": {}
+      },
       {
         "name": "org.osbuild.locale",
         "options": {
@@ -93,10 +97,6 @@
           "kernel_opts": "ro biosdevname=0 net.ifnames=0"
         }
       },
-      {
-        "name": "org.osbuild.fix-bls",
-        "options": {}
-      },
       {
         "name": "org.osbuild.selinux",
         "options": {
diff --git a/test/cases/qcow2_empty_blueprint.json b/test/cases/qcow2_empty_blueprint.json
index 4d2a88dbd..cf4370527 100644
--- a/test/cases/qcow2_empty_blueprint.json
+++ b/test/cases/qcow2_empty_blueprint.json
@@ -65,6 +65,10 @@
           "basearch": "x86_64"
         }
       },
+      {
+        "name": "org.osbuild.fix-bls",
+        "options": {}
+      },
       {
         "name": "org.osbuild.locale",
         "options": {
@@ -94,10 +98,6 @@
           "kernel_opts": "ro biosdevname=0 net.ifnames=0"
         }
       },
-      {
-        "name": "org.osbuild.fix-bls",
-        "options": {}
-      },
       {
         "name": "org.osbuild.selinux",
         "options": {
diff --git a/test/cases/vhd_empty_blueprint.json b/test/cases/vhd_empty_blueprint.json
index 30563b96d..b04cc4479 100644
--- a/test/cases/vhd_empty_blueprint.json
+++ b/test/cases/vhd_empty_blueprint.json
@@ -63,6 +63,10 @@
           "basearch": "x86_64"
         }
       },
+      {
+        "name": "org.osbuild.fix-bls",
+        "options": {}
+      },
       {
         "name": "org.osbuild.locale",
         "options": {
@@ -92,10 +96,6 @@
           "kernel_opts": "ro biosdevname=0 net.ifnames=0"
         }
       },
-      {
-        "name": "org.osbuild.fix-bls",
-        "options": {}
-      },
       {
         "name": "org.osbuild.selinux",
         "options": {
diff --git a/test/cases/vmdk_empty_blueprint.json b/test/cases/vmdk_empty_blueprint.json
index 939aff005..339d20f5a 100644
--- a/test/cases/vmdk_empty_blueprint.json
+++ b/test/cases/vmdk_empty_blueprint.json
@@ -61,6 +61,10 @@
           "basearch": "x86_64"
         }
       },
+      {
+        "name": "org.osbuild.fix-bls",
+        "options": {}
+      },
       {
         "name": "org.osbuild.locale",
         "options": {
@@ -90,10 +94,6 @@
           "kernel_opts": "ro biosdevname=0 net.ifnames=0"
         }
       },
-      {
-        "name": "org.osbuild.fix-bls",
-        "options": {}
-      },
       {
         "name": "org.osbuild.selinux",
         "options": {