diff --git a/cmd/otk/osbuild-gen-partition-table/export_test.go b/cmd/otk/osbuild-gen-partition-table/export_test.go deleted file mode 100644 index daa9ad1b60..0000000000 --- a/cmd/otk/osbuild-gen-partition-table/export_test.go +++ /dev/null @@ -1,6 +0,0 @@ -package main - -var ( - Run = run - GenPartitionTable = genPartitionTable -) diff --git a/cmd/otk/osbuild-gen-partition-table/main.go b/cmd/otk/osbuild-gen-partition-table/main.go deleted file mode 100644 index 368b8cda78..0000000000 --- a/cmd/otk/osbuild-gen-partition-table/main.go +++ /dev/null @@ -1,319 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io" - "math/rand" - "os" - - "github.com/osbuild/blueprint/pkg/blueprint" - "github.com/osbuild/images/internal/buildconfig" - "github.com/osbuild/images/internal/cmdutil" - "github.com/osbuild/images/internal/otkdisk" - "github.com/osbuild/images/pkg/arch" - "github.com/osbuild/images/pkg/datasizes" - "github.com/osbuild/images/pkg/disk" - "github.com/osbuild/images/pkg/disk/partition" - "github.com/osbuild/images/pkg/osbuild" -) - -// Tree is the wrapper aroudn the "real" input -type Tree struct { - Tree Input `json:"tree"` -} - -// Input represents the user provided inputs that will be used -// to generate the partition table -type Input struct { - Properties InputProperties `json:"properties"` - Partitions []*InputPartition `json:"partitions"` - - Modifications InputModifications `json:"modifications"` -} - -// InputProperties contains global properties of the partition table -type InputProperties struct { - Type otkdisk.PartType `json:"type"` - Architecture string `json:"architecture"` - DefaultSize string `json:"default_size"` - UUID string `json:"uuid"` - StartOffset string `json:"start_offset"` - Create InputCreate `json:"create"` - - SectorSize uint64 `json:"sector_size"` -} - -// InputCreate contains details what partitions to auto-generate -type InputCreate struct { - BIOSBootPartition bool `json:"bios_boot_partition"` - EspPartition bool `json:"esp_partition"` - EspPartitionSize string `json:"esp_partition_size"` -} - -// InputPartition represents a single user provided partition input -type InputPartition struct { - Name string `json:"name"` - Bootable bool `json:"bootable"` - Mountpoint string `json:"mountpoint"` - Label string `json:"label"` - Size string `json:"size"` - Type string `json:"type"` - PartUUID string `json:"part_uuid"` - PartType string `json:"part_type"` - FsUUID string `json:"fs_uuid"` - FSMntOps string `json:"fs_mntops"` - FSFreq uint64 `json:"fs_freq"` - FSPassNo uint64 `json:"fs_passno"` - - // TODO: add sectorlvm,luks, see https://github.com/achilleas-k/images/pull/2#issuecomment-2136025471 -} - -// InputModifications allow modifiying the partition generation to e.g. -// increase the default disk size -type InputModifications struct { - PartitionMode partition.PartitioningMode `json:"partition_mode"` - Filesystems []blueprint.FilesystemCustomization `json:"filesystems"` - MinDiskSize string `json:"min_disk_size"` - Filename string `json:"filename"` -} - -// Output contains a full description of a disk, this can be consumed -// by other tools like osbuild-make-* -type Output = otkdisk.Data - -func makePartMap(pt *disk.PartitionTable) map[string]otkdisk.Partition { - pm := make(map[string]otkdisk.Partition, len(pt.Partitions)) - // TODO: think about exposing more partitions, if we do, what labels - // would we use? ition.Name? what about clashes with - // "{r,b}oot" then? - for _, part := range pt.Partitions { - switch pl := part.Payload.(type) { - case *disk.Filesystem: - switch pl.Mountpoint { - case "/": - pm["root"] = otkdisk.Partition{ - UUID: pl.UUID, - } - case "/boot": - pm["boot"] = otkdisk.Partition{ - UUID: pl.UUID, - } - } - } - } - - return pm -} - -func validateInput(input *Input) error { - // TODO: validate more - if err := input.Properties.Type.Validate(); err != nil { - return err - } - return nil -} - -func makePartitionTableFromOtkInput(input *Input) (*disk.PartitionTable, error) { - var err error - - if err := validateInput(input); err != nil { - return nil, fmt.Errorf("cannot validate inputs: %w", err) - } - - var startOffset uint64 - if input.Properties.StartOffset != "" { - startOffset, err = datasizes.Parse(input.Properties.StartOffset) - if err != nil { - return nil, err - } - } - - partType, err := disk.NewPartitionTableType(string(input.Properties.Type)) - if err != nil { - return nil, err - } - pt := &disk.PartitionTable{ - UUID: input.Properties.UUID, - Type: partType, - SectorSize: input.Properties.SectorSize, - StartOffset: startOffset, - } - if input.Properties.Create.BIOSBootPartition { - if len(pt.Partitions) > 0 { - return nil, fmt.Errorf("internal error: bios partition *must* go first") - } - pt.Partitions = append(pt.Partitions, disk.Partition{ - Size: 1 * datasizes.MebiByte, - Bootable: true, - Type: disk.BIOSBootPartitionGUID, - UUID: disk.BIOSBootPartitionUUID, - }) - } - if input.Properties.Create.EspPartition { - size := input.Properties.Create.EspPartitionSize - if size == "" { - size = "1 GiB" - } - uintSize, err := datasizes.Parse(size) - if err != nil { - return nil, err - } - if uintSize > 0 { - part := disk.Partition{ - Size: uintSize, - Payload: &disk.Filesystem{ - Type: "vfat", - UUID: disk.EFIFilesystemUUID, - Mountpoint: "/boot/efi", - Label: "ESP", - FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt", - FSTabFreq: 0, - FSTabPassNo: 2, - }, - } - switch input.Properties.Type { - case otkdisk.PartTypeGPT: - part.Type = disk.EFISystemPartitionGUID - part.UUID = disk.EFISystemPartitionUUID - case otkdisk.PartTypeDOS: - part.Bootable = true - part.Type = disk.FAT16BDOSID - default: - return nil, fmt.Errorf("unsupported partition type: %v", input) - } - pt.Partitions = append(pt.Partitions, part) - } - } - - for _, part := range input.Partitions { - uintSize, err := datasizes.Parse(part.Size) - if err != nil { - return nil, err - } - // XXX: support lvm,luks here - newPart := disk.Partition{ - Size: uintSize, - UUID: part.PartUUID, - Type: part.PartType, - Bootable: part.Bootable, - } - if part.Type != "" { - newPart.Payload = &disk.Filesystem{ - Label: part.Label, - Type: part.Type, - Mountpoint: part.Mountpoint, - UUID: part.FsUUID, - FSTabOptions: part.FSMntOps, - FSTabFreq: part.FSFreq, - FSTabPassNo: part.FSPassNo, - } - } - pt.Partitions = append(pt.Partitions, newPart) - } - - return pt, nil -} - -func getDiskSizeFrom(input *Input) (diskSize uint64, err error) { - var defaultSize, modMinSize uint64 - - if input.Properties.DefaultSize != "" { - defaultSize, err = datasizes.Parse(input.Properties.DefaultSize) - if err != nil { - return 0, err - } - } - if input.Modifications.MinDiskSize != "" { - modMinSize, err = datasizes.Parse(input.Modifications.MinDiskSize) - if err != nil { - return 0, err - } - } - return max(defaultSize, modMinSize), nil -} - -func genPartitionTable(genPartInput *Input, rng *rand.Rand) (*Output, error) { - basePt, err := makePartitionTableFromOtkInput(genPartInput) - if err != nil { - return nil, err - } - diskSize, err := getDiskSizeFrom(genPartInput) - if err != nil { - return nil, fmt.Errorf("cannot get the disk size: %w", err) - } - - architecture := arch.ARCH_UNSET - if genPartInput.Properties.Type == otkdisk.PartTypeGPT { - // GPT partition table generation requires an architecture - architecture, err = arch.FromString(genPartInput.Properties.Architecture) - if err != nil { - return nil, err - } - } - pt, err := disk.NewPartitionTable(basePt, genPartInput.Modifications.Filesystems, diskSize, genPartInput.Modifications.PartitionMode, architecture, nil, rng) - if err != nil { - return nil, err - } - fname := "disk.img" - if genPartInput.Modifications.Filename != "" { - fname = genPartInput.Modifications.Filename - } - - _, kernelOptions, err := osbuild.GenImageKernelOptions(pt, false) // NOTE: this generator doesn't support using mount units - if err != nil { - return nil, err - } - otkPart := &Output{ - Const: otkdisk.Const{ - Internal: otkdisk.Internal{ - PartitionTable: pt, - }, - KernelOptsList: kernelOptions, - PartitionMap: makePartMap(pt), - Filename: fname, - }, - } - - return otkPart, nil -} - -func run(r io.Reader, w io.Writer) error { - rngSeed, err := cmdutil.SeedArgFor(&buildconfig.BuildConfig{}, "", "", "") - if err != nil { - return err - } - // math/rand is good enough in this case - /* #nosec G404 */ - rng := rand.New(rand.NewSource(rngSeed)) - - var genPartInputTree Tree - if err := json.NewDecoder(r).Decode(&genPartInputTree); err != nil { - return err - } - // XXX: validate inputs, right now an empty "type" is not an error - // but it should either be an error or we should set a default - - generated, err := genPartitionTable(&genPartInputTree.Tree, rng) - if err != nil { - return fmt.Errorf("cannot generate partition table: %w", err) - } - // there is no need to output "nice" json, but it does make testing - // simpler - output := map[string]interface{}{ - "tree": generated, - } - outputJson, err := json.MarshalIndent(output, "", " ") - if err != nil { - return fmt.Errorf("cannot marshal response: %w", err) - } - fmt.Fprintf(w, "%s\n", outputJson) - return nil -} - -func main() { - if err := run(os.Stdin, os.Stdout); err != nil { - fmt.Fprintf(os.Stderr, "error: %v", err.Error()) - os.Exit(1) - } -} diff --git a/cmd/otk/osbuild-gen-partition-table/main_test.go b/cmd/otk/osbuild-gen-partition-table/main_test.go deleted file mode 100644 index 27bd040442..0000000000 --- a/cmd/otk/osbuild-gen-partition-table/main_test.go +++ /dev/null @@ -1,802 +0,0 @@ -package main_test - -import ( - "bytes" - "encoding/json" - "math/rand" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/osbuild/blueprint/pkg/blueprint" - genpart "github.com/osbuild/images/cmd/otk/osbuild-gen-partition-table" - "github.com/osbuild/images/internal/otkdisk" - "github.com/osbuild/images/pkg/datasizes" - "github.com/osbuild/images/pkg/disk" - "github.com/osbuild/images/pkg/disk/partition" -) - -// see https://github.com/achilleas-k/images/pull/2#issuecomment-2136025471 -// Note that this partition table contains all json keys for testing, some may -// contradict each other -var partInputsComplete = ` -{ - "properties": { - "create": { - "bios_boot_partition": true, - "esp_partition": true, - "esp_partition_size": "2 GiB" - }, - "bios": true, - "type": "gpt", - "default_size": "10 GiB", - "start_offset": "8 MB" - }, - "partitions": [ - { - "name": "root", - "bootable": true, - "mountpoint": "/", - "label": "root", - "size": "7 GiB", - "type": "ext4", - "part_uuid": "0FC63DAF-8483-4772-8E79-3D69D8477DE4" - }, - { - "name": "home", - "mountpoint": "/home", - "label": "home", - "size": "2 GiB", - "type": "ext4" - } - ], - "modifications": { - "min_disk_size": "20 GiB", - "partition_mode": "auto-lvm", - "filesystems": [ - {"mountpoint": "/var/log", "minsize": 10241024} - ] - } -}` - -var expectedInput = &genpart.Input{ - Properties: genpart.InputProperties{ - Create: genpart.InputCreate{ - BIOSBootPartition: true, - EspPartition: true, - EspPartitionSize: "2 GiB", - }, - Type: "gpt", - DefaultSize: "10 GiB", - StartOffset: "8 MB", - }, - Partitions: []*genpart.InputPartition{ - { - Name: "root", - Bootable: true, - Mountpoint: "/", - Label: "root", - Size: "7 GiB", - Type: "ext4", - PartUUID: "0FC63DAF-8483-4772-8E79-3D69D8477DE4", - }, { - Name: "home", - Mountpoint: "/home", - Label: "home", - Size: "2 GiB", - Type: "ext4", - }, - }, - Modifications: genpart.InputModifications{ - MinDiskSize: "20 GiB", - PartitionMode: partition.AutoLVMPartitioningMode, - Filesystems: []blueprint.FilesystemCustomization{ - { - Mountpoint: "/var/log", - MinSize: 10241024, - }, - }, - }, -} - -func TestUnmarshalInput(t *testing.T) { - var otkInput genpart.Input - err := json.Unmarshal([]byte(partInputsComplete), &otkInput) - assert.NoError(t, err) - assert.Equal(t, expectedInput, &otkInput) -} - -func TestUnmarshalOutput(t *testing.T) { - fakeOtkOutput := &otkdisk.Data{ - Const: otkdisk.Const{ - KernelOptsList: []string{"root=UUID=1234"}, - PartitionMap: map[string]otkdisk.Partition{ - "root": { - UUID: "12345", - }, - }, - Filename: "disk.img", - Internal: otkdisk.Internal{ - PartitionTable: &disk.PartitionTable{ - Size: 911, - Partitions: []disk.Partition{ - { - UUID: "911911", - Type: "119119", - Payload: &disk.Filesystem{ - Type: "ext4", - }, - }, - }, - }, - }, - }, - } - // XXX: anything under "internal" we don't actually need to test - // as we do not make any gurantees to the outside - expectedOutput := `{ - "const": { - "kernel_opts_list": [ - "root=UUID=1234" - ], - "partition_map": { - "root": { - "uuid": "12345" - } - }, - "internal": { - "partition-table": { - "size": 911, - "type": "", - "partitions": [ - { - "size": 0, - "type": "119119", - "uuid": "911911", - "payload": { - "type": "ext4" - }, - "payload_type": "filesystem" - } - ] - } - }, - "filename": "disk.img" - } -}` - output, err := json.MarshalIndent(fakeOtkOutput, "", " ") - assert.NoError(t, err) - assert.Equal(t, expectedOutput, string(output)) -} - -var partInputsSimple = `{ - "tree": { - "properties": { - "create": { - "bios_boot_partition": true, - "esp_partition": true, - "esp_partition_size": "2 GiB" - }, - "type": "gpt", - "default_size": "10 GiB", - "start_offset": "8 MB", - "architecture": "x86_64" - }, - "partitions": [ - { - "name": "root", - "mountpoint": "/", - "label": "root", - "size": "7 GiB", - "type": "ext4" - }, - { - "name": "home", - "mountpoint": "/home", - "label": "home", - "size": "2 GiB", - "type": "ext4" - } - ] - } -} -` - -// XXX: anything under "internal" we don't actually need to test -// as we do not make any gurantees to the outside -var expectedSimplePartOutput = `{ - "tree": { - "const": { - "kernel_opts_list": [], - "partition_map": { - "root": { - "uuid": "9851898e-0b30-437d-8fad-51ec16c3697f" - } - }, - "internal": { - "partition-table": { - "size": 11821645824, - "uuid": "dbd21911-1c4e-4107-8a9f-14fe6e751358", - "type": "gpt", - "partitions": [ - { - "start": 9048576, - "size": 1048576, - "type": "21686148-6449-6E6F-744E-656564454649", - "bootable": true, - "uuid": "FAC7F1FB-3E8D-4137-A512-961DE09A5549" - }, - { - "start": 10097152, - "size": 2147483648, - "type": "C12A7328-F81F-11D2-BA4B-00A0C93EC93B", - "uuid": "68B2905B-DF3E-4FB3-80FA-49D1E773AA33", - "payload": { - "type": "vfat", - "uuid": "7B77-95E7", - "label": "ESP", - "mountpoint": "/boot/efi", - "fstab_options": "defaults,uid=0,gid=0,umask=077,shortname=winnt", - "fstab_passno": 2 - }, - "payload_type": "filesystem" - }, - { - "start": 4305064448, - "size": 7516564480, - "uuid": "ed130be6-c822-49af-83bb-4ea648bb2264", - "payload": { - "type": "ext4", - "uuid": "9851898e-0b30-437d-8fad-51ec16c3697f", - "label": "root", - "mountpoint": "/" - }, - "payload_type": "filesystem" - }, - { - "start": 2157580800, - "size": 2147483648, - "uuid": "9f6173fd-edc9-4dbe-9313-632af556c607", - "payload": { - "type": "ext4", - "uuid": "d8bb61b8-81cf-4c85-937b-69439a23dc5e", - "label": "home", - "mountpoint": "/home" - }, - "payload_type": "filesystem" - } - ], - "start_offset": 8000000 - } - }, - "filename": "disk.img" - } - } -} -` - -func TestIntegrationRealistic(t *testing.T) { - t.Setenv("OSBUILD_TESTING_RNG_SEED", "0") - - inp := bytes.NewBufferString(partInputsSimple) - outp := bytes.NewBuffer(nil) - err := genpart.Run(inp, outp) - assert.NoError(t, err) - assert.Equal(t, expectedSimplePartOutput, outp.String()) -} - -func TestGenPartitionTableBootable(t *testing.T) { - inp := &genpart.Input{ - Properties: genpart.InputProperties{ - Type: "dos", - }, - Partitions: []*genpart.InputPartition{ - { - Bootable: true, - Mountpoint: "/", - Size: "10 GiB", - Type: "ext4", - }, - }, - } - - output, err := genpart.GenPartitionTable(inp, rand.New(rand.NewSource(0))) /* #nosec G404 */ - assert.NoError(t, err) - assert.Equal(t, true, output.Const.Internal.PartitionTable.Partitions[0].Bootable) -} - -func TestGenPartitionTableIntegrationPPC(t *testing.T) { - inp := &genpart.Input{ - Properties: genpart.InputProperties{ - Type: "dos", - DefaultSize: "10 GiB", - UUID: "0x14fc63d2", - }, - Partitions: []*genpart.InputPartition{ - { - Name: "ppc-boot", - Bootable: true, - Size: "4 MiB", - PartType: disk.PRepPartitionDOSID, - PartUUID: "", - }, - { - Name: "root", - Size: "10 GiB", - Type: "xfs", - Mountpoint: "/", - }, - }, - } - expectedOutput := &otkdisk.Data{ - Const: otkdisk.Const{ - KernelOptsList: []string{}, - PartitionMap: map[string]otkdisk.Partition{ - "root": { - UUID: "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8", - }, - }, - Filename: "disk.img", - Internal: otkdisk.Internal{ - PartitionTable: &disk.PartitionTable{ - Size: 10742661120, - UUID: "0x14fc63d2", - Type: disk.PT_DOS, - Partitions: []disk.Partition{ - { - Bootable: true, - Start: 1048576, - Size: 4194304, - Type: disk.PRepPartitionDOSID, - }, - { - Start: 5242880, - Size: 10737418240, - Payload: &disk.Filesystem{ - Type: "xfs", - UUID: "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8", - Mountpoint: "/", - }, - }, - }, - }, - }, - }, - } - output, err := genpart.GenPartitionTable(inp, rand.New(rand.NewSource(0))) /* #nosec G404 */ - assert.NoError(t, err) - assert.Equal(t, expectedOutput, output) -} - -func TestGenPartitionTableMinimal(t *testing.T) { - // XXX: think about what the smalltest inputs can be and validate - // that it's complete and/or provide defaults (e.g. for "type" for - // partition and filesystem type) - inp := &genpart.Input{ - Properties: genpart.InputProperties{ - Type: "dos", - }, - Partitions: []*genpart.InputPartition{ - { - Mountpoint: "/", - Size: "10 GiB", - Type: "ext4", - }, - }, - } - expectedOutput := &otkdisk.Data{ - Const: otkdisk.Const{ - KernelOptsList: []string{}, - PartitionMap: map[string]otkdisk.Partition{ - "root": { - UUID: "6e4ff95f-f662-45ee-a82a-bdf44a2d0b75", - }, - }, - Filename: "disk.img", - Internal: otkdisk.Internal{ - PartitionTable: &disk.PartitionTable{ - Size: 10738466816, - UUID: "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8", - Type: disk.PT_DOS, - Partitions: []disk.Partition{ - { - Start: 1048576, - Size: 10737418240, - Payload: &disk.Filesystem{ - Type: "ext4", - UUID: "6e4ff95f-f662-45ee-a82a-bdf44a2d0b75", - Mountpoint: "/", - }, - }, - }, - }, - }, - }, - } - output, err := genpart.GenPartitionTable(inp, rand.New(rand.NewSource(0))) /* #nosec G404 */ - assert.NoError(t, err) - assert.Equal(t, expectedOutput, output) -} - -func TestGenPartitionTableCustomizationExtraMp(t *testing.T) { - inp := &genpart.Input{ - Properties: genpart.InputProperties{ - Type: "dos", - }, - Partitions: []*genpart.InputPartition{ - { - Mountpoint: "/boot", - Size: "2 GiB", - Type: "ext4", - }, - { - Mountpoint: "/", - Size: "10 GiB", - Type: "ext4", - }, - }, - Modifications: genpart.InputModifications{ - Filesystems: []blueprint.FilesystemCustomization{ - { - Mountpoint: "/var/log", - MinSize: 3 * datasizes.GigaByte, - }, - }, - }, - } - expectedOutput := &otkdisk.Data{ - Const: otkdisk.Const{ - KernelOptsList: []string{}, - PartitionMap: map[string]otkdisk.Partition{ - "boot": { - UUID: "6e4ff95f-f662-45ee-a82a-bdf44a2d0b75", - }, - }, - Filename: "disk.img", - Internal: otkdisk.Internal{ - PartitionTable: &disk.PartitionTable{ - Size: 15893266432, - UUID: "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8", - Type: disk.PT_DOS, - Partitions: []disk.Partition{ - { - Start: 1048576, - Size: 2147483648, - Payload: &disk.Filesystem{ - Type: "ext4", - UUID: "6e4ff95f-f662-45ee-a82a-bdf44a2d0b75", - Mountpoint: "/boot", - }, - }, - { - Start: 2148532224, - Size: 13744734208, - Type: disk.LVMPartitionDOSID, - Payload: &disk.LVMVolumeGroup{ - Name: "rootvg", - Description: "created via lvm2 and osbuild", - LogicalVolumes: []disk.LVMLogicalVolume{ - { - Name: "rootlv", - Size: 10737418240, - Payload: &disk.Filesystem{ - Mountpoint: "/", - Type: "ext4", - UUID: "fb180daf-48a7-4ee0-b10d-394651850fd4", - }, - }, { - Name: "var_loglv", - Size: 3003121664, - Payload: &disk.Filesystem{ - Mountpoint: "/var/log", - // XXX: this is confusing - Type: "xfs", - UUID: "a178892e-e285-4ce1-9114-55780875d64e", - // XXX: is this needed? - FSTabOptions: "defaults", - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - // default partition mode is "auto-lvm" so LVM is created by default - output, err := genpart.GenPartitionTable(inp, rand.New(rand.NewSource(0))) /* #nosec G404 */ - assert.NoError(t, err) - assert.Equal(t, expectedOutput, output) -} - -func TestGenPartitionTableCustomizationExtraMpPlusModificationPartitionMode(t *testing.T) { - inp := &genpart.Input{ - Properties: genpart.InputProperties{ - Type: "dos", - }, - Partitions: []*genpart.InputPartition{ - { - Mountpoint: "/", - Size: "10 GiB", - Type: "ext4", - }, - }, - Modifications: genpart.InputModifications{ - // note that the extra partitin mode is used here - PartitionMode: partition.RawPartitioningMode, - Filesystems: []blueprint.FilesystemCustomization{ - { - Mountpoint: "/var/log", - MinSize: 3 * datasizes.GigaByte, - }, - }, - }, - } - expectedOutput := &otkdisk.Data{ - Const: otkdisk.Const{ - KernelOptsList: []string{}, - PartitionMap: map[string]otkdisk.Partition{ - "root": { - UUID: "6e4ff95f-f662-45ee-a82a-bdf44a2d0b75", - }, - }, - Filename: "disk.img", - Internal: otkdisk.Internal{ - PartitionTable: &disk.PartitionTable{ - Size: 13739491328, - UUID: "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8", - Type: disk.PT_DOS, - Partitions: []disk.Partition{ - { - Start: 3002073088, - Size: 10737418240, - Payload: &disk.Filesystem{ - Mountpoint: "/", - Type: "ext4", - UUID: "6e4ff95f-f662-45ee-a82a-bdf44a2d0b75", - }, - }, { - Start: 1048576, - Size: 3001024512, - Payload: &disk.Filesystem{ - Mountpoint: "/var/log", - // XXX: this is confusing - Type: "xfs", - UUID: "fb180daf-48a7-4ee0-b10d-394651850fd4", - FSTabOptions: "defaults", - }, - }, - }, - }, - }, - }, - } - output, err := genpart.GenPartitionTable(inp, rand.New(rand.NewSource(0))) /* #nosec G404 */ - assert.NoError(t, err) - assert.Equal(t, expectedOutput, output) -} - -func TestGenPartitionTablePropertiesDefaultSize(t *testing.T) { - inp := &genpart.Input{ - Properties: genpart.InputProperties{ - Type: "dos", - DefaultSize: "15 GiB", - }, - Partitions: []*genpart.InputPartition{ - { - Mountpoint: "/", - Size: "10 GiB", - Type: "ext4", - }, - }, - } - expectedOutput := &otkdisk.Data{ - Const: otkdisk.Const{ - KernelOptsList: []string{}, - PartitionMap: map[string]otkdisk.Partition{ - "root": { - UUID: "6e4ff95f-f662-45ee-a82a-bdf44a2d0b75", - }, - }, - Filename: "disk.img", - Internal: otkdisk.Internal{ - PartitionTable: &disk.PartitionTable{ - Size: 16106127360, - UUID: "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8", - Type: disk.PT_DOS, - Partitions: []disk.Partition{ - { - Start: 1048576, - Size: 16105078784, - Payload: &disk.Filesystem{ - Type: "ext4", - UUID: "6e4ff95f-f662-45ee-a82a-bdf44a2d0b75", - Mountpoint: "/", - }, - }, - }, - }, - }, - }, - } - output, err := genpart.GenPartitionTable(inp, rand.New(rand.NewSource(0))) /* #nosec G404 */ - assert.NoError(t, err) - assert.Equal(t, expectedOutput, output) -} - -func TestGenPartitionTableModificationMinDiskSize(t *testing.T) { - inp := &genpart.Input{ - Properties: genpart.InputProperties{ - Type: "dos", - DefaultSize: "15 GiB", - }, - Partitions: []*genpart.InputPartition{ - { - Mountpoint: "/", - Size: "10 GiB", - Type: "ext4", - }, - }, - Modifications: genpart.InputModifications{ - MinDiskSize: "20 GiB", - }, - } - expectedOutput := &otkdisk.Data{ - Const: otkdisk.Const{ - KernelOptsList: []string{}, - PartitionMap: map[string]otkdisk.Partition{ - "root": { - UUID: "6e4ff95f-f662-45ee-a82a-bdf44a2d0b75", - }, - }, - Filename: "disk.img", - Internal: otkdisk.Internal{ - PartitionTable: &disk.PartitionTable{ - Size: 21474836480, - UUID: "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8", - Type: disk.PT_DOS, - Partitions: []disk.Partition{ - { - Start: 1048576, - Size: 21473787904, - Payload: &disk.Filesystem{ - Type: "ext4", - UUID: "6e4ff95f-f662-45ee-a82a-bdf44a2d0b75", - Mountpoint: "/", - }, - }, - }, - }, - }, - }, - } - output, err := genpart.GenPartitionTable(inp, rand.New(rand.NewSource(0))) /* #nosec G404 */ - assert.NoError(t, err) - assert.Equal(t, expectedOutput, output) -} - -func TestGenPartitionTableModificationFilename(t *testing.T) { - inp := &genpart.Input{ - Properties: genpart.InputProperties{ - Type: "dos", - }, - Partitions: []*genpart.InputPartition{ - { - Mountpoint: "/", - Size: "10 GiB", - Type: "ext4", - }, - }, - Modifications: genpart.InputModifications{ - Filename: "custom-disk.img", - }, - } - expectedOutput := &otkdisk.Data{ - Const: otkdisk.Const{ - KernelOptsList: []string{}, - PartitionMap: map[string]otkdisk.Partition{ - "root": { - UUID: "6e4ff95f-f662-45ee-a82a-bdf44a2d0b75", - }, - }, - Filename: "custom-disk.img", - Internal: otkdisk.Internal{ - PartitionTable: &disk.PartitionTable{ - Size: 10738466816, - UUID: "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8", - Type: disk.PT_DOS, - Partitions: []disk.Partition{ - { - Start: 1048576, - Size: 10737418240, - Payload: &disk.Filesystem{ - Type: "ext4", - UUID: "6e4ff95f-f662-45ee-a82a-bdf44a2d0b75", - Mountpoint: "/", - }, - }, - }, - }, - }, - }, - } - output, err := genpart.GenPartitionTable(inp, rand.New(rand.NewSource(0))) /* #nosec G404 */ - assert.NoError(t, err) - assert.Equal(t, expectedOutput, output) -} - -func TestGenPartitionTableValidates(t *testing.T) { - inp := &genpart.Input{ - Properties: genpart.InputProperties{ - Type: "invalid-type", - }, - } - _, err := genpart.GenPartitionTable(inp, rand.New(rand.NewSource(0))) /* #nosec G404 */ - assert.EqualError(t, err, `cannot validate inputs: unsupported partition type "invalid-type"`) -} - -func TestGenPartitionCreateESPDos(t *testing.T) { - inp := &genpart.Input{ - Properties: genpart.InputProperties{ - Type: "dos", - Create: genpart.InputCreate{ - EspPartition: true, - EspPartitionSize: "2 GiB", - }, - }, - Partitions: []*genpart.InputPartition{ - { - Mountpoint: "/", - Size: "10 GiB", - Type: "ext4", - }, - }, - } - expectedOutput := &otkdisk.Data{ - Const: otkdisk.Const{ - KernelOptsList: []string{}, - PartitionMap: map[string]otkdisk.Partition{ - "root": { - UUID: "6e4ff95f-f662-45ee-a82a-bdf44a2d0b75", - }, - }, - Filename: "disk.img", - Internal: otkdisk.Internal{ - PartitionTable: &disk.PartitionTable{ - Size: 12885950464, - Type: disk.PT_DOS, - UUID: "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8", - Partitions: []disk.Partition{ - { - Start: 1048576, - Size: 2147483648, - Bootable: true, - Type: "06", - Payload: &disk.Filesystem{ - Type: "vfat", - UUID: "7B77-95E7", - Label: "ESP", - Mountpoint: "/boot/efi", - FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt", - FSTabPassNo: 2, - }, - }, - { - Start: 2148532224, - Size: 10737418240, - Payload: &disk.Filesystem{ - Type: "ext4", - UUID: "6e4ff95f-f662-45ee-a82a-bdf44a2d0b75", - Mountpoint: "/", - }, - }, - }, - }, - }, - }, - } - output, err := genpart.GenPartitionTable(inp, rand.New(rand.NewSource(0))) /* #nosec G404 */ - assert.NoError(t, err) - assert.Equal(t, expectedOutput, output) -} diff --git a/cmd/otk/osbuild-make-fstab-stage/export_test.go b/cmd/otk/osbuild-make-fstab-stage/export_test.go deleted file mode 100644 index cc2e2795d4..0000000000 --- a/cmd/otk/osbuild-make-fstab-stage/export_test.go +++ /dev/null @@ -1,3 +0,0 @@ -package main - -var Run = run diff --git a/cmd/otk/osbuild-make-fstab-stage/main.go b/cmd/otk/osbuild-make-fstab-stage/main.go deleted file mode 100644 index ff1a1a31da..0000000000 --- a/cmd/otk/osbuild-make-fstab-stage/main.go +++ /dev/null @@ -1,49 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io" - "os" - - "github.com/osbuild/images/pkg/osbuild" - - "github.com/osbuild/images/internal/otkdisk" -) - -type Input struct { - Tree otkdisk.Data `json:"tree"` -} - -func run(r io.Reader, w io.Writer) error { - var inp Input - if err := json.NewDecoder(r).Decode(&inp); err != nil { - return err - } - if err := inp.Tree.Validate(); err != nil { - return fmt.Errorf("cannot validate input data: %w", err) - } - - opts, err := osbuild.NewFSTabStageOptions(inp.Tree.Const.Internal.PartitionTable) - if err != nil { - return fmt.Errorf("cannot make partition stages: %w", err) - } - stage := osbuild.NewFSTabStage(opts) - - out := map[string]interface{}{ - "tree": stage, - } - outputJson, err := json.MarshalIndent(out, "", " ") - if err != nil { - return fmt.Errorf("cannot marshal response: %w", err) - } - fmt.Fprintf(w, "%s\n", outputJson) - return nil -} - -func main() { - if err := run(os.Stdin, os.Stdout); err != nil { - fmt.Fprintf(os.Stderr, "error: %v", err.Error()) - os.Exit(1) - } -} diff --git a/cmd/otk/osbuild-make-fstab-stage/main_test.go b/cmd/otk/osbuild-make-fstab-stage/main_test.go deleted file mode 100644 index 5e55ae8cbe..0000000000 --- a/cmd/otk/osbuild-make-fstab-stage/main_test.go +++ /dev/null @@ -1,71 +0,0 @@ -package main_test - -import ( - "bytes" - "encoding/json" - "testing" - - "github.com/stretchr/testify/assert" - - makefstab "github.com/osbuild/images/cmd/otk/osbuild-make-fstab-stage" - "github.com/osbuild/images/internal/otkdisk" - "github.com/osbuild/images/internal/testdisk" -) - -// this is not symetrical to the output, this is sad but also -// okay because the input is really just a dump of the internal -// disk.PartitionTable so encoding it in json here will not add -// a benefit for the test -var minimalInputBase = makefstab.Input{ - Tree: otkdisk.Data{ - Const: otkdisk.Const{ - Internal: otkdisk.Internal{ - PartitionTable: testdisk.MakeFakePartitionTable("/", "/var"), - }, - }, - }, -} - -var minimalExpectedStages = `{ - "tree": { - "type": "org.osbuild.fstab", - "options": { - "filesystems": [ - { - "uuid": "6264D520-3FB9-423F-8AB8-7A0A8E3D3562", - "vfs_type": "ext4", - "path": "/" - }, - { - "uuid": "CB07C243-BC44-4717-853E-28852021225B", - "vfs_type": "ext4", - "path": "/var" - } - ] - } - } -} -` - -func TestIntegration(t *testing.T) { - minimalInput := minimalInputBase - minimalInput.Tree.Const.Filename = "disk.img" - expectedStages := minimalExpectedStages - - inpJSON, err := json.Marshal(&minimalInput) - assert.NoError(t, err) - fakeStdin := bytes.NewBuffer(inpJSON) - fakeStdout := bytes.NewBuffer(nil) - - err = makefstab.Run(fakeStdin, fakeStdout) - assert.NoError(t, err) - - assert.Equal(t, expectedStages, fakeStdout.String()) -} - -func TestIntegrationNoPartitionTable(t *testing.T) { - fakeStdin := bytes.NewBufferString(`{}`) - fakeStdout := bytes.NewBuffer(nil) - err := makefstab.Run(fakeStdin, fakeStdout) - assert.EqualError(t, err, "cannot validate input data: no partition table") -} diff --git a/cmd/otk/osbuild-make-grub2-inst-stage/export_test.go b/cmd/otk/osbuild-make-grub2-inst-stage/export_test.go deleted file mode 100644 index cc2e2795d4..0000000000 --- a/cmd/otk/osbuild-make-grub2-inst-stage/export_test.go +++ /dev/null @@ -1,3 +0,0 @@ -package main - -var Run = run diff --git a/cmd/otk/osbuild-make-grub2-inst-stage/main.go b/cmd/otk/osbuild-make-grub2-inst-stage/main.go deleted file mode 100644 index 4849030c37..0000000000 --- a/cmd/otk/osbuild-make-grub2-inst-stage/main.go +++ /dev/null @@ -1,48 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io" - "os" - - "github.com/osbuild/images/pkg/osbuild" - - "github.com/osbuild/images/internal/otkdisk" -) - -type Input struct { - Tree Tree `json:"tree"` -} - -type Tree struct { - Platform string `json:"platform"` - Filesystem otkdisk.Data `json:"filesystem"` -} - -func run(r io.Reader, w io.Writer) error { - var inp Input - if err := json.NewDecoder(r).Decode(&inp); err != nil { - return err - } - - opts := osbuild.NewGrub2InstStageOption(inp.Tree.Filesystem.Const.Filename, inp.Tree.Filesystem.Const.Internal.PartitionTable, inp.Tree.Platform) - stage := osbuild.NewGrub2InstStage(opts) - - out := map[string]interface{}{ - "tree": stage, - } - outputJson, err := json.MarshalIndent(out, "", " ") - if err != nil { - return fmt.Errorf("cannot marshal response: %w", err) - } - fmt.Fprintf(w, "%s\n", outputJson) - return nil -} - -func main() { - if err := run(os.Stdin, os.Stdout); err != nil { - fmt.Fprintf(os.Stderr, "error: %v", err.Error()) - os.Exit(1) - } -} diff --git a/cmd/otk/osbuild-make-grub2-inst-stage/main_test.go b/cmd/otk/osbuild-make-grub2-inst-stage/main_test.go deleted file mode 100644 index ef80e159d1..0000000000 --- a/cmd/otk/osbuild-make-grub2-inst-stage/main_test.go +++ /dev/null @@ -1,91 +0,0 @@ -package main_test - -import ( - "bytes" - "encoding/json" - "testing" - - "github.com/stretchr/testify/assert" - - makeGrub2Inst "github.com/osbuild/images/cmd/otk/osbuild-make-grub2-inst-stage" - "github.com/osbuild/images/internal/otkdisk" - "github.com/osbuild/images/pkg/datasizes" - "github.com/osbuild/images/pkg/disk" -) - -var fakePt = &disk.PartitionTable{ - Type: disk.PT_GPT, - Partitions: []disk.Partition{ - { - Size: 1 * datasizes.MiB, - Start: 1 * datasizes.MiB, - Bootable: true, - Type: disk.BIOSBootPartitionGUID, - UUID: disk.BIOSBootPartitionUUID, - }, - { - Size: 1 * datasizes.GiB, - Payload: &disk.Filesystem{ - Type: "ext4", - Mountpoint: "/", - UUID: disk.RootPartitionUUID, - }, - }, - }, -} - -// this is not symetrical to the output, this is sad but also -// okay because the input is really just a dump of the internal -// disk.PartitionTable so encoding it in json here will not add -// a benefit for the test -var minimalInputBase = makeGrub2Inst.Input{ - Tree: makeGrub2Inst.Tree{ - Platform: "i386-pc", - Filesystem: otkdisk.Data{ - Const: otkdisk.Const{ - Internal: otkdisk.Internal{ - PartitionTable: fakePt, - }, - }, - }, - }, -} - -var minimalExpectedStages = `{ - "tree": { - "type": "org.osbuild.grub2.inst", - "options": { - "filename": "disk.img", - "platform": "i386-pc", - "location": 2048, - "core": { - "type": "mkimage", - "partlabel": "gpt", - "filesystem": "ext4" - }, - "prefix": { - "type": "partition", - "partlabel": "gpt", - "number": 1, - "path": "/boot/grub2" - } - } - } -} -` - -func TestIntegration(t *testing.T) { - minimalInput := minimalInputBase - minimalInput.Tree.Filesystem.Const.Filename = "disk.img" - expectedStages := minimalExpectedStages - - inpJSON, err := json.Marshal(&minimalInput) - assert.NoError(t, err) - fakeStdin := bytes.NewBuffer(inpJSON) - fakeStdout := bytes.NewBuffer(nil) - - err = makeGrub2Inst.Run(fakeStdin, fakeStdout) - assert.NoError(t, err) - - assert.Equal(t, expectedStages, fakeStdout.String()) -} diff --git a/cmd/otk/osbuild-make-ostree-source/export_test.go b/cmd/otk/osbuild-make-ostree-source/export_test.go deleted file mode 100644 index 77c5f1a937..0000000000 --- a/cmd/otk/osbuild-make-ostree-source/export_test.go +++ /dev/null @@ -1,5 +0,0 @@ -package main - -var ( - Run = run -) diff --git a/cmd/otk/osbuild-make-ostree-source/main.go b/cmd/otk/osbuild-make-ostree-source/main.go deleted file mode 100644 index 0cda5b9911..0000000000 --- a/cmd/otk/osbuild-make-ostree-source/main.go +++ /dev/null @@ -1,59 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io" - "os" - - "github.com/osbuild/images/internal/otkostree" - "github.com/osbuild/images/pkg/osbuild" - "github.com/osbuild/images/pkg/ostree" -) - -type Input struct { - Tree InputTree `json:"tree"` -} - -type InputTree struct { - Const otkostree.ResolvedConst `json:"const"` -} - -type Output struct { - OSTreeSource osbuild.OSTreeSource `json:"org.osbuild.ostree"` -} - -func run(r io.Reader, w io.Writer) error { - var inp Input - if err := json.NewDecoder(r).Decode(&inp); err != nil { - return err - } - - ostreeSource := osbuild.NewOSTreeSource() - ostreeSource.AddItem(ostree.CommitSpec{ - Ref: inp.Tree.Const.Ref, - URL: inp.Tree.Const.URL, - Secrets: inp.Tree.Const.Secrets, - Checksum: inp.Tree.Const.Checksum, - }) - - output := Output{ - OSTreeSource: *ostreeSource, - } - out := map[string]interface{}{ - "tree": output, - } - outputJson, err := json.MarshalIndent(out, "", " ") - if err != nil { - return fmt.Errorf("cannot marshal response: %w", err) - } - fmt.Fprintf(w, "%s\n", outputJson) - return nil -} - -func main() { - if err := run(os.Stdin, os.Stdout); err != nil { - fmt.Fprintf(os.Stderr, "error: %v", err.Error()) - os.Exit(1) - } -} diff --git a/cmd/otk/osbuild-make-ostree-source/main_test.go b/cmd/otk/osbuild-make-ostree-source/main_test.go deleted file mode 100644 index b9cb7c08f2..0000000000 --- a/cmd/otk/osbuild-make-ostree-source/main_test.go +++ /dev/null @@ -1,84 +0,0 @@ -package main_test - -import ( - "bytes" - "testing" - - sourcemaker "github.com/osbuild/images/cmd/otk/osbuild-make-ostree-source" - "github.com/stretchr/testify/require" -) - -func TestSourceMakerBasic(t *testing.T) { - require := require.New(t) - - input := `{ - "tree": { - "const": { - "ref": "does/not/matter", - "checksum": "d04105393ca0617856b34f897842833d785522e41617e17dca2063bf97e294ef", - "url": "https://ostree.example.org/repo" - } - } -}` - - expOutput := `{ - "tree": { - "org.osbuild.ostree": { - "items": { - "d04105393ca0617856b34f897842833d785522e41617e17dca2063bf97e294ef": { - "remote": { - "url": "https://ostree.example.org/repo" - } - } - } - } - } -} -` - - inpBuf := bytes.NewBuffer([]byte(input)) - outBuf := &bytes.Buffer{} - - require.NoError(sourcemaker.Run(inpBuf, outBuf)) - require.Equal(expOutput, outBuf.String()) -} - -func TestSourceMakerWithSecrets(t *testing.T) { - require := require.New(t) - - input := ` -{ - "tree": { - "const": { - "ref": "does/not/matter", - "checksum": "d04105393ca0617856b34f897842833d785522e41617e17dca2063bf97e294ef", - "url": "https://ostree.example.org/repo", - "secrets": "org.osbuild.rhsm.consumer" - } - } -}` - - expOutput := `{ - "tree": { - "org.osbuild.ostree": { - "items": { - "d04105393ca0617856b34f897842833d785522e41617e17dca2063bf97e294ef": { - "remote": { - "url": "https://ostree.example.org/repo", - "secrets": { - "name": "org.osbuild.rhsm.consumer" - } - } - } - } - } - } -} -` - - inpBuf := bytes.NewBuffer([]byte(input)) - outBuf := &bytes.Buffer{} - - require.NoError(sourcemaker.Run(inpBuf, outBuf)) - require.Equal(expOutput, outBuf.String()) -} diff --git a/cmd/otk/osbuild-make-partition-mounts-devices/export_test.go b/cmd/otk/osbuild-make-partition-mounts-devices/export_test.go deleted file mode 100644 index cc2e2795d4..0000000000 --- a/cmd/otk/osbuild-make-partition-mounts-devices/export_test.go +++ /dev/null @@ -1,3 +0,0 @@ -package main - -var Run = run diff --git a/cmd/otk/osbuild-make-partition-mounts-devices/main.go b/cmd/otk/osbuild-make-partition-mounts-devices/main.go deleted file mode 100644 index 80469b91ee..0000000000 --- a/cmd/otk/osbuild-make-partition-mounts-devices/main.go +++ /dev/null @@ -1,57 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io" - "os" - - "github.com/osbuild/images/internal/otkdisk" - "github.com/osbuild/images/pkg/osbuild" -) - -type Input struct { - Tree otkdisk.Data `json:"tree"` -} - -type Output struct { - RootMountName string `json:"root_mount_name"` - Mounts []osbuild.Mount `json:"mounts"` - Devices map[string]osbuild.Device `json:"devices"` -} - -func run(r io.Reader, w io.Writer) error { - var inp Input - if err := json.NewDecoder(r).Decode(&inp); err != nil { - return err - } - if err := inp.Tree.Validate(); err != nil { - return fmt.Errorf("cannot validate input data: %w", err) - } - - rootMntName, mounts, devices, err := osbuild.GenMountsDevicesFromPT(inp.Tree.Const.Filename, inp.Tree.Const.Internal.PartitionTable) - if err != nil { - return err - } - - out := map[string]interface{}{ - "tree": Output{ - RootMountName: rootMntName, - Mounts: mounts, - Devices: devices, - }, - } - outputJson, err := json.MarshalIndent(out, "", " ") - if err != nil { - return fmt.Errorf("cannot marshal response: %w", err) - } - fmt.Fprintf(w, "%s\n", outputJson) - return nil -} - -func main() { - if err := run(os.Stdin, os.Stdout); err != nil { - fmt.Fprintf(os.Stderr, "error: %v", err.Error()) - os.Exit(1) - } -} diff --git a/cmd/otk/osbuild-make-partition-mounts-devices/main_test.go b/cmd/otk/osbuild-make-partition-mounts-devices/main_test.go deleted file mode 100644 index fd2d9e54c0..0000000000 --- a/cmd/otk/osbuild-make-partition-mounts-devices/main_test.go +++ /dev/null @@ -1,90 +0,0 @@ -package main_test - -import ( - "bytes" - "encoding/json" - "testing" - - mkdevmnt "github.com/osbuild/images/cmd/otk/osbuild-make-partition-mounts-devices" - "github.com/osbuild/images/internal/otkdisk" - "github.com/osbuild/images/internal/testdisk" - "github.com/stretchr/testify/assert" -) - -const expectedOutput = `{ - "tree": { - "root_mount_name": "-", - "mounts": [ - { - "name": "-", - "type": "org.osbuild.ext4", - "source": "-", - "target": "/" - }, - { - "name": "boot", - "type": "org.osbuild.ext4", - "source": "boot", - "target": "/boot" - }, - { - "name": "boot-efi", - "type": "org.osbuild.fat", - "source": "boot-efi", - "target": "/boot/efi" - } - ], - "devices": { - "-": { - "type": "org.osbuild.loopback", - "options": { - "filename": "test.disk", - "size": 1615872 - } - }, - "boot": { - "type": "org.osbuild.loopback", - "options": { - "filename": "test.disk", - "size": 1615872 - } - }, - "boot-efi": { - "type": "org.osbuild.loopback", - "options": { - "filename": "test.disk", - "size": 1615872 - } - } - } - } -} -` - -func TestIntegration(t *testing.T) { - pt := testdisk.MakeFakePartitionTable("/", "/boot", "/boot/efi") - input := mkdevmnt.Input{ - Tree: otkdisk.Data{ - Const: otkdisk.Const{ - Filename: "test.disk", - Internal: otkdisk.Internal{ - PartitionTable: pt, - }, - }, - }, - } - inpJSON, err := json.Marshal(&input) - assert.NoError(t, err) - fakeStdin := bytes.NewBuffer(inpJSON) - fakeStdout := bytes.NewBuffer(nil) - err = mkdevmnt.Run(fakeStdin, fakeStdout) - assert.NoError(t, err) - assert.Equal(t, expectedOutput, fakeStdout.String()) -} - -func TestIntegrationNoPartitionTable(t *testing.T) { - fakeStdin := bytes.NewBufferString(`{}`) - fakeStdout := bytes.NewBuffer(nil) - err := mkdevmnt.Run(fakeStdin, fakeStdout) - assert.EqualError(t, err, "cannot validate input data: no partition table") -} diff --git a/cmd/otk/osbuild-make-partition-stages/export_test.go b/cmd/otk/osbuild-make-partition-stages/export_test.go deleted file mode 100644 index cc2e2795d4..0000000000 --- a/cmd/otk/osbuild-make-partition-stages/export_test.go +++ /dev/null @@ -1,3 +0,0 @@ -package main - -var Run = run diff --git a/cmd/otk/osbuild-make-partition-stages/main.go b/cmd/otk/osbuild-make-partition-stages/main.go deleted file mode 100644 index 62bc839010..0000000000 --- a/cmd/otk/osbuild-make-partition-stages/main.go +++ /dev/null @@ -1,62 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io" - "os" - - "github.com/osbuild/images/pkg/osbuild" - - "github.com/osbuild/images/internal/otkdisk" -) - -type Input struct { - Tree otkdisk.Data `json:"tree"` -} - -func makeImagePrepareStages(inp Input, filename string) (stages []*osbuild.Stage, err error) { - defer func() { - if r := recover(); r != nil { - err = fmt.Errorf("cannot generate image prepare stages: %v", r) - } - }() - - // rhel7 uses PTSgdisk, if we ever need to support this, make this - // configurable - partTool := osbuild.PTSfdisk - stages = osbuild.GenImagePrepareStages(inp.Tree.Const.Internal.PartitionTable, inp.Tree.Const.Filename, partTool) - return stages, nil -} - -func run(r io.Reader, w io.Writer) error { - var inp Input - if err := json.NewDecoder(r).Decode(&inp); err != nil { - return err - } - if err := inp.Tree.Validate(); err != nil { - return fmt.Errorf("cannot validate input data: %w", err) - } - - stages, err := makeImagePrepareStages(inp, inp.Tree.Const.Filename) - if err != nil { - return fmt.Errorf("cannot make partition stages: %w", err) - } - - stagesInTree := map[string]interface{}{ - "tree": stages, - } - outputJson, err := json.MarshalIndent(stagesInTree, "", " ") - if err != nil { - return fmt.Errorf("cannot marshal response: %w", err) - } - fmt.Fprintf(w, "%s\n", outputJson) - return nil -} - -func main() { - if err := run(os.Stdin, os.Stdout); err != nil { - fmt.Fprintf(os.Stderr, "error: %v", err.Error()) - os.Exit(1) - } -} diff --git a/cmd/otk/osbuild-make-partition-stages/main_test.go b/cmd/otk/osbuild-make-partition-stages/main_test.go deleted file mode 100644 index a92526f0e8..0000000000 --- a/cmd/otk/osbuild-make-partition-stages/main_test.go +++ /dev/null @@ -1,134 +0,0 @@ -package main_test - -import ( - "bytes" - "encoding/json" - "strings" - "testing" - - "github.com/stretchr/testify/assert" - - makestages "github.com/osbuild/images/cmd/otk/osbuild-make-partition-stages" - "github.com/osbuild/images/internal/otkdisk" - "github.com/osbuild/images/pkg/disk" -) - -// this is not symetrical to the output, this is sad but also -// okay because the input is really just a dump of the internal -// disk.PartitionTable so encoding it in json here will not add -// a benefit for the test -var minimalInputBase = makestages.Input{ - Tree: otkdisk.Data{ - Const: otkdisk.Const{ - Internal: otkdisk.Internal{ - PartitionTable: &disk.PartitionTable{ - Size: 10738466816, - UUID: "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8", - Type: disk.PT_DOS, - Partitions: []disk.Partition{ - { - Start: 1048576, - Size: 10737418240, - Payload: &disk.Filesystem{ - Type: "ext4", - UUID: "6e4ff95f-f662-45ee-a82a-bdf44a2d0b75", - Mountpoint: "/", - }, - }, - }, - }, - }, - }, - }, -} - -var minimalExpectedStages = `{ - "tree": [ - { - "type": "org.osbuild.truncate", - "options": { - "filename": "disk.img", - "size": "10738466816" - } - }, - { - "type": "org.osbuild.sfdisk", - "options": { - "label": "dos", - "uuid": "0194fdc2-fa2f-4cc0-81d3-ff12045b73c8", - "partitions": [ - { - "size": 20971520, - "start": 2048 - } - ] - }, - "devices": { - "device": { - "type": "org.osbuild.loopback", - "options": { - "filename": "disk.img", - "lock": true - } - } - } - }, - { - "type": "org.osbuild.mkfs.ext4", - "options": { - "uuid": "6e4ff95f-f662-45ee-a82a-bdf44a2d0b75" - }, - "devices": { - "device": { - "type": "org.osbuild.loopback", - "options": { - "filename": "disk.img", - "start": 2048, - "size": 20971520, - "lock": true - } - } - } - } - ] -} -` - -func TestIntegration(t *testing.T) { - minimalInput := minimalInputBase - minimalInput.Tree.Const.Filename = "disk.img" - expectedStages := minimalExpectedStages - - inpJSON, err := json.Marshal(&minimalInput) - assert.NoError(t, err) - fakeStdin := bytes.NewBuffer(inpJSON) - fakeStdout := bytes.NewBuffer(nil) - - err = makestages.Run(fakeStdin, fakeStdout) - assert.NoError(t, err) - - assert.Equal(t, expectedStages, fakeStdout.String()) -} - -func TestModificationFname(t *testing.T) { - input := minimalInputBase - input.Tree.Const.Filename = "mydisk.img2" - expectedStages := strings.ReplaceAll(minimalExpectedStages, `"disk.img"`, `"mydisk.img2"`) - - inpJSON, err := json.Marshal(&input) - assert.NoError(t, err) - fakeStdin := bytes.NewBuffer(inpJSON) - fakeStdout := bytes.NewBuffer(nil) - - err = makestages.Run(fakeStdin, fakeStdout) - assert.NoError(t, err) - - assert.Equal(t, expectedStages, fakeStdout.String()) -} - -func TestIntegrationNoPartitionTable(t *testing.T) { - fakeStdin := bytes.NewBufferString(`{}`) - fakeStdout := bytes.NewBuffer(nil) - err := makestages.Run(fakeStdin, fakeStdout) - assert.EqualError(t, err, "cannot validate input data: no partition table") -} diff --git a/cmd/otk/osbuild-resolve-containers/export_test.go b/cmd/otk/osbuild-resolve-containers/export_test.go deleted file mode 100644 index 77c5f1a937..0000000000 --- a/cmd/otk/osbuild-resolve-containers/export_test.go +++ /dev/null @@ -1,5 +0,0 @@ -package main - -var ( - Run = run -) diff --git a/cmd/otk/osbuild-resolve-containers/main.go b/cmd/otk/osbuild-resolve-containers/main.go deleted file mode 100644 index f5421d9b1c..0000000000 --- a/cmd/otk/osbuild-resolve-containers/main.go +++ /dev/null @@ -1,114 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io" - "os" - - "github.com/osbuild/blueprint/pkg/blueprint" - "github.com/osbuild/images/pkg/container" -) - -// All otk external inputs are nested under a top-level "tree" -type Tree struct { - Tree Input `json:"tree"` -} - -// Input represents the user-provided inputs that will be used to resolve a -// container image. -type Input struct { - // The architecture of the container images to resolve. - Arch string `json:"arch"` - - // List of container refs to resolve. - Containers []blueprint.Container `json:"containers"` -} - -// Output contains everything needed to write a manifest that requires pulling -// container images. -type Output struct { - Const OutputConst `json:"const"` -} - -type OutputConst struct { - Containers []ContainerInfo `json:"containers"` -} - -type ContainerInfo struct { - Source string `json:"source"` - - // Digest of the manifest at the source. - Digest string `json:"digest"` - - // Container image identifier. - ImageID string `json:"imageid"` - - // Name to use inside the image. - LocalName string `json:"local-name"` - - // Digest of the list manifest at the source - ListDigest string `json:"list-digest,omitempty"` - - // The architecture of the image - Arch string `json:"arch"` - - TLSVerify *bool `json:"tls-verify,omitempty"` -} - -func run(r io.Reader, w io.Writer) error { - var inputTree Tree - if err := json.NewDecoder(r).Decode(&inputTree); err != nil { - return err - } - - resolver := container.NewResolver(inputTree.Tree.Arch) - - for _, bpSpec := range inputTree.Tree.Containers { - srcSpec := container.SourceSpec{ - Source: bpSpec.Source, - Name: bpSpec.Name, - TLSVerify: bpSpec.TLSVerify, - } - resolver.Add(srcSpec) - } - - containerSpecs, err := resolver.Finish() - if err != nil { - return err - } - containerInfos := make([]ContainerInfo, len(containerSpecs)) - for idx := range containerSpecs { - spec := containerSpecs[idx] - containerInfos[idx] = ContainerInfo{ - Source: spec.Source, - Digest: spec.Digest, - ImageID: spec.ImageID, - LocalName: spec.LocalName, - ListDigest: spec.ListDigest, - Arch: spec.Arch.String(), - TLSVerify: spec.TLSVerify, - } - } - - output := map[string]Output{ - "tree": { - Const: OutputConst{ - Containers: containerInfos, - }, - }, - } - outputJson, err := json.MarshalIndent(output, "", " ") - if err != nil { - return fmt.Errorf("cannot marshal response: %w", err) - } - fmt.Fprintf(w, "%s\n", outputJson) - return nil -} - -func main() { - if err := run(os.Stdin, os.Stdout); err != nil { - fmt.Fprintf(os.Stderr, "error: %v\n", err.Error()) - os.Exit(1) - } -} diff --git a/cmd/otk/osbuild-resolve-containers/main_test.go b/cmd/otk/osbuild-resolve-containers/main_test.go deleted file mode 100644 index a3792cf42d..0000000000 --- a/cmd/otk/osbuild-resolve-containers/main_test.go +++ /dev/null @@ -1,251 +0,0 @@ -package main_test - -import ( - "bytes" - "encoding/json" - "fmt" - "strings" - "testing" - "time" - - "github.com/osbuild/blueprint/pkg/blueprint" - "github.com/osbuild/images/internal/common" - "github.com/osbuild/images/internal/testregistry" - "github.com/osbuild/images/pkg/arch" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - resolver "github.com/osbuild/images/cmd/otk/osbuild-resolve-containers" -) - -const ( - owner = "osbuild" - reponame = "testcontainer" -) - -func createTestRegistry() (*testregistry.Registry, []string) { - registry := testregistry.New() - repo := registry.AddRepo(fmt.Sprintf("%s/%s", owner, reponame)) - ref := registry.GetRef(fmt.Sprintf("%s/%s", owner, reponame)) - - // add 10 images, all in the same repository with the same content - // (rootLayer), but each with a different tag and comment - refs := make([]string, 10) - for idx := 0; idx < len(refs); idx++ { - checksum := repo.AddImage( - []testregistry.Blob{testregistry.NewDataBlobFromBase64(testregistry.RootLayer)}, - []string{"amd64", "ppc64le"}, - fmt.Sprintf("image %d", idx), - time.Time{}) - - tag := fmt.Sprintf("tag-%d", idx) - repo.AddTag(checksum, tag) - refs[idx] = fmt.Sprintf("%s:%s", ref, tag) - } - return registry, refs -} - -func TestResolver(t *testing.T) { - registry, refs := createTestRegistry() - defer registry.Close() - - inpContainers := make([]blueprint.Container, len(refs)) - for idx, ref := range refs { - inpContainers[idx] = blueprint.Container{ - Source: ref, - Name: fmt.Sprintf("test/localhost/%s", ref), // add a prefix for the local name to override the source - TLSVerify: common.ToPtr(false), - LocalStorage: false, - } - } - - for _, containerArch := range []string{"amd64", "ppc64le"} { - t.Run(containerArch, func(t *testing.T) { - - require := require.New(t) - assert := assert.New(t) - - input := map[string]interface{}{ - "arch": containerArch, - "containers": inpContainers, - } - inputReq, err := json.Marshal(map[string]map[string]interface{}{ - "tree": input, - }) - require.NoError(err) - - inpBuf := bytes.NewBuffer(inputReq) - outBuf := &bytes.Buffer{} - - assert.NoError(resolver.Run(inpBuf, outBuf)) - - var output map[string]resolver.Output - require.NoError(json.Unmarshal(outBuf.Bytes(), &output)) - - outputContainers := output["tree"].Const.Containers - - assert.Len(outputContainers, len(refs)) - - expectedOutput := make([]resolver.ContainerInfo, len(refs)) - for idx, ref := range refs { - // resolve directly with the registry and convert to ContainerInfo to - // compare with output. - spec, err := registry.Resolve(ref, common.Must(arch.FromString(containerArch))) - assert.NoError(err) - expectedOutput[idx] = resolver.ContainerInfo{ - Source: spec.Source, - Digest: spec.Digest, - ImageID: spec.ImageID, - // registry.Resolve() copies the ref to the local name but the - // resolver will add the user-defined local name instead - LocalName: fmt.Sprintf("test/localhost/%s", ref), - ListDigest: spec.ListDigest, - Arch: spec.Arch.String(), - TLSVerify: spec.TLSVerify, - } - } - - // NOTE: the order of containers in the resolver's output is stable but is - // not the same as the order of the inputs. - assert.ElementsMatch(outputContainers, expectedOutput) - }) - } -} - -func TestResolverUnhappy(t *testing.T) { - registry, refs := createTestRegistry() - defer registry.Close() - - type testCase struct { - source string - arch string - tlsverify bool - errSubstr string - } - - testCases := map[string]testCase{ - "bad-registry": { - source: "127.0.0.2:1990/org/repo:tag", - arch: "amd64", - errSubstr: "127.0.0.2:1990: connect: connection refused", - }, - "bad-repo": { - // modify the container path of an existing ref - source: strings.Replace(refs[0], owner, "notosbuild", 1), - arch: "amd64", - errSubstr: fmt.Sprintf("notosbuild/%s: StatusCode: 404", reponame), - }, - "bad-repo-containername": { - // modify the container path of an existing ref - source: strings.Replace(refs[0], reponame, "container-does-not-exist", 1), - arch: "amd64", - errSubstr: fmt.Sprintf("%s/container-does-not-exist: StatusCode: 404", owner), - }, - "bad-tag": { - // modify the tag of an existing ref - source: strings.Replace(refs[0], "tag", "not-a-tag", 1), - arch: "amd64", - errSubstr: "error getting manifest: reading manifest not-a-tag-0", - }, - "bad-arch": { - source: refs[0], - arch: "s390x", - errSubstr: "no image found in manifest list for architecture \"s390x\"", - }, - "tls-fail": { - source: refs[0], - arch: "amd64", - tlsverify: true, - errSubstr: "failed to verify certificate: x509: certificate signed by unknown authority", - }, - } - - for name := range testCases { - tc := testCases[name] - t.Run(name, func(t *testing.T) { - require := require.New(t) - assert := assert.New(t) - - input := map[string]interface{}{ - "arch": tc.arch, - "containers": []blueprint.Container{ - { - Source: tc.source, - TLSVerify: &tc.tlsverify, - }, - }, - } - inputReq, err := json.Marshal(map[string]map[string]interface{}{ - "tree": input, - }) - require.NoError(err) - inpBuf := bytes.NewBuffer(inputReq) - outBuf := &bytes.Buffer{} - assert.ErrorContains(resolver.Run(inpBuf, outBuf), tc.errSubstr) - }) - } -} - -func TestResolverRawJSON(t *testing.T) { - require := require.New(t) - - registry, refs := createTestRegistry() - defer registry.Close() - - inpContainers := make([]blueprint.Container, len(refs)) - for idx, ref := range refs { - inpContainers[idx] = blueprint.Container{ - Source: ref, - Name: fmt.Sprintf("test/localhost/%s", ref), // add a prefix for the local name to override the source - TLSVerify: common.ToPtr(false), - LocalStorage: false, - } - } - - for _, containerArch := range []string{"amd64", "ppc64le"} { - t.Run(containerArch, func(t *testing.T) { - cntName := fmt.Sprintf("test/localhost/%s", refs[0]) - inpBuf := bytes.NewBufferString(fmt.Sprintf(`{ -"tree":{ - "arch":"%s", - "containers":[ - { - "source":"%s", - "name":"%s", - "tls-verify":false - } - ] - } -}`, containerArch, refs[0], cntName)) - outBuf := &bytes.Buffer{} - - err := resolver.Run(inpBuf, outBuf) - require.NoError(err) - - // resolve directly with the registry and convert to a raw JSON - // string to compare with output - spec, err := registry.Resolve(refs[0], common.Must(arch.FromString(containerArch))) - require.NoError(err) - - expected := fmt.Sprintf(`{ - "tree": { - "const": { - "containers": [ - { - "source": "%s", - "digest": "%s", - "imageid": "%s", - "local-name": "%s", - "list-digest": "%s", - "arch": "%s", - "tls-verify": %v - } - ] - } - } -} -`, spec.Source, spec.Digest, spec.ImageID, fmt.Sprintf("test/localhost/%s", refs[0]), spec.ListDigest, spec.Arch, *spec.TLSVerify) - require.Equal(expected, outBuf.String()) - }) - } -} diff --git a/cmd/otk/osbuild-resolve-ostree-commit/export_test.go b/cmd/otk/osbuild-resolve-ostree-commit/export_test.go deleted file mode 100644 index 2de3e0d412..0000000000 --- a/cmd/otk/osbuild-resolve-ostree-commit/export_test.go +++ /dev/null @@ -1,18 +0,0 @@ -package main - -var ( - Run = run -) - -func MockEnvLookup() (restore func()) { - saved := osLookupEnv - osLookupEnv = func(key string) (string, bool) { - if key == "OTK_UNDER_TEST" { - return "1", true - } - return "", false - } - return func() { - osLookupEnv = saved - } -} diff --git a/cmd/otk/osbuild-resolve-ostree-commit/main.go b/cmd/otk/osbuild-resolve-ostree-commit/main.go deleted file mode 100644 index 962a998c74..0000000000 --- a/cmd/otk/osbuild-resolve-ostree-commit/main.go +++ /dev/null @@ -1,110 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io" - "os" - - "github.com/osbuild/images/internal/otkostree" - "github.com/osbuild/images/pkg/manifestgen/manifestmock" - "github.com/osbuild/images/pkg/ostree" -) - -// All otk external inputs are nested under a top-level "tree" -type Tree struct { - Tree Input `json:"tree"` -} - -// Input represents the user-provided inputs that will be used to resolve an -// ostree commit ID. -type Input struct { - // URL of the repo where the commit can be fetched. - URL string `json:"url"` - - // Ref to resolve. - Ref string `json:"ref"` - - // Whether to use RHSM secrets when resolving and fetching the commit. - RHSM bool `json:"rhsm,omitempty"` - - // MTLS information. Will be ignored if RHSM is set. - MTLS *struct { - CA string `json:"ca"` - ClientCert string `json:"client_cert"` - ClientKey string `json:"client_key"` - } `json:"mtls,omitempty"` - - // HTTP proxy to use when fetching the ref. - Proxy string `json:"proxy,omitempty"` -} - -// Output contains everything needed to write a manifest that requires pulling -// an ostree commit. -type Output struct { - Const otkostree.ResolvedConst `json:"const"` -} - -// for mocking in testing -var osLookupEnv = os.LookupEnv - -func underTest() bool { - testVar, found := osLookupEnv("OTK_UNDER_TEST") - return found && testVar == "1" -} - -func run(r io.Reader, w io.Writer) error { - var inputTree Tree - if err := json.NewDecoder(r).Decode(&inputTree); err != nil { - return err - } - - sourceSpec := ostree.SourceSpec{ - URL: inputTree.Tree.URL, - Ref: inputTree.Tree.Ref, - RHSM: inputTree.Tree.RHSM, - Proxy: inputTree.Tree.Proxy, - } - - if inputTree.Tree.MTLS != nil { - sourceSpec.MTLS = &ostree.MTLS{} - sourceSpec.MTLS.CA = inputTree.Tree.MTLS.CA - sourceSpec.MTLS.ClientCert = inputTree.Tree.MTLS.ClientCert - sourceSpec.MTLS.ClientKey = inputTree.Tree.MTLS.ClientKey - } - - var commitSpec ostree.CommitSpec - if !underTest() { - var err error - commitSpec, err = ostree.Resolve(sourceSpec) - if err != nil { - return fmt.Errorf("failed to resolve ostree commit: %w", err) - } - } else { - commitSpec = manifestmock.OSTreeResolve(sourceSpec) - } - - output := map[string]Output{ - "tree": { - Const: otkostree.ResolvedConst{ - Ref: commitSpec.Ref, - URL: commitSpec.URL, - Secrets: commitSpec.Secrets, - Checksum: commitSpec.Checksum, - }, - }, - } - outputJson, err := json.MarshalIndent(output, "", " ") - if err != nil { - return fmt.Errorf("cannot marshal response: %w", err) - } - fmt.Fprintf(w, "%s\n", outputJson) - return nil -} - -func main() { - if err := run(os.Stdin, os.Stdout); err != nil { - fmt.Fprintf(os.Stderr, "error: %v\n", err.Error()) - os.Exit(1) - } -} diff --git a/cmd/otk/osbuild-resolve-ostree-commit/main_test.go b/cmd/otk/osbuild-resolve-ostree-commit/main_test.go deleted file mode 100644 index 8d80b3f4ab..0000000000 --- a/cmd/otk/osbuild-resolve-ostree-commit/main_test.go +++ /dev/null @@ -1,297 +0,0 @@ -package main_test - -import ( - "bytes" - "encoding/json" - "fmt" - "net/http" - "net/http/httptest" - "strings" - "testing" - - resolver "github.com/osbuild/images/cmd/otk/osbuild-resolve-ostree-commit" - "github.com/osbuild/images/pkg/ostree/test_mtls_server" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -var commitMap = map[string]string{ - "centos/9/x86_64/edge": "d04105393ca0617856b34f897842833d785522e41617e17dca2063bf97e294ef", - "fake/ref/f": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "fake/ref/9": "9999999999999999999999999999999999999999999999999999999999999999", - "test/ref/alpha": "9b1ea9a8e10dc27d4ea40545bec028ad8e360dd26d18de64b0f6217833a8443d", - "test/ref/one": "7433e1b49fb136d61dcca49ebe34e713fdbb8e29bf328fe90819628f71b86105", -} - -const TestCertDir = "../../../pkg/ostree/test_mtls_server" - -// Create a test server that responds with the commit ID that corresponds to -// the ref. -func createTestServer(refIDs map[string]string) *httptest.Server { - handler := createTestHandler(refIDs) - - return httptest.NewServer(handler) -} - -// Create a test server that responds with the commit ID that corresponds to -// the ref. MTLS variant. -func createMTLSTestServer(refIDs map[string]string) *httptest.Server { - handler := createTestHandler(refIDs) - - mtlss, err := test_mtls_server.NewMTLSServerInPath(handler, TestCertDir) - if err != nil { - panic(err) - } - - return mtlss.Server -} - -func createTestHandler(refIDs map[string]string) *http.ServeMux { - handler := http.NewServeMux() - handler.HandleFunc("/refs/heads/", func(w http.ResponseWriter, r *http.Request) { - reqRef := strings.TrimPrefix(r.URL.Path, "/refs/heads/") - id, ok := refIDs[reqRef] - if !ok { - http.NotFound(w, r) - return - } - fmt.Fprint(w, id) - }) - - return handler -} - -func TestResolver(t *testing.T) { - require := require.New(t) - assert := assert.New(t) - - repoServer := createTestServer(commitMap) - defer repoServer.Close() - - url := repoServer.URL - for ref, id := range commitMap { - inputReq, err := json.Marshal(map[string]map[string]string{ - "tree": { - "url": url, - "ref": ref, - }, - }) - require.NoError(err) - - inpBuf := bytes.NewBuffer(inputReq) - outBuf := &bytes.Buffer{} - - assert.NoError(resolver.Run(inpBuf, outBuf)) - - var output map[string]map[string]map[string]string - require.NoError(json.Unmarshal(outBuf.Bytes(), &output)) - - expOutput := map[string]map[string]map[string]string{ - "tree": { - "const": { - "url": url, - "ref": ref, - "checksum": id, - }, - }, - } - assert.Equal(expOutput, output) - } -} - -func TestResolverMTLS(t *testing.T) { - require := require.New(t) - assert := assert.New(t) - - repoServer := createMTLSTestServer(commitMap) - defer repoServer.Close() - - url := repoServer.URL - for ref, id := range commitMap { - inputReq, err := json.Marshal(map[string]interface{}{ - "tree": map[string]interface{}{ - "url": url, - "ref": ref, - "mtls": map[string]string{ - "ca": fmt.Sprintf("%s/ca.crt", TestCertDir), - "client_cert": fmt.Sprintf("%s/client.crt", TestCertDir), - "client_key": fmt.Sprintf("%s/client.key", TestCertDir), - }, - }, - }) - require.NoError(err) - - inpBuf := bytes.NewBuffer(inputReq) - outBuf := &bytes.Buffer{} - - assert.NoError(resolver.Run(inpBuf, outBuf)) - - var output map[string]map[string]map[string]string - require.NoError(json.Unmarshal(outBuf.Bytes(), &output)) - - expOutput := map[string]map[string]map[string]string{ - "tree": { - "const": { - "url": url, - "ref": ref, - "checksum": id, - "secrets": "org.osbuild.mtls", - }, - }, - } - assert.Equal(expOutput, output) - } -} - -func TestResolverByID(t *testing.T) { - require := require.New(t) - assert := assert.New(t) - - for _, id := range commitMap { - inputReq, err := json.Marshal(map[string]map[string]string{ - "tree": { - "ref": id, - }, - }) - require.NoError(err) - - inpBuf := bytes.NewBuffer(inputReq) - outBuf := &bytes.Buffer{} - - assert.NoError(resolver.Run(inpBuf, outBuf)) - - var output map[string]map[string]map[string]string - require.NoError(json.Unmarshal(outBuf.Bytes(), &output)) - - expOutput := map[string]map[string]map[string]string{ - "tree": { - "const": { - "ref": id, - "checksum": id, - "url": "", - }, - }, - } - assert.Equal(expOutput, output) - } -} -func TestResolverIDwithURL(t *testing.T) { - - require := require.New(t) - assert := assert.New(t) - - // the URL is not used when the ref is a commit ID, but it should be returned in the output - url := "https://doesnt-matter.example.org" - for _, id := range commitMap { - inputReq, err := json.Marshal(map[string]map[string]string{ - "tree": { - "ref": id, - "url": url, - }, - }) - require.NoError(err) - - inpBuf := bytes.NewBuffer(inputReq) - outBuf := &bytes.Buffer{} - - assert.NoError(resolver.Run(inpBuf, outBuf)) - - var output map[string]map[string]map[string]string - require.NoError(json.Unmarshal(outBuf.Bytes(), &output)) - - expOutput := map[string]map[string]map[string]string{ - "tree": { - "const": { - "ref": id, - "checksum": id, - "url": url, - }, - }, - } - assert.Equal(expOutput, output) - } -} - -func TestResolverErrors(t *testing.T) { - - repoServer := createTestServer(commitMap) - defer repoServer.Close() - - type testCase struct { - url string - ref string - errSubstring string - } - - testCases := map[string]testCase{ - "bad-ref": { - url: "doesn't matter", - ref: "---", - errSubstring: "Invalid ostree ref or commit", - }, - "ref-not-found": { - url: repoServer.URL, - ref: "good/ref/but/does-not-exist", - errSubstring: "returned status: 404 Not Found", - }, - } - - for name := range testCases { - tc := testCases[name] - t.Run(name, func(t *testing.T) { - require := require.New(t) - assert := assert.New(t) - - inputReq, err := json.Marshal(map[string]map[string]string{ - "tree": { - "url": tc.url, - "ref": tc.ref, - }, - }) - require.NoError(err) - - inpBuf := bytes.NewBuffer(inputReq) - outBuf := &bytes.Buffer{} - - assert.ErrorContains(resolver.Run(inpBuf, outBuf), tc.errSubstring) - }) - } -} - -func TestMockResolve(t *testing.T) { - restore := resolver.MockEnvLookup() - defer restore() - - assert := assert.New(t) - - inputReq := ` -{ - "tree": { - "ref": "otk/ostree/test", - "url": "https://ostree.example.org/repo", - "mtls": { - "ca": "ca.crt", - "client_cert": "client.crt", - "client_key": "client.key" - }, - "proxy": "proxy.example.com:8080" - } -} -` - expOutput := `{ - "tree": { - "const": { - "ref": "otk/ostree/test", - "url": "https://ostree.example.org/repo", - "checksum": "5c1c0655481926623eca85109dd4017c8dba320ea1473c42b43005db6d900a60" - } - } -} -` - input := bytes.NewBuffer([]byte(inputReq)) - output := &bytes.Buffer{} - - assert.NoError(resolver.Run(input, output)) - - assert.Equal(expOutput, output.String()) -} diff --git a/internal/otkdisk/partition.go b/internal/otkdisk/partition.go deleted file mode 100644 index 1803739085..0000000000 --- a/internal/otkdisk/partition.go +++ /dev/null @@ -1,83 +0,0 @@ -package otkdisk - -import ( - "fmt" - - "slices" - - "github.com/osbuild/images/pkg/disk" -) - -// Data contains the full description of the partition table as well as extra -// options and a PartitionMap for easier access. The data under Const should -// not be modified by a consumer of this data structure. -type Data struct { - Const Const `json:"const"` -} - -// Validate does basic validation of the data -func (d Data) Validate() error { - return d.Const.Internal.Validate() -} - -// Const contains partition table data that is considered "constant", -// i.e. that should not be modified by the consumer as there may be -// inter-dependencies between the values -type Const struct { - KernelOptsList []string `json:"kernel_opts_list"` - - // PartitionMap is generated for convenient indexing of certain partitions - // with predictable names in otk, such as - // "filesystem.partition_map.boot.uuid" - PartitionMap map[string]Partition `json:"partition_map"` - - // Internal representation of the full partition table. The representation - // is internal to the partition tools and should not be used by otk - // directly. It makes no external API guarantees about the content or - // structure. - Internal Internal `json:"internal"` - - // Filename for the disk image. - Filename string `json:"filename"` -} - -// Partition represents an exported view of a partition. This is an API so only -// add things here that are necessary for convenient external access and -// unlikely to change. -type Partition struct { - // NOTE: Not a UUID type because fat UUIDs are not compliant - UUID string `json:"uuid"` -} - -// Interal contains partition table data that is stricly internal and -// may change in non-backward compatible ways. No "otk" manifest -// should ever use this directly, it's strictly meant for the -// "otk-{gen,make}-*" tools for their data exchange. -type Internal struct { - PartitionTable *disk.PartitionTable `json:"partition-table"` -} - -// Validate does basic validation of the internal data -func (i Internal) Validate() error { - if i.PartitionTable == nil { - return fmt.Errorf("no partition table") - } - return nil -} - -// PartType represents a partition type -type PartType string - -const ( - PartTypeUnset PartType = "" - PartTypeGPT PartType = "gpt" - PartTypeDOS PartType = "dos" -) - -// Validate validates that the given PartType is valid -func (p PartType) Validate() error { - if !slices.Contains([]PartType{PartTypeGPT, PartTypeDOS}, p) { - return fmt.Errorf("unsupported partition type %q", p) - } - return nil -} diff --git a/internal/otkdisk/partition_test.go b/internal/otkdisk/partition_test.go deleted file mode 100644 index f9aadd87f3..0000000000 --- a/internal/otkdisk/partition_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package otkdisk_test - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/osbuild/images/internal/otkdisk" - "github.com/osbuild/images/pkg/disk" -) - -func TestPartTypeValidationHappy(t *testing.T) { - assert.NoError(t, otkdisk.PartTypeDOS.Validate()) - assert.NoError(t, otkdisk.PartTypeGPT.Validate()) -} - -func TestPartTypeValidationSad(t *testing.T) { - assert.EqualError(t, otkdisk.PartTypeUnset.Validate(), `unsupported partition type ""`) - assert.EqualError(t, otkdisk.PartType("foo").Validate(), `unsupported partition type "foo"`) -} - -func TestDataValidates(t *testing.T) { - // sad - d := otkdisk.Data{} - assert.EqualError(t, d.Validate(), "no partition table") - // happy - d.Const.Internal.PartitionTable = &disk.PartitionTable{} - err := d.Validate() - assert.NoError(t, err) -} diff --git a/internal/otkostree/types.go b/internal/otkostree/types.go deleted file mode 100644 index a3c66e91ce..0000000000 --- a/internal/otkostree/types.go +++ /dev/null @@ -1,16 +0,0 @@ -package otkostree - -type ResolvedConst struct { - // Ref of the commit (can be empty). - Ref string `json:"ref,omitempty"` - - // URL of the repo where the commit can be fetched. - URL string `json:"url"` - - // Secrets type to use when pulling the ostree commit content - // (e.g. org.osbuild.rhsm.consumer). - Secrets string `json:"secrets,omitempty"` - - // Checksum of the commit. - Checksum string `json:"checksum"` -}