osbuild1: DELETED
This commit is contained in:
parent
dcef56c75a
commit
01d87b4e60
57 changed files with 0 additions and 1976 deletions
|
|
@ -1,55 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// An Assembler turns a filesystem tree into a target image.
|
||||
type Assembler struct {
|
||||
Name string `json:"name"`
|
||||
Options AssemblerOptions `json:"options"`
|
||||
}
|
||||
|
||||
// AssemblerOptions specify the operations of a given assembler-type.
|
||||
type AssemblerOptions interface {
|
||||
isAssemblerOptions()
|
||||
}
|
||||
|
||||
type rawAssembler struct {
|
||||
Name string `json:"name"`
|
||||
Options json.RawMessage `json:"options"`
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals JSON into an Assembler object. Each type of
|
||||
// assembler has a custom unmarshaller for its options, selected based on the
|
||||
// stage name.
|
||||
func (assembler *Assembler) UnmarshalJSON(data []byte) error {
|
||||
var rawAssembler rawAssembler
|
||||
err := json.Unmarshal(data, &rawAssembler)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var options AssemblerOptions
|
||||
switch rawAssembler.Name {
|
||||
case "org.osbuild.ostree.commit":
|
||||
options = new(OSTreeCommitAssemblerOptions)
|
||||
case "org.osbuild.qemu":
|
||||
options = new(QEMUAssemblerOptions)
|
||||
case "org.osbuild.rawfs":
|
||||
options = new(RawFSAssemblerOptions)
|
||||
case "org.osbuild.tar":
|
||||
options = new(TarAssemblerOptions)
|
||||
default:
|
||||
return errors.New("unexpected assembler name")
|
||||
}
|
||||
err = json.Unmarshal(rawAssembler.Options, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
assembler.Name = rawAssembler.Name
|
||||
assembler.Options = options
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,171 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAssembler_UnmarshalJSON(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
assembler Assembler
|
||||
data []byte
|
||||
errorExpected bool
|
||||
}{
|
||||
{
|
||||
// invalid JSON - note the missing brace at the end of the string
|
||||
name: "invalid json",
|
||||
data: []byte(`{"name":"org.osbuild.tar","options":{"filename":""}`),
|
||||
errorExpected: true,
|
||||
},
|
||||
{
|
||||
// valid JSON, but with an unknown assembler (org.osbuild.foo)
|
||||
name: "unknown assembler",
|
||||
data: []byte(`{"name":"org.osbuild.foo","options":{"bar":null}}`),
|
||||
errorExpected: true,
|
||||
},
|
||||
{
|
||||
name: "missing options",
|
||||
data: []byte(`{"name":"org.osbuild.rawfs"`),
|
||||
errorExpected: true,
|
||||
},
|
||||
{
|
||||
name: "missing name",
|
||||
data: []byte(`{"options":{"bar":null}}`),
|
||||
errorExpected: true,
|
||||
},
|
||||
{
|
||||
name: "qemu assembler empty",
|
||||
assembler: Assembler{
|
||||
Name: "org.osbuild.qemu",
|
||||
Options: &QEMUAssemblerOptions{},
|
||||
},
|
||||
data: []byte(`{"name":"org.osbuild.qemu","options":{"format":"","filename":"","size":0,"ptuuid":"","pttype":"","partitions":null}}`),
|
||||
},
|
||||
{
|
||||
name: "qemu assembler full",
|
||||
assembler: Assembler{
|
||||
Name: "org.osbuild.qemu",
|
||||
Options: &QEMUAssemblerOptions{
|
||||
Format: "qcow2",
|
||||
Filename: "disk.qcow2",
|
||||
Size: 2147483648,
|
||||
PTUUID: "0x14fc63d2",
|
||||
PTType: "mbr",
|
||||
Partitions: []QEMUPartition{QEMUPartition{
|
||||
Start: 2048,
|
||||
Bootable: true,
|
||||
Filesystem: &QEMUFilesystem{
|
||||
Type: "ext4",
|
||||
UUID: "76a22bf4-f153-4541-b6c7-0332c0dfaeac",
|
||||
Label: "root",
|
||||
Mountpoint: "/",
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
data: []byte(`{"name":"org.osbuild.qemu","options":{"format":"qcow2","filename":"disk.qcow2","size":2147483648,"ptuuid":"0x14fc63d2","pttype":"mbr","partitions":[{"start":2048,"bootable":true,"filesystem":{"type":"ext4","uuid":"76a22bf4-f153-4541-b6c7-0332c0dfaeac","label":"root","mountpoint":"/"}}]}}`),
|
||||
},
|
||||
{
|
||||
name: "tar assembler empty",
|
||||
assembler: Assembler{
|
||||
Name: "org.osbuild.tar",
|
||||
Options: &TarAssemblerOptions{},
|
||||
},
|
||||
data: []byte(`{"name":"org.osbuild.tar","options":{"filename":""}}`),
|
||||
},
|
||||
{
|
||||
name: "tar assembler full",
|
||||
assembler: Assembler{
|
||||
Name: "org.osbuild.tar",
|
||||
Options: &TarAssemblerOptions{
|
||||
Filename: "root.tar.xz",
|
||||
Compression: "xz",
|
||||
},
|
||||
},
|
||||
data: []byte(`{"name":"org.osbuild.tar","options":{"filename":"root.tar.xz","compression":"xz"}}`),
|
||||
},
|
||||
{
|
||||
name: "rawfs assembler empty",
|
||||
assembler: Assembler{
|
||||
Name: "org.osbuild.rawfs",
|
||||
Options: &RawFSAssemblerOptions{},
|
||||
},
|
||||
data: []byte(`{"name":"org.osbuild.rawfs","options":{"filename":"","root_fs_uuid":"00000000-0000-0000-0000-000000000000","size":0}}`),
|
||||
},
|
||||
{
|
||||
name: "rawfs assembler full",
|
||||
assembler: Assembler{
|
||||
Name: "org.osbuild.rawfs",
|
||||
Options: &RawFSAssemblerOptions{
|
||||
Filename: "filesystem.img",
|
||||
RootFilesystemUUID: uuid.MustParse("76a22bf4-f153-4541-b6c7-0332c0dfaeac"),
|
||||
Size: 2147483648,
|
||||
},
|
||||
},
|
||||
data: []byte(`{"name":"org.osbuild.rawfs","options":{"filename":"filesystem.img","root_fs_uuid":"76a22bf4-f153-4541-b6c7-0332c0dfaeac","size":2147483648}}`),
|
||||
},
|
||||
{
|
||||
name: "ostree commit assembler",
|
||||
assembler: Assembler{
|
||||
Name: "org.osbuild.ostree.commit",
|
||||
Options: &OSTreeCommitAssemblerOptions{
|
||||
Ref: "foo",
|
||||
Tar: OSTreeCommitAssemblerTarOptions{
|
||||
Filename: "foo.tar",
|
||||
},
|
||||
},
|
||||
},
|
||||
data: []byte(`{"name":"org.osbuild.ostree.commit","options":{"ref":"foo","tar":{"filename":"foo.tar"}}}`),
|
||||
},
|
||||
}
|
||||
|
||||
assert := assert.New(t)
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assembler := &tt.assembler
|
||||
var gotAssembler Assembler
|
||||
err := gotAssembler.UnmarshalJSON(tt.data)
|
||||
if tt.errorExpected {
|
||||
assert.NotNil(err)
|
||||
return
|
||||
} else {
|
||||
assert.Nil(err)
|
||||
}
|
||||
gotBytes, err := json.Marshal(assembler)
|
||||
assert.Nilf(err, "Could not marshal assembler: %v", err)
|
||||
assert.Equal(tt.data, gotBytes)
|
||||
assert.Equal(&gotAssembler, assembler)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewQEMUAssembler(t *testing.T) {
|
||||
options := &QEMUAssemblerOptions{}
|
||||
expectedAssembler := &Assembler{
|
||||
Name: "org.osbuild.qemu",
|
||||
Options: &QEMUAssemblerOptions{},
|
||||
}
|
||||
assert.Equal(t, expectedAssembler, NewQEMUAssembler(options))
|
||||
}
|
||||
|
||||
func TestNewTarAssembler(t *testing.T) {
|
||||
options := &TarAssemblerOptions{}
|
||||
expectedAssembler := &Assembler{
|
||||
Name: "org.osbuild.tar",
|
||||
Options: &TarAssemblerOptions{},
|
||||
}
|
||||
assert.Equal(t, expectedAssembler, NewTarAssembler(options))
|
||||
}
|
||||
|
||||
func TestNewRawFSAssembler(t *testing.T) {
|
||||
options := &RawFSAssemblerOptions{}
|
||||
expectedAssembler := &Assembler{
|
||||
Name: "org.osbuild.rawfs",
|
||||
Options: &RawFSAssemblerOptions{},
|
||||
}
|
||||
assert.Equal(t, expectedAssembler, NewRawFSAssembler(options))
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
type ChronyStageOptions struct {
|
||||
Timeservers []string `json:"timeservers"`
|
||||
}
|
||||
|
||||
func (ChronyStageOptions) isStageOptions() {}
|
||||
|
||||
func NewChronyStage(options *ChronyStageOptions) *Stage {
|
||||
return &Stage{
|
||||
Name: "org.osbuild.chrony",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewChronyStage(t *testing.T) {
|
||||
expectedStage := &Stage{
|
||||
Name: "org.osbuild.chrony",
|
||||
Options: &ChronyStageOptions{},
|
||||
}
|
||||
actualStage := NewChronyStage(&ChronyStageOptions{})
|
||||
assert.Equal(t, expectedStage, actualStage)
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
type Secret struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
}
|
||||
type FileSource struct {
|
||||
URL string `json:"url"`
|
||||
Secrets *Secret `json:"secrets,omitempty"`
|
||||
}
|
||||
|
||||
// The FilesSourceOptions specifies a custom script to run in the image
|
||||
type FilesSource struct {
|
||||
URLs map[string]FileSource `json:"urls"`
|
||||
}
|
||||
|
||||
func (FilesSource) isSource() {}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
type FirewallStageOptions struct {
|
||||
Ports []string `json:"ports,omitempty"`
|
||||
EnabledServices []string `json:"enabled_services,omitempty"`
|
||||
DisabledServices []string `json:"disabled_services,omitempty"`
|
||||
}
|
||||
|
||||
func (FirewallStageOptions) isStageOptions() {}
|
||||
|
||||
func NewFirewallStage(options *FirewallStageOptions) *Stage {
|
||||
return &Stage{
|
||||
Name: "org.osbuild.firewall",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewFirewallStage(t *testing.T) {
|
||||
expectedFirewall := &Stage{
|
||||
Name: "org.osbuild.firewall",
|
||||
Options: &FirewallStageOptions{},
|
||||
}
|
||||
actualFirewall := NewFirewallStage(&FirewallStageOptions{})
|
||||
assert.Equal(t, expectedFirewall, actualFirewall)
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
type FirstBootStageOptions struct {
|
||||
Commands []string `json:"commands"`
|
||||
WaitForNetwork bool `json:"wait_for_network,omitempty"`
|
||||
}
|
||||
|
||||
func (FirstBootStageOptions) isStageOptions() {}
|
||||
|
||||
func NewFirstBootStage(options *FirstBootStageOptions) *Stage {
|
||||
return &Stage{
|
||||
Name: "org.osbuild.first-boot",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewFirstBootStage(t *testing.T) {
|
||||
expectedStage := &Stage{
|
||||
Name: "org.osbuild.first-boot",
|
||||
Options: &FirstBootStageOptions{},
|
||||
}
|
||||
actualStage := NewFirstBootStage(&FirstBootStageOptions{})
|
||||
assert.Equal(t, expectedStage, actualStage)
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
// A FixBLSStageOptions struct is empty, as the stage takes no options.
|
||||
//
|
||||
// The FixBLSStage fixes the paths in the Boot Loader Specification
|
||||
// snippets installed into /boot. grub2's kernel install script will
|
||||
// try to guess the correct path to the kernel and bootloader, and adjust
|
||||
// the boot loader scripts accordingly. When run under OSBuild this does
|
||||
// not work correctly, so this stage essentially reverts the "fixup".
|
||||
type FixBLSStageOptions struct {
|
||||
}
|
||||
|
||||
func (FixBLSStageOptions) isStageOptions() {}
|
||||
|
||||
// NewFixBLSStage creates a new FixBLSStage.
|
||||
func NewFixBLSStage() *Stage {
|
||||
return &Stage{
|
||||
Name: "org.osbuild.fix-bls",
|
||||
Options: &FixBLSStageOptions{},
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewFixBLSStage(t *testing.T) {
|
||||
expectedStage := &Stage{
|
||||
Name: "org.osbuild.fix-bls",
|
||||
Options: &FixBLSStageOptions{},
|
||||
}
|
||||
actualStage := NewFixBLSStage()
|
||||
assert.Equal(t, expectedStage, actualStage)
|
||||
}
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/osbuild/osbuild-composer/internal/disk"
|
||||
)
|
||||
|
||||
// The FSTabStageOptions describe the content of the /etc/fstab file.
|
||||
//
|
||||
// The structure of the options follows the format of /etc/fstab, except
|
||||
// that filesystem must be identified by their UUID and ommitted fields
|
||||
// are set to their defaults (if possible).
|
||||
type FSTabStageOptions struct {
|
||||
FileSystems []*FSTabEntry `json:"filesystems"`
|
||||
}
|
||||
|
||||
func (FSTabStageOptions) isStageOptions() {}
|
||||
|
||||
// NewFSTabStage creates a now FSTabStage object
|
||||
func NewFSTabStage(options *FSTabStageOptions) *Stage {
|
||||
return &Stage{
|
||||
Name: "org.osbuild.fstab",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
||||
// An FSTabEntry represents one line in /etc/fstab. With the one exception
|
||||
// that the the spec field must be represented as an UUID.
|
||||
type FSTabEntry struct {
|
||||
UUID string `json:"uuid,omitempty"`
|
||||
Label string `json:"label,omitempty"`
|
||||
VFSType string `json:"vfs_type"`
|
||||
Path string `json:"path,omitempty"`
|
||||
Options string `json:"options,omitempty"`
|
||||
Freq uint64 `json:"freq,omitempty"`
|
||||
PassNo uint64 `json:"passno,omitempty"`
|
||||
}
|
||||
|
||||
// AddFilesystem adds one entry to and FSTabStageOptions object.
|
||||
func (options *FSTabStageOptions) AddFilesystem(id string, vfsType string, path string, opts string, freq uint64, passNo uint64) {
|
||||
options.FileSystems = append(options.FileSystems, &FSTabEntry{
|
||||
UUID: id,
|
||||
VFSType: vfsType,
|
||||
Path: path,
|
||||
Options: opts,
|
||||
Freq: freq,
|
||||
PassNo: passNo,
|
||||
})
|
||||
}
|
||||
|
||||
func NewFSTabStageOptions(pt *disk.PartitionTable) *FSTabStageOptions {
|
||||
var options FSTabStageOptions
|
||||
genOption := func(mnt disk.Mountable, path []disk.Entity) error {
|
||||
fsSpec := mnt.GetFSSpec()
|
||||
fsOptions := mnt.GetFSTabOptions()
|
||||
options.AddFilesystem(fsSpec.UUID, mnt.GetFSType(), mnt.GetMountpoint(), fsOptions.MntOps, fsOptions.Freq, fsOptions.PassNo)
|
||||
return nil
|
||||
}
|
||||
|
||||
_ = pt.ForEachMountable(genOption)
|
||||
// sort the entries by PassNo to maintain backward compatibility
|
||||
sort.Slice(options.FileSystems, func(i, j int) bool {
|
||||
return options.FileSystems[i].PassNo < options.FileSystems[j].PassNo
|
||||
})
|
||||
return &options
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewFSTabStage(t *testing.T) {
|
||||
expectedStage := &Stage{
|
||||
Name: "org.osbuild.fstab",
|
||||
Options: &FSTabStageOptions{},
|
||||
}
|
||||
actualStage := NewFSTabStage(&FSTabStageOptions{})
|
||||
assert.Equal(t, expectedStage, actualStage)
|
||||
}
|
||||
|
||||
func TestAddFilesystem(t *testing.T) {
|
||||
options := &FSTabStageOptions{}
|
||||
filesystems := []*FSTabEntry{
|
||||
{
|
||||
UUID: "76a22bf4-f153-4541-b6c7-0332c0dfaeac",
|
||||
VFSType: "ext4",
|
||||
Path: "/",
|
||||
Options: "defaults",
|
||||
Freq: 1,
|
||||
PassNo: 1,
|
||||
},
|
||||
{
|
||||
UUID: "bba22bf4-f153-4541-b6c7-0332c0dfaeac",
|
||||
VFSType: "xfs",
|
||||
Path: "/home",
|
||||
Options: "defaults",
|
||||
Freq: 1,
|
||||
PassNo: 2,
|
||||
},
|
||||
{
|
||||
UUID: "cca22bf4-f153-4541-b6c7-0332c0dfaeac",
|
||||
VFSType: "xfs",
|
||||
Path: "/var",
|
||||
Options: "defaults",
|
||||
Freq: 1,
|
||||
PassNo: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for i, fs := range filesystems {
|
||||
options.AddFilesystem(fs.UUID, fs.VFSType, fs.Path, fs.Options, fs.Freq, fs.PassNo)
|
||||
assert.Equal(t, options.FileSystems[i], fs)
|
||||
}
|
||||
assert.Equal(t, len(filesystems), len(options.FileSystems))
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import "github.com/osbuild/osbuild-composer/internal/blueprint"
|
||||
|
||||
type GroupsStageOptions struct {
|
||||
Groups map[string]GroupsStageOptionsGroup `json:"groups"`
|
||||
}
|
||||
|
||||
func (GroupsStageOptions) isStageOptions() {}
|
||||
|
||||
type GroupsStageOptionsGroup struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
GID *int `json:"gid,omitempty"`
|
||||
}
|
||||
|
||||
func NewGroupsStage(options *GroupsStageOptions) *Stage {
|
||||
return &Stage{
|
||||
Name: "org.osbuild.groups",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
||||
func NewGroupsStageOptions(groups []blueprint.GroupCustomization) *GroupsStageOptions {
|
||||
options := GroupsStageOptions{
|
||||
Groups: map[string]GroupsStageOptionsGroup{},
|
||||
}
|
||||
|
||||
for _, group := range groups {
|
||||
options.Groups[group.Name] = GroupsStageOptionsGroup{
|
||||
GID: group.GID,
|
||||
}
|
||||
}
|
||||
|
||||
return &options
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewGroupsStage(t *testing.T) {
|
||||
expectedStage := &Stage{
|
||||
Name: "org.osbuild.groups",
|
||||
Options: &GroupsStageOptions{},
|
||||
}
|
||||
actualStage := NewGroupsStage(&GroupsStageOptions{})
|
||||
assert.Equal(t, expectedStage, actualStage)
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import "github.com/google/uuid"
|
||||
|
||||
// The GRUB2StageOptions describes the bootloader configuration.
|
||||
//
|
||||
// The stage is responsible for installing all bootloader files in
|
||||
// /boot as well as config files in /etc necessary for regenerating
|
||||
// the configuration in /boot.
|
||||
//
|
||||
// Note that it is the role of an assembler to install any necessary
|
||||
// bootloaders that are stored in the image outside of any filesystem.
|
||||
type GRUB2StageOptions struct {
|
||||
RootFilesystemUUID uuid.UUID `json:"root_fs_uuid"`
|
||||
BootFilesystemUUID *uuid.UUID `json:"boot_fs_uuid,omitempty"`
|
||||
KernelOptions string `json:"kernel_opts,omitempty"`
|
||||
Legacy string `json:"legacy,omitempty"`
|
||||
UEFI *GRUB2UEFI `json:"uefi,omitempty"`
|
||||
SavedEntry string `json:"saved_entry,omitempty"`
|
||||
}
|
||||
|
||||
type GRUB2UEFI struct {
|
||||
Vendor string `json:"vendor"`
|
||||
}
|
||||
|
||||
func (GRUB2StageOptions) isStageOptions() {}
|
||||
|
||||
// NewGRUB2Stage creates a new GRUB2 stage object.
|
||||
func NewGRUB2Stage(options *GRUB2StageOptions) *Stage {
|
||||
return &Stage{
|
||||
Name: "org.osbuild.grub2",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewGRUB2Stage(t *testing.T) {
|
||||
expectedStage := &Stage{
|
||||
Name: "org.osbuild.grub2",
|
||||
Options: &GRUB2StageOptions{},
|
||||
}
|
||||
actualStage := NewGRUB2Stage(&GRUB2StageOptions{})
|
||||
assert.Equal(t, expectedStage, actualStage)
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
type HostnameStageOptions struct {
|
||||
Hostname string `json:"hostname"`
|
||||
}
|
||||
|
||||
func (HostnameStageOptions) isStageOptions() {}
|
||||
|
||||
func NewHostnameStage(options *HostnameStageOptions) *Stage {
|
||||
return &Stage{
|
||||
Name: "org.osbuild.hostname",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewHostnameStage(t *testing.T) {
|
||||
expectedStage := &Stage{
|
||||
Name: "org.osbuild.hostname",
|
||||
Options: &HostnameStageOptions{},
|
||||
}
|
||||
actualStage := NewHostnameStage(&HostnameStageOptions{})
|
||||
assert.Equal(t, expectedStage, actualStage)
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
// KernelCmdlineStageOptions describe how to create kernel-cmdline stage
|
||||
//
|
||||
// Configures the kernel boot parameters, also known as the kernel command line.
|
||||
type KernelCmdlineStageOptions struct {
|
||||
RootFsUUID string `json:"root_fs_uuid,omitempty"`
|
||||
KernelOpts string `json:"kernel_opts,omitempty"`
|
||||
}
|
||||
|
||||
func (KernelCmdlineStageOptions) isStageOptions() {}
|
||||
|
||||
// NewKernelCmdlineStage creates a new kernel-cmdline Stage object.
|
||||
func NewKernelCmdlineStage(options *KernelCmdlineStageOptions) *Stage {
|
||||
return &Stage{
|
||||
Name: "org.osbuild.kernel-cmdline",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewKernelCmdlineStage(t *testing.T) {
|
||||
expectedStage := &Stage{
|
||||
Name: "org.osbuild.kernel-cmdline",
|
||||
Options: &KernelCmdlineStageOptions{},
|
||||
}
|
||||
actualStage := NewKernelCmdlineStage(&KernelCmdlineStageOptions{})
|
||||
assert.Equal(t, expectedStage, actualStage)
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
type X11Keymap struct {
|
||||
Layouts []string `json:"layouts"`
|
||||
}
|
||||
|
||||
type KeymapStageOptions struct {
|
||||
Keymap string `json:"keymap"`
|
||||
X11Keymap *X11Keymap `json:"x11-keymap,omitempty"`
|
||||
}
|
||||
|
||||
func (KeymapStageOptions) isStageOptions() {}
|
||||
|
||||
func NewKeymapStage(options *KeymapStageOptions) *Stage {
|
||||
return &Stage{
|
||||
Name: "org.osbuild.keymap",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewKeymapStage(t *testing.T) {
|
||||
expectedStage := &Stage{
|
||||
Name: "org.osbuild.keymap",
|
||||
Options: &KeymapStageOptions{},
|
||||
}
|
||||
actualStage := NewKeymapStage(&KeymapStageOptions{})
|
||||
assert.Equal(t, expectedStage, actualStage)
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
// The LocaleStageOptions describes the image's locale.
|
||||
//
|
||||
// A locale is typically specified as language_[territory], where language
|
||||
// is specified in ISO 639 and territory in ISO 3166.
|
||||
type LocaleStageOptions struct {
|
||||
Language string `json:"language"`
|
||||
}
|
||||
|
||||
func (LocaleStageOptions) isStageOptions() {}
|
||||
|
||||
// NewLocaleStage creates a new Locale Stage object.
|
||||
func NewLocaleStage(options *LocaleStageOptions) *Stage {
|
||||
return &Stage{
|
||||
Name: "org.osbuild.locale",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewLocaleStage(t *testing.T) {
|
||||
expectedStage := &Stage{
|
||||
Name: "org.osbuild.locale",
|
||||
Options: &LocaleStageOptions{},
|
||||
}
|
||||
actualStage := NewLocaleStage(&LocaleStageOptions{})
|
||||
assert.Equal(t, expectedStage, actualStage)
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
// Package osbuild provides primitives for representing and (un)marshalling
|
||||
// OSBuild (schema v1) types.
|
||||
package osbuild1
|
||||
|
||||
// A Manifest represents an OSBuild source and pipeline manifest
|
||||
type Manifest struct {
|
||||
Sources Sources `json:"sources"`
|
||||
Pipeline Pipeline `json:"pipeline"`
|
||||
}
|
||||
|
||||
// A Pipeline represents an OSBuild pipeline
|
||||
type Pipeline struct {
|
||||
// The build environment which can run this pipeline
|
||||
Build *Build `json:"build,omitempty"`
|
||||
// Sequence of stages that produce the filesystem tree, which is the
|
||||
// payload of the produced image.
|
||||
Stages []*Stage `json:"stages,omitempty"`
|
||||
// Assembler that assembles the filesystem tree into the target image.
|
||||
Assembler *Assembler `json:"assembler,omitempty"`
|
||||
}
|
||||
|
||||
type Build struct {
|
||||
// Pipeline describes how to create the build root
|
||||
Pipeline *Pipeline `json:"pipeline"`
|
||||
// The runner to use in this build root
|
||||
Runner string `json:"runner"`
|
||||
}
|
||||
|
||||
// SetBuild sets the pipeline and runner for generating the build environment
|
||||
// for a pipeline.
|
||||
func (p *Pipeline) SetBuild(pipeline *Pipeline, runner string) {
|
||||
p.Build = &Build{
|
||||
Pipeline: pipeline,
|
||||
Runner: runner,
|
||||
}
|
||||
}
|
||||
|
||||
// AddStage appends a stage to the list of stages of a pipeline. The stages
|
||||
// will be executed in the order they are appended.
|
||||
func (p *Pipeline) AddStage(stage *Stage) {
|
||||
p.Stages = append(p.Stages, stage)
|
||||
}
|
||||
|
||||
// SetAssembler sets the assembler for a pipeline.
|
||||
func (p *Pipeline) SetAssembler(assembler *Assembler) {
|
||||
p.Assembler = assembler
|
||||
}
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
// Package osbuild provides primitives for representing and (un)marshalling
|
||||
// OSBuild types.
|
||||
package osbuild1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPipeline_SetBuild(t *testing.T) {
|
||||
expectedPipeline := &Pipeline{
|
||||
Build: &Build{
|
||||
Pipeline: &Pipeline{},
|
||||
Runner: "org.osbuild.fedora32",
|
||||
},
|
||||
}
|
||||
actualPipeline := &Pipeline{}
|
||||
actualPipeline.SetBuild(&Pipeline{}, "org.osbuild.fedora32")
|
||||
assert.Equal(t, expectedPipeline, actualPipeline)
|
||||
}
|
||||
|
||||
func TestPipeline_AddStage(t *testing.T) {
|
||||
expectedPipeline := &Pipeline{
|
||||
Build: &Build{
|
||||
Pipeline: &Pipeline{},
|
||||
Runner: "org.osbuild.fedora32",
|
||||
},
|
||||
Stages: []*Stage{
|
||||
{
|
||||
Name: "org.osbuild.rpm",
|
||||
},
|
||||
},
|
||||
}
|
||||
actualPipeline := &Pipeline{
|
||||
Build: &Build{
|
||||
Pipeline: &Pipeline{},
|
||||
Runner: "org.osbuild.fedora32",
|
||||
},
|
||||
}
|
||||
actualPipeline.AddStage(&Stage{
|
||||
Name: "org.osbuild.rpm",
|
||||
})
|
||||
assert.Equal(t, expectedPipeline, actualPipeline)
|
||||
assert.Equal(t, 1, len(actualPipeline.Stages))
|
||||
}
|
||||
|
||||
func TestPipeline_SetAssembler(t *testing.T) {
|
||||
expectedPipeline := &Pipeline{
|
||||
Assembler: &Assembler{
|
||||
Name: "org.osbuild.testassembler",
|
||||
},
|
||||
}
|
||||
actualPipeline := &Pipeline{}
|
||||
actualPipeline.SetAssembler(&Assembler{
|
||||
Name: "org.osbuild.testassembler",
|
||||
})
|
||||
assert.Equal(t, expectedPipeline, actualPipeline)
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
// OSTreeCommitAssemblerOptions desrcibe how to assemble a tree into an OSTree commit.
|
||||
type OSTreeCommitAssemblerOptions struct {
|
||||
Ref string `json:"ref"`
|
||||
Parent string `json:"parent,omitempty"`
|
||||
Tar OSTreeCommitAssemblerTarOptions `json:"tar"`
|
||||
}
|
||||
|
||||
// OSTreeCommitAssemblerTarOptions desrcibes the output tarball
|
||||
type OSTreeCommitAssemblerTarOptions struct {
|
||||
Filename string `json:"filename"`
|
||||
}
|
||||
|
||||
func (OSTreeCommitAssemblerOptions) isAssemblerOptions() {}
|
||||
|
||||
// NewOSTreeCommitAssembler creates a new OSTree Commit Assembler object.
|
||||
func NewOSTreeCommitAssembler(options *OSTreeCommitAssemblerOptions) *Assembler {
|
||||
return &Assembler{
|
||||
Name: "org.osbuild.ostree.commit",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
||||
type OSTreeCommitStageMetadata struct {
|
||||
Compose OSTreeCommitStageMetadataCompose `json:"compose"`
|
||||
}
|
||||
|
||||
type OSTreeCommitStageMetadataCompose struct {
|
||||
Ref string `json:"ref"`
|
||||
OSTreeNMetadataTotal int `json:"ostree-n-metadata-total"`
|
||||
OSTreeNMetadataWritten int `json:"ostree-n-metadata-written"`
|
||||
OSTreeNContentTotal int `json:"ostree-n-content-total"`
|
||||
OSTreeNContentWritten int `json:"ostree-n-content-written"`
|
||||
OSTreeNCacheHits int `json:"ostree-n-cache-hits"`
|
||||
OSTreeContentBytesWritten int `json:"ostree-content-bytes-written"`
|
||||
OSTreeCommit string `json:"ostree-commit"`
|
||||
OSTreeContentChecksum string `json:"ostree-content-checksum"`
|
||||
OSTreeTimestamp string `json:"ostree-timestamp"`
|
||||
RPMOSTreeInputHash string `json:"rpm-ostree-inputhash"`
|
||||
}
|
||||
|
||||
func (OSTreeCommitStageMetadata) isStageMetadata() {}
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import "github.com/osbuild/osbuild-composer/internal/disk"
|
||||
|
||||
type VMDKSubformat string
|
||||
|
||||
const (
|
||||
VMDKSubformatMonolithicSparse VMDKSubformat = "monolithicSparse"
|
||||
VMDKSubformatMonolithicFlat VMDKSubformat = "monolithicFlat"
|
||||
VMDKSubformatTwoGbMaxExtentSparse VMDKSubformat = "twoGbMaxExtentSparse"
|
||||
VMDKSubformatTwoGbMaxExtentFlat VMDKSubformat = "twoGbMaxExtentFlat"
|
||||
VMDKSubformatStreamOptimized VMDKSubformat = "streamOptimized"
|
||||
)
|
||||
|
||||
// QEMUAssemblerOptions desrcibe how to assemble a tree into an image using qemu.
|
||||
//
|
||||
// The assembler creates an image of the given size, adds a GRUB2 bootloader
|
||||
// and if necessary and a partition table to it with the given PTUUID
|
||||
// containing the indicated partitions. Finally, the image is converted into
|
||||
// the target format and stored with the given filename.
|
||||
type QEMUAssemblerOptions struct {
|
||||
Bootloader *QEMUBootloader `json:"bootloader,omitempty"`
|
||||
Format string `json:"format"`
|
||||
Qcow2Compat string `json:"qcow2_compat,omitempty"`
|
||||
VMDKSubformat VMDKSubformat `json:"vmdk_subformat,omitempty"`
|
||||
Filename string `json:"filename"`
|
||||
Size uint64 `json:"size"`
|
||||
PTUUID string `json:"ptuuid"`
|
||||
PTType string `json:"pttype"`
|
||||
Partitions []QEMUPartition `json:"partitions"`
|
||||
}
|
||||
|
||||
type QEMUPartition struct {
|
||||
Start uint64 `json:"start"`
|
||||
Size uint64 `json:"size,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Bootable bool `json:"bootable,omitempty"`
|
||||
UUID string `json:"uuid,omitempty"`
|
||||
Filesystem *QEMUFilesystem `json:"filesystem,omitempty"`
|
||||
}
|
||||
|
||||
type QEMUFilesystem struct {
|
||||
Type string `json:"type"`
|
||||
UUID string `json:"uuid"`
|
||||
Label string `json:"label,omitempty"`
|
||||
Mountpoint string `json:"mountpoint"`
|
||||
}
|
||||
|
||||
type QEMUBootloader struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Platform string `json:"platform,omitempty"`
|
||||
}
|
||||
|
||||
func (QEMUAssemblerOptions) isAssemblerOptions() {}
|
||||
|
||||
// NewQEMUAssembler creates a new QEMU Assembler object.
|
||||
func NewQEMUAssembler(options *QEMUAssemblerOptions) *Assembler {
|
||||
return &Assembler{
|
||||
Name: "org.osbuild.qemu",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
||||
// NewQEMUAssemblerOptions creates and returns QEMUAssemblerOptions based on
|
||||
// the given PartitionTable.
|
||||
func NewQEMUAssemblerOptions(pt *disk.PartitionTable) QEMUAssemblerOptions {
|
||||
var partitions []QEMUPartition
|
||||
for idx := range pt.Partitions {
|
||||
partitions = append(partitions, NewQEMUPartition(&pt.Partitions[idx]))
|
||||
}
|
||||
|
||||
return QEMUAssemblerOptions{
|
||||
Size: pt.Size,
|
||||
PTUUID: pt.UUID,
|
||||
PTType: pt.Type,
|
||||
Partitions: partitions,
|
||||
}
|
||||
}
|
||||
|
||||
// NewQEMUPartition creates and returns a QEMUPartition based on the given
|
||||
// Partition.
|
||||
func NewQEMUPartition(p *disk.Partition) QEMUPartition {
|
||||
var fs *QEMUFilesystem
|
||||
if p.Payload != nil {
|
||||
// NOTE: Partition Payload for QEMU assembler should always be a Filesystem
|
||||
f := NewQEMUFilesystem(p.Payload.(*disk.Filesystem))
|
||||
fs = &f
|
||||
}
|
||||
return QEMUPartition{
|
||||
Start: p.Start,
|
||||
Size: p.Size,
|
||||
Type: p.Type,
|
||||
Bootable: p.Bootable,
|
||||
UUID: p.UUID,
|
||||
Filesystem: fs,
|
||||
}
|
||||
}
|
||||
|
||||
// NewQEMUFilesystem creates and returns a QEMUFilesystem based on the given
|
||||
// Filesystem.
|
||||
func NewQEMUFilesystem(fs *disk.Filesystem) QEMUFilesystem {
|
||||
return QEMUFilesystem{
|
||||
Type: fs.Type,
|
||||
UUID: fs.UUID,
|
||||
Label: fs.Label,
|
||||
Mountpoint: fs.Mountpoint,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import "github.com/google/uuid"
|
||||
|
||||
// RawFSAssemblerOptions desrcibe how to assemble a tree into a raw filesystem
|
||||
// image.
|
||||
type RawFSAssemblerOptions struct {
|
||||
Filename string `json:"filename"`
|
||||
RootFilesystemUUID uuid.UUID `json:"root_fs_uuid"`
|
||||
Size uint64 `json:"size"`
|
||||
FilesystemType string `json:"fs_type,omitempty"`
|
||||
}
|
||||
|
||||
func (RawFSAssemblerOptions) isAssemblerOptions() {}
|
||||
|
||||
// NewRawFSAssembler creates a new RawFS Assembler object.
|
||||
func NewRawFSAssembler(options *RawFSAssemblerOptions) *Assembler {
|
||||
return &Assembler{
|
||||
Name: "org.osbuild.rawfs",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
type ResolvConfStageOptions struct {
|
||||
Nameserver []string `json:"nameserver,omitempty"`
|
||||
Search []string `json:"search,omitempty"`
|
||||
}
|
||||
|
||||
func (ResolvConfStageOptions) isStageOptions() {}
|
||||
|
||||
func NewResolvConfStage(options *ResolvConfStageOptions) *Stage {
|
||||
return &Stage{
|
||||
Name: "org.osbuild.resolv-conf",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewResolvConfStageStage(t *testing.T) {
|
||||
expectedStage := &Stage{
|
||||
Name: "org.osbuild.resolv-conf",
|
||||
Options: &ResolvConfStageOptions{},
|
||||
}
|
||||
actualStage := NewResolvConfStage(&ResolvConfStageOptions{})
|
||||
assert.Equal(t, expectedStage, actualStage)
|
||||
}
|
||||
|
|
@ -1,130 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type StageResult struct {
|
||||
Name string `json:"name"`
|
||||
Options json.RawMessage `json:"options"`
|
||||
Success bool `json:"success"`
|
||||
Output string `json:"output"`
|
||||
Metadata StageMetadata `json:"metadata"`
|
||||
}
|
||||
|
||||
// StageMetadata specify the metadata of a given stage-type.
|
||||
type StageMetadata interface {
|
||||
isStageMetadata()
|
||||
}
|
||||
|
||||
type RawStageMetadata json.RawMessage
|
||||
|
||||
func (RawStageMetadata) isStageMetadata() {}
|
||||
|
||||
type rawStageResult struct {
|
||||
Name string `json:"name"`
|
||||
Options json.RawMessage `json:"options"`
|
||||
Success bool `json:"success"`
|
||||
Output string `json:"output"`
|
||||
Metadata json.RawMessage `json:"metadata"`
|
||||
}
|
||||
|
||||
type buildResult struct {
|
||||
Stages []StageResult `json:"stages"`
|
||||
TreeID string `json:"tree_id"`
|
||||
Success bool `json:"success"`
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
TreeID string `json:"tree_id"`
|
||||
OutputID string `json:"output_id"`
|
||||
Build *buildResult `json:"build"`
|
||||
Stages []StageResult `json:"stages"`
|
||||
Assembler *StageResult `json:"assembler"`
|
||||
Success bool `json:"success"`
|
||||
}
|
||||
|
||||
func (result *StageResult) UnmarshalJSON(data []byte) error {
|
||||
var rawStageResult rawStageResult
|
||||
err := json.Unmarshal(data, &rawStageResult)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var metadata StageMetadata
|
||||
switch {
|
||||
case strings.HasSuffix(rawStageResult.Name, "org.osbuild.rpm"):
|
||||
metadata = new(RPMStageMetadata)
|
||||
err = json.Unmarshal(rawStageResult.Metadata, metadata)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case strings.HasSuffix(rawStageResult.Name, "org.osbuild.ostree.commit"):
|
||||
metadata = new(OSTreeCommitStageMetadata)
|
||||
err = json.Unmarshal(rawStageResult.Metadata, metadata)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
metadata = RawStageMetadata(rawStageResult.Metadata)
|
||||
}
|
||||
|
||||
result.Name = rawStageResult.Name
|
||||
result.Options = rawStageResult.Options
|
||||
result.Success = rawStageResult.Success
|
||||
result.Output = rawStageResult.Output
|
||||
result.Metadata = metadata
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cr *Result) Write(writer io.Writer) error {
|
||||
if cr == nil || (cr.Build == nil && len(cr.Stages) == 0 && cr.Assembler == nil) {
|
||||
fmt.Fprintf(writer, "The compose result is empty.\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
if cr.Build != nil {
|
||||
fmt.Fprintf(writer, "Build pipeline:\n")
|
||||
|
||||
for _, stage := range cr.Build.Stages {
|
||||
fmt.Fprintf(writer, "Stage %s\n", stage.Name)
|
||||
enc := json.NewEncoder(writer)
|
||||
enc.SetIndent("", " ")
|
||||
err := enc.Encode(stage.Options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(writer, "\nOutput:\n%s\n", stage.Output)
|
||||
}
|
||||
}
|
||||
|
||||
if len(cr.Stages) > 0 {
|
||||
fmt.Fprintf(writer, "Stages:\n")
|
||||
for _, stage := range cr.Stages {
|
||||
fmt.Fprintf(writer, "Stage: %s\n", stage.Name)
|
||||
enc := json.NewEncoder(writer)
|
||||
enc.SetIndent("", " ")
|
||||
err := enc.Encode(stage.Options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(writer, "\nOutput:\n%s\n", stage.Output)
|
||||
}
|
||||
}
|
||||
|
||||
if cr.Assembler != nil {
|
||||
fmt.Fprintf(writer, "Assembler %s:\n", cr.Assembler.Name)
|
||||
enc := json.NewEncoder(writer)
|
||||
enc.SetIndent("", " ")
|
||||
err := enc.Encode(cr.Assembler.Options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(writer, "\nOutput:\n%s\n", cr.Assembler.Output)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,168 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUnmarshal(t *testing.T) {
|
||||
resultRaw := `{
|
||||
"success": true,
|
||||
"build": {
|
||||
"success": true,
|
||||
"stages": [
|
||||
{
|
||||
"name": "org.osbuild.rpm",
|
||||
"id": "9eb0a6f6fd6e2995e107f5bcc6aa3b19643b02ec133bdc8a8ac614860b1bbf2d",
|
||||
"success": true,
|
||||
"output": "Building...",
|
||||
"metadata": {
|
||||
"packages": [
|
||||
{
|
||||
"name": "libgcc",
|
||||
"version": "10.0.1",
|
||||
"release": "0.11.fc32",
|
||||
"epoch": null,
|
||||
"arch": "x86_64",
|
||||
"sigmd5": "84fc907a5047aeebaf8da1642925a417",
|
||||
"sigpgp": null,
|
||||
"siggpg": "883f0305005f2310139ec3e4c0f7e257e611023e11009f639c5fe64abaa76224dab3a9f70c2714a84c63bd009d1cc184fb4b428dfcd7c3556f4a5f860cc0187740"
|
||||
},
|
||||
{
|
||||
"name": "whois-nls",
|
||||
"version": "5.5.6",
|
||||
"release": "1.fc32",
|
||||
"epoch": null,
|
||||
"arch": "noarch",
|
||||
"sigmd5": "f868cd02046630c8ce3a9c48820e2437",
|
||||
"sigpgp": "89023304000108001d162104963a2beb02009608fe67ea4249fd77499570ff3105025f5a272b000a091049fd77499570ff31ccdb0ffe38b95a55ebf3c021526b3cd4f2358c7e23f7767d1f5ce4b7cccef7b33653c6a96a23022313a818fbaf7abeb41837910f0d3ac15664e02838d5939d38ff459aa0076e248728a032d3ae09ddfaec955f941601081a2e3f9bbd49586fd65c1bc1b31685aeb0405687d1791471eab7359ccf00d5584ddef680e99ebc8a4846316391b9baa68ac8ed8ad696ee16fd625d847f8edd92517df3ea6920a46b77b4f119715a0f619f38835d25e0bd0eb5cfad08cd9c796eace6a2b28f4d3dee552e6068255d9748dc2a1906c951e0ba8aed9922ab24e1f659413a06083f8a0bfea56cfff14bddef23bced449f36bcd369da72f90ddf0512e7b0801ba5a0c8eaa8eb0582c630815e992192042cfb0a7c7239f76219197c2fdf18b6553260c105280806d4f037d7b04bdf3da9fd7e9a207db5c71f7e548f4288928f047c989c4cb9cbb8088eec7bd2fa5c252e693f51a3cfc660f666af6a255a5ca0fd2216d5ccd66cbd9c11afa61067d7f615ec8d0dc0c879b5fe633d8c9443f97285da597e4da8a3993af36f0be06acfa9b8058ec70bbc78b876e4c6c5d2108fb05c15a74ba48a3d7ded697cbc1748c228d77d1e0794a41fd5240fa67c3ed745fe47555a47c3d6163d8ce95fd6c2d0d6fa48f8e5b411e571e442109b1cb200d9a8117ee08bfe645f96aca34f7b7559622bbab75143dcad59f126ae0d319e6668ebba417e725638c4febf2e",
|
||||
"siggpg": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}`
|
||||
|
||||
var result Result
|
||||
err := json.Unmarshal([]byte(resultRaw), &result)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, result.Build.Stages[0].Name, "org.osbuild.rpm")
|
||||
metadata, ok := result.Build.Stages[0].Metadata.(*RPMStageMetadata)
|
||||
assert.True(t, ok)
|
||||
package1 := metadata.Packages[0]
|
||||
assert.Equal(t, package1.Name, "libgcc")
|
||||
assert.Nil(t, package1.Epoch)
|
||||
assert.Equal(t, package1.Version, "10.0.1")
|
||||
assert.Equal(t, package1.Release, "0.11.fc32")
|
||||
assert.Equal(t, package1.Arch, "x86_64")
|
||||
assert.Equal(t, package1.SigMD5, "84fc907a5047aeebaf8da1642925a417")
|
||||
assert.Empty(t, package1.SigPGP)
|
||||
assert.Equal(t, package1.SigGPG, "883f0305005f2310139ec3e4c0f7e257e611023e11009f639c5fe64abaa76224dab3a9f70c2714a84c63bd009d1cc184fb4b428dfcd7c3556f4a5f860cc0187740")
|
||||
|
||||
package2 := metadata.Packages[1]
|
||||
assert.Equal(t, package2.SigPGP, "89023304000108001d162104963a2beb02009608fe67ea4249fd77499570ff3105025f5a272b000a091049fd77499570ff31ccdb0ffe38b95a55ebf3c021526b3cd4f2358c7e23f7767d1f5ce4b7cccef7b33653c6a96a23022313a818fbaf7abeb41837910f0d3ac15664e02838d5939d38ff459aa0076e248728a032d3ae09ddfaec955f941601081a2e3f9bbd49586fd65c1bc1b31685aeb0405687d1791471eab7359ccf00d5584ddef680e99ebc8a4846316391b9baa68ac8ed8ad696ee16fd625d847f8edd92517df3ea6920a46b77b4f119715a0f619f38835d25e0bd0eb5cfad08cd9c796eace6a2b28f4d3dee552e6068255d9748dc2a1906c951e0ba8aed9922ab24e1f659413a06083f8a0bfea56cfff14bddef23bced449f36bcd369da72f90ddf0512e7b0801ba5a0c8eaa8eb0582c630815e992192042cfb0a7c7239f76219197c2fdf18b6553260c105280806d4f037d7b04bdf3da9fd7e9a207db5c71f7e548f4288928f047c989c4cb9cbb8088eec7bd2fa5c252e693f51a3cfc660f666af6a255a5ca0fd2216d5ccd66cbd9c11afa61067d7f615ec8d0dc0c879b5fe633d8c9443f97285da597e4da8a3993af36f0be06acfa9b8058ec70bbc78b876e4c6c5d2108fb05c15a74ba48a3d7ded697cbc1748c228d77d1e0794a41fd5240fa67c3ed745fe47555a47c3d6163d8ce95fd6c2d0d6fa48f8e5b411e571e442109b1cb200d9a8117ee08bfe645f96aca34f7b7559622bbab75143dcad59f126ae0d319e6668ebba417e725638c4febf2e")
|
||||
assert.Empty(t, package2.SigGPG)
|
||||
}
|
||||
|
||||
func TestWriteFull(t *testing.T) {
|
||||
|
||||
const testOptions = `{"msg": "test"}`
|
||||
|
||||
dnfStage := StageResult{
|
||||
Name: "org.osbuild.rpm",
|
||||
Options: []byte(testOptions),
|
||||
Success: true,
|
||||
Output: "Finished",
|
||||
Metadata: RPMStageMetadata{
|
||||
Packages: []RPMPackageMetadata{
|
||||
{
|
||||
Name: "foobar",
|
||||
Epoch: nil,
|
||||
Version: "1",
|
||||
Release: "1",
|
||||
Arch: "noarch",
|
||||
SigMD5: "deadbeef",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
testStage := StageResult{
|
||||
Name: "org.osbuild.test",
|
||||
Options: []byte(testOptions),
|
||||
Success: true,
|
||||
Output: "Finished",
|
||||
}
|
||||
|
||||
testBuild := buildResult{
|
||||
Stages: []StageResult{testStage},
|
||||
TreeID: "treeID",
|
||||
Success: true,
|
||||
}
|
||||
|
||||
testAssembler := StageResult{
|
||||
Name: "testAssembler",
|
||||
Options: []byte(testOptions),
|
||||
Success: true,
|
||||
Output: "Done",
|
||||
}
|
||||
|
||||
testComposeResult := Result{
|
||||
TreeID: "TreeID",
|
||||
OutputID: "OutputID",
|
||||
Build: &testBuild,
|
||||
Stages: []StageResult{dnfStage},
|
||||
Assembler: &testAssembler,
|
||||
Success: true,
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
assert.NoError(t, testComposeResult.Write(&b))
|
||||
expectedMessage :=
|
||||
`Build pipeline:
|
||||
Stage org.osbuild.test
|
||||
{
|
||||
"msg": "test"
|
||||
}
|
||||
|
||||
Output:
|
||||
Finished
|
||||
Stages:
|
||||
Stage: org.osbuild.rpm
|
||||
{
|
||||
"msg": "test"
|
||||
}
|
||||
|
||||
Output:
|
||||
Finished
|
||||
Assembler testAssembler:
|
||||
{
|
||||
"msg": "test"
|
||||
}
|
||||
|
||||
Output:
|
||||
Done
|
||||
`
|
||||
assert.Equal(t, expectedMessage, b.String())
|
||||
}
|
||||
|
||||
func TestWriteEmpty(t *testing.T) {
|
||||
var b bytes.Buffer
|
||||
|
||||
var testNilResult *Result
|
||||
assert.NoError(t, testNilResult.Write(&b))
|
||||
assert.Equal(t, "The compose result is empty.\n", b.String())
|
||||
|
||||
testComposeResult := Result{}
|
||||
|
||||
b.Reset()
|
||||
assert.NoError(t, testComposeResult.Write(&b))
|
||||
assert.Equal(t, "The compose result is empty.\n", b.String())
|
||||
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
// RHSMStageOptions describes configuration of the RHSM stage.
|
||||
//
|
||||
// The RHSM stage allows configuration of Red Hat Subscription Manager (RHSM)
|
||||
// related components. Currently it allows only configuration of the enablement
|
||||
// state of DNF plugins used by the Subscription Manager.
|
||||
type RHSMStageOptions struct {
|
||||
DnfPlugins *RHSMStageOptionsDnfPlugins `json:"dnf-plugins,omitempty"`
|
||||
}
|
||||
|
||||
func (RHSMStageOptions) isStageOptions() {}
|
||||
|
||||
// RHSMStageOptionsDnfPlugins describes configuration of all RHSM DNF plugins
|
||||
type RHSMStageOptionsDnfPlugins struct {
|
||||
ProductID *RHSMStageOptionsDnfPlugin `json:"product-id,omitempty"`
|
||||
SubscriptionManager *RHSMStageOptionsDnfPlugin `json:"subscription-manager,omitempty"`
|
||||
}
|
||||
|
||||
// RHSMStageOptionsDnfPlugin describes configuration of a specific RHSM DNF
|
||||
// plugin
|
||||
//
|
||||
// Only the enablement state of a DNF plugin can be currenlty set.
|
||||
type RHSMStageOptionsDnfPlugin struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
// NewRHSMStage creates a new RHSM stage
|
||||
func NewRHSMStage(options *RHSMStageOptions) *Stage {
|
||||
return &Stage{
|
||||
Name: "org.osbuild.rhsm",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewRhsmStage(t *testing.T) {
|
||||
expectedStage := &Stage{
|
||||
Name: "org.osbuild.rhsm",
|
||||
Options: &RHSMStageOptions{},
|
||||
}
|
||||
actualStage := NewRHSMStage(&RHSMStageOptions{})
|
||||
assert.Equal(t, expectedStage, actualStage)
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
// RPMOSTreeStageOptions configures the invocation of the `rpm-ostree`
|
||||
// process for generating an ostree commit.
|
||||
type RPMOSTreeStageOptions struct {
|
||||
EtcGroupMembers []string `json:"etc_group_members,omitempty"`
|
||||
}
|
||||
|
||||
func (RPMOSTreeStageOptions) isStageOptions() {}
|
||||
|
||||
// NewRPMOSTreeStage creates a new rpm-ostree Stage object.
|
||||
func NewRPMOSTreeStage(options *RPMOSTreeStageOptions) *Stage {
|
||||
return &Stage{
|
||||
Name: "org.osbuild.rpm-ostree",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
// The RPMStageOptions describe the operations of the RPM stage.
|
||||
//
|
||||
// The RPM stage installs a given set of packages, identified by their
|
||||
// content hash. This ensures that given a set of RPM stage options,
|
||||
// the output is be reproducible, if the underlying tools are.
|
||||
type RPMStageOptions struct {
|
||||
GPGKeys []string `json:"gpgkeys,omitempty"`
|
||||
Packages []RPMPackage `json:"packages"`
|
||||
}
|
||||
|
||||
// RPMPackage represents one RPM, as referenced by its content hash
|
||||
// (checksum). The files source must indicate where to fetch the given
|
||||
// RPM. If CheckGPG is `true` the RPM must be signed with one of the
|
||||
// GPGKeys given in the RPMStageOptions.
|
||||
type RPMPackage struct {
|
||||
Checksum string `json:"checksum"`
|
||||
CheckGPG bool `json:"check_gpg,omitempty"`
|
||||
}
|
||||
|
||||
func (RPMStageOptions) isStageOptions() {}
|
||||
|
||||
// NewRPMStage creates a new RPM stage.
|
||||
func NewRPMStage(options *RPMStageOptions) *Stage {
|
||||
return &Stage{
|
||||
Name: "org.osbuild.rpm",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
||||
// RPMStageMetadata gives the set of packages installed by the RPM stage
|
||||
type RPMStageMetadata struct {
|
||||
Packages []RPMPackageMetadata `json:"packages"`
|
||||
}
|
||||
|
||||
// RPMPackageMetadata contains the metadata extracted from one RPM header
|
||||
type RPMPackageMetadata struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Release string `json:"release"`
|
||||
Epoch *string `json:"epoch"`
|
||||
Arch string `json:"arch"`
|
||||
SigMD5 string `json:"sigmd5"`
|
||||
SigPGP string `json:"sigpgp"`
|
||||
SigGPG string `json:"siggpg"`
|
||||
}
|
||||
|
||||
func (RPMStageMetadata) isStageMetadata() {}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewRPMStage(t *testing.T) {
|
||||
expectedStage := &Stage{
|
||||
Name: "org.osbuild.rpm",
|
||||
Options: &RPMStageOptions{},
|
||||
}
|
||||
actualStage := NewRPMStage(&RPMStageOptions{})
|
||||
assert.Equal(t, expectedStage, actualStage)
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
// The ScriptStageOptions specifies a custom script to run in the image
|
||||
type ScriptStageOptions struct {
|
||||
Script string `json:"script"`
|
||||
}
|
||||
|
||||
func (ScriptStageOptions) isStageOptions() {}
|
||||
|
||||
// NewScriptStageOptions creates a new script stage options object, with
|
||||
// the mandatory fields set.
|
||||
func NewScriptStageOptions(script string) *ScriptStageOptions {
|
||||
return &ScriptStageOptions{
|
||||
Script: script,
|
||||
}
|
||||
}
|
||||
|
||||
// NewScriptStage creates a new Script Stage object.
|
||||
func NewScriptStage(options *ScriptStageOptions) *Stage {
|
||||
return &Stage{
|
||||
Name: "org.osbuild.script",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewScriptStageOptions(t *testing.T) {
|
||||
expectedOptions := &ScriptStageOptions{
|
||||
Script: "/root/test.sh",
|
||||
}
|
||||
actualOptions := NewScriptStageOptions("/root/test.sh")
|
||||
assert.Equal(t, expectedOptions, actualOptions)
|
||||
}
|
||||
|
||||
func TestNewScriptStage(t *testing.T) {
|
||||
expectedStage := &Stage{
|
||||
Name: "org.osbuild.script",
|
||||
Options: &ScriptStageOptions{},
|
||||
}
|
||||
actualStage := NewScriptStage(&ScriptStageOptions{})
|
||||
assert.Equal(t, expectedStage, actualStage)
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
// The SELinuxStageOptions describe how to apply selinux labels.
|
||||
//
|
||||
// A file contexts configuration file is sepcified that describes
|
||||
// the filesystem labels to apply to the image.
|
||||
type SELinuxStageOptions struct {
|
||||
FileContexts string `json:"file_contexts"`
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
}
|
||||
|
||||
func (SELinuxStageOptions) isStageOptions() {}
|
||||
|
||||
// NewSELinuxStageOptions creates a new SELinuxStaeOptions object, with
|
||||
// the mandatory fields set.
|
||||
func NewSELinuxStageOptions(fileContexts string) *SELinuxStageOptions {
|
||||
return &SELinuxStageOptions{
|
||||
FileContexts: fileContexts,
|
||||
}
|
||||
}
|
||||
|
||||
// NewSELinuxStage creates a new SELinux Stage object.
|
||||
func NewSELinuxStage(options *SELinuxStageOptions) *Stage {
|
||||
return &Stage{
|
||||
Name: "org.osbuild.selinux",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewSELinuxStageOptions(t *testing.T) {
|
||||
expectedOptions := &SELinuxStageOptions{
|
||||
FileContexts: "etc/selinux/targeted/contexts/files/file_contexts",
|
||||
}
|
||||
actualOptions := NewSELinuxStageOptions("etc/selinux/targeted/contexts/files/file_contexts")
|
||||
assert.Equal(t, expectedOptions, actualOptions)
|
||||
}
|
||||
|
||||
func TestNewSELinuxStage(t *testing.T) {
|
||||
expectedStage := &Stage{
|
||||
Name: "org.osbuild.selinux",
|
||||
Options: &SELinuxStageOptions{},
|
||||
}
|
||||
actualStage := NewSELinuxStage(&SELinuxStageOptions{})
|
||||
assert.Equal(t, expectedStage, actualStage)
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// A Sources map contains all the sources made available to an osbuild run
|
||||
type Sources map[string]Source
|
||||
|
||||
// Source specifies the operations of a given source-type.
|
||||
type Source interface {
|
||||
isSource()
|
||||
}
|
||||
|
||||
type rawSources map[string]json.RawMessage
|
||||
|
||||
// UnmarshalJSON unmarshals JSON into a Source object. Each type of source has
|
||||
// a custom unmarshaller for its options, selected based on the source name.
|
||||
func (sources *Sources) UnmarshalJSON(data []byte) error {
|
||||
var rawSources rawSources
|
||||
err := json.Unmarshal(data, &rawSources)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*sources = make(map[string]Source)
|
||||
for name, rawSource := range rawSources {
|
||||
var source Source
|
||||
switch name {
|
||||
case "org.osbuild.files":
|
||||
source = new(FilesSource)
|
||||
default:
|
||||
return errors.New("unexpected source name: " + name)
|
||||
}
|
||||
err = json.Unmarshal(rawSource, source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
(*sources)[name] = source
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,100 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSource_UnmarshalJSON(t *testing.T) {
|
||||
type fields struct {
|
||||
Name string
|
||||
Source Source
|
||||
}
|
||||
type args struct {
|
||||
data []byte
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "invalid json",
|
||||
args: args{
|
||||
data: []byte(`{"name":"org.osbuild.foo","options":{"bar":null}`),
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "unknown source",
|
||||
args: args{
|
||||
data: []byte(`{"name":"org.osbuild.foo","options":{"bar":null}}`),
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "missing options",
|
||||
args: args{
|
||||
data: []byte(`{"name":"org.osbuild.files"}`),
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "missing name",
|
||||
args: args{
|
||||
data: []byte(`{"foo":null,"options":{"bar":null}}`),
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "files-empty",
|
||||
fields: fields{
|
||||
Name: "org.osbuild.files",
|
||||
Source: &FilesSource{URLs: map[string]FileSource{}},
|
||||
},
|
||||
args: args{
|
||||
data: []byte(`{"org.osbuild.files":{"urls":{}}}`),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "files",
|
||||
fields: fields{
|
||||
Name: "org.osbuild.files",
|
||||
Source: &FilesSource{URLs: map[string]FileSource{
|
||||
"checksum1": FileSource{URL: "url1"},
|
||||
"checksum2": FileSource{URL: "url2"},
|
||||
}},
|
||||
},
|
||||
args: args{
|
||||
data: []byte(`{"org.osbuild.files":{"urls":{"checksum1":{"url":"url1"},"checksum2":{"url":"url2"}}}}`),
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
sources := &Sources{
|
||||
tt.fields.Name: tt.fields.Source,
|
||||
}
|
||||
var gotSources Sources
|
||||
if err := gotSources.UnmarshalJSON(tt.args.data); (err != nil) != tt.wantErr {
|
||||
t.Errorf("Sources.UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
if tt.wantErr {
|
||||
return
|
||||
}
|
||||
gotBytes, err := json.Marshal(sources)
|
||||
if err != nil {
|
||||
t.Errorf("Could not marshal source: %v", err)
|
||||
}
|
||||
if !bytes.Equal(gotBytes, tt.args.data) {
|
||||
t.Errorf("Expected '%v', got '%v'", string(tt.args.data), string(gotBytes))
|
||||
}
|
||||
if !reflect.DeepEqual(&gotSources, sources) {
|
||||
t.Errorf("got '%v', expected '%v'", &gotSources, sources)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
// A Stage transforms a filesystem tree.
|
||||
type Stage struct {
|
||||
// Well-known name in reverse domain-name notation, uniquely identifying
|
||||
// the stage type.
|
||||
Name string `json:"name"`
|
||||
// Stage-type specific options fully determining the operations of the
|
||||
// stage.
|
||||
Options StageOptions `json:"options"`
|
||||
}
|
||||
|
||||
// StageOptions specify the operations of a given stage-type.
|
||||
type StageOptions interface {
|
||||
isStageOptions()
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
type SysconfigStageOptions struct {
|
||||
Kernel SysconfigKernelOptions `json:"kernel,omitempty"`
|
||||
Network SysconfigNetworkOptions `json:"network,omitempty"`
|
||||
}
|
||||
|
||||
type SysconfigNetworkOptions struct {
|
||||
Networking bool `json:"networking,omitempty"`
|
||||
NoZeroConf bool `json:"no_zero_conf,omitempty"`
|
||||
}
|
||||
|
||||
type SysconfigKernelOptions struct {
|
||||
UpdateDefault bool `json:"update_default,omitempty"`
|
||||
DefaultKernel string `json:"default_kernel,omitempty"`
|
||||
}
|
||||
|
||||
func (SysconfigStageOptions) isStageOptions() {}
|
||||
|
||||
func NewSysconfigStage(options *SysconfigStageOptions) *Stage {
|
||||
return &Stage{
|
||||
Name: "org.osbuild.sysconfig",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewSysconfigStage(t *testing.T) {
|
||||
expectedStage := &Stage{
|
||||
Name: "org.osbuild.sysconfig",
|
||||
Options: &SysconfigStageOptions{},
|
||||
}
|
||||
actualStage := NewSysconfigStage(&SysconfigStageOptions{})
|
||||
assert.Equal(t, expectedStage, actualStage)
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
type SystemdStageOptions struct {
|
||||
EnabledServices []string `json:"enabled_services,omitempty"`
|
||||
DisabledServices []string `json:"disabled_services,omitempty"`
|
||||
DefaultTarget string `json:"default_target,omitempty"`
|
||||
}
|
||||
|
||||
func (SystemdStageOptions) isStageOptions() {}
|
||||
|
||||
func NewSystemdStage(options *SystemdStageOptions) *Stage {
|
||||
return &Stage{
|
||||
Name: "org.osbuild.systemd",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewSystemdStage(t *testing.T) {
|
||||
expectedStage := &Stage{
|
||||
Name: "org.osbuild.systemd",
|
||||
Options: &SystemdStageOptions{},
|
||||
}
|
||||
actualStage := NewSystemdStage(&SystemdStageOptions{})
|
||||
assert.Equal(t, expectedStage, actualStage)
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
// TarAssemblerOptions desrcibe how to assemble a tree into a tar ball.
|
||||
//
|
||||
// The assembler tars and optionally compresses the tree using the provided
|
||||
// compression type, and stores the output with the given filename.
|
||||
type TarAssemblerOptions struct {
|
||||
Filename string `json:"filename"`
|
||||
Compression string `json:"compression,omitempty"`
|
||||
}
|
||||
|
||||
func (TarAssemblerOptions) isAssemblerOptions() {}
|
||||
|
||||
// NewTarAssembler creates a new Tar Assembler object.
|
||||
func NewTarAssembler(options *TarAssemblerOptions) *Assembler {
|
||||
return &Assembler{
|
||||
Name: "org.osbuild.tar",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
type TimezoneStageOptions struct {
|
||||
Zone string `json:"zone"`
|
||||
}
|
||||
|
||||
func (TimezoneStageOptions) isStageOptions() {}
|
||||
|
||||
func NewTimezoneStage(options *TimezoneStageOptions) *Stage {
|
||||
return &Stage{
|
||||
Name: "org.osbuild.timezone",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewTimezoneStage(t *testing.T) {
|
||||
expectedStage := &Stage{
|
||||
Name: "org.osbuild.timezone",
|
||||
Options: &TimezoneStageOptions{},
|
||||
}
|
||||
actualStage := NewTimezoneStage(&TimezoneStageOptions{})
|
||||
assert.Equal(t, expectedStage, actualStage)
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"github.com/osbuild/osbuild-composer/internal/blueprint"
|
||||
"github.com/osbuild/osbuild-composer/internal/crypt"
|
||||
)
|
||||
|
||||
type UsersStageOptions struct {
|
||||
Users map[string]UsersStageOptionsUser `json:"users"`
|
||||
}
|
||||
|
||||
func (UsersStageOptions) isStageOptions() {}
|
||||
|
||||
type UsersStageOptionsUser struct {
|
||||
UID *int `json:"uid,omitempty"`
|
||||
GID *int `json:"gid,omitempty"`
|
||||
Groups []string `json:"groups,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Home *string `json:"home,omitempty"`
|
||||
Shell *string `json:"shell,omitempty"`
|
||||
Password *string `json:"password,omitempty"`
|
||||
Key *string `json:"key,omitempty"`
|
||||
}
|
||||
|
||||
func NewUsersStage(options *UsersStageOptions) *Stage {
|
||||
return &Stage{
|
||||
Name: "org.osbuild.users",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
||||
func NewUsersStageOptions(userCustomizations []blueprint.UserCustomization) (*UsersStageOptions, error) {
|
||||
if len(userCustomizations) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
users := make(map[string]UsersStageOptionsUser, len(userCustomizations))
|
||||
for _, uc := range userCustomizations {
|
||||
if uc.Password != nil && !crypt.PasswordIsCrypted(*uc.Password) {
|
||||
cryptedPassword, err := crypt.CryptSHA512(*uc.Password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
uc.Password = &cryptedPassword
|
||||
}
|
||||
|
||||
user := UsersStageOptionsUser{
|
||||
UID: uc.UID,
|
||||
GID: uc.GID,
|
||||
Groups: uc.Groups,
|
||||
Description: uc.Description,
|
||||
Home: uc.Home,
|
||||
Shell: uc.Shell,
|
||||
Password: uc.Password,
|
||||
Key: uc.Key,
|
||||
}
|
||||
users[uc.Name] = user
|
||||
}
|
||||
|
||||
return &UsersStageOptions{Users: users}, nil
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewUsersStage(t *testing.T) {
|
||||
expectedStage := &Stage{
|
||||
Name: "org.osbuild.users",
|
||||
Options: &UsersStageOptions{},
|
||||
}
|
||||
actualStage := NewUsersStage(&UsersStageOptions{})
|
||||
assert.Equal(t, expectedStage, actualStage)
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
// The ZiplStageOptions describe how to create zipl stage
|
||||
//
|
||||
// The only configuration option available is a boot timeout and it is optional
|
||||
type ZiplStageOptions struct {
|
||||
Timeout int `json:"timeout,omitempty"`
|
||||
}
|
||||
|
||||
func (ZiplStageOptions) isStageOptions() {}
|
||||
|
||||
// NewZiplStageOptions creates a new ZiplStageOptions object with no timeout
|
||||
func NewZiplStageOptions() *ZiplStageOptions {
|
||||
return &ZiplStageOptions{
|
||||
Timeout: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// NewZiplStage creates a new zipl Stage object.
|
||||
func NewZiplStage(options *ZiplStageOptions) *Stage {
|
||||
return &Stage{
|
||||
Name: "org.osbuild.zipl",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
package osbuild1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewZiplStageOptions(t *testing.T) {
|
||||
expectedOptions := &ZiplStageOptions{
|
||||
Timeout: 0,
|
||||
}
|
||||
actualOptions := NewZiplStageOptions()
|
||||
assert.Equal(t, expectedOptions, actualOptions)
|
||||
}
|
||||
|
||||
func TestNewZiplStage(t *testing.T) {
|
||||
expectedStage := &Stage{
|
||||
Name: "org.osbuild.zipl",
|
||||
Options: &ZiplStageOptions{},
|
||||
}
|
||||
actualStage := NewZiplStage(&ZiplStageOptions{})
|
||||
assert.Equal(t, expectedStage, actualStage)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue