blueprint: add functions converting dir and file customizations

Add helper functions for converting slices of directory and file
customizations structures from the `blueprint` package to a slice of
structures from the `fsnode` package, which are used in image type
definitions.

These will be used to convert BP customizations to the os pipeline
customization then used by the pipeline generator.

Signed-off-by: Tomáš Hozza <thozza@redhat.com>
This commit is contained in:
Tomáš Hozza 2023-02-03 14:34:31 +01:00 committed by Sanne Raymaekers
parent c1991b3d51
commit 053c1b090f
2 changed files with 227 additions and 0 deletions

View file

@ -150,6 +150,30 @@ func (d DirectoryCustomization) ToFsNodeDirectory() (*fsnode.Directory, error) {
return fsnode.NewDirectory(d.Path, mode, d.User, d.Group, d.EnsureParents)
}
// DirectoryCustomizationsToFsNodeDirectories converts a slice of DirectoryCustomizations
// to a slice of fsnode.Directories
func DirectoryCustomizationsToFsNodeDirectories(dirs []DirectoryCustomization) ([]*fsnode.Directory, error) {
if len(dirs) == 0 {
return nil, nil
}
var fsDirs []*fsnode.Directory
var errors []error
for _, dir := range dirs {
fsDir, err := dir.ToFsNodeDirectory()
if err != nil {
errors = append(errors, err)
}
fsDirs = append(fsDirs, fsDir)
}
if len(errors) > 0 {
return nil, fmt.Errorf("invalid directory customizations: %v", errors)
}
return fsDirs, nil
}
// FileCustomization represents a file to be created in the image
type FileCustomization struct {
// Absolute path to the file
@ -283,3 +307,26 @@ func (f FileCustomization) ToFsNodeFile() (*fsnode.File, error) {
return fsnode.NewFile(f.Path, mode, f.User, f.Group, data)
}
// FileCustomizationsToFsNodeFiles converts a slice of FileCustomization to a slice of *fsnode.File
func FileCustomizationsToFsNodeFiles(files []FileCustomization) ([]*fsnode.File, error) {
if len(files) == 0 {
return nil, nil
}
var fsFiles []*fsnode.File
var errors []error
for _, file := range files {
fsFile, err := file.ToFsNodeFile()
if err != nil {
errors = append(errors, err)
}
fsFiles = append(fsFiles, fsFile)
}
if len(errors) > 0 {
return nil, fmt.Errorf("invalid file customizations: %v", errors)
}
return fsFiles, nil
}

View file

@ -142,6 +142,94 @@ func TestDirectoryCustomizationToFsNodeDirectory(t *testing.T) {
}
}
func TestDirectoryCustomizationsToFsNodeDirectories(t *testing.T) {
ensureDirCreation := func(dir *fsnode.Directory, err error) *fsnode.Directory {
t.Helper()
assert.NoError(t, err)
assert.NotNil(t, dir)
return dir
}
testCases := []struct {
Name string
Dirs []DirectoryCustomization
WantDirs []*fsnode.Directory
Error bool
}{
{
Name: "empty",
Dirs: []DirectoryCustomization{},
WantDirs: nil,
},
{
Name: "single-directory",
Dirs: []DirectoryCustomization{
{
Path: "/etc/dir",
User: "root",
Group: "root",
Mode: "0700",
EnsureParents: true,
},
},
WantDirs: []*fsnode.Directory{
ensureDirCreation(fsnode.NewDirectory(
"/etc/dir",
common.ToPtr(os.FileMode(0700)),
"root",
"root",
true,
)),
},
},
{
Name: "multiple-directories",
Dirs: []DirectoryCustomization{
{
Path: "/etc/dir",
User: "root",
Group: "root",
},
{
Path: "/etc/dir2",
User: int64(0),
Group: int64(0),
},
},
WantDirs: []*fsnode.Directory{
ensureDirCreation(fsnode.NewDirectory("/etc/dir", nil, "root", "root", false)),
ensureDirCreation(fsnode.NewDirectory("/etc/dir2", nil, int64(0), int64(0), false)),
},
},
{
Name: "multiple-directories-with-errors",
Dirs: []DirectoryCustomization{
{
Path: "/etc/../dir",
},
{
Path: "/etc/dir2",
User: "r@@t",
},
},
Error: true,
},
}
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
dirs, err := DirectoryCustomizationsToFsNodeDirectories(tc.Dirs)
if tc.Error {
assert.Error(t, err)
assert.Nil(t, dirs)
} else {
assert.NoError(t, err)
assert.EqualValues(t, tc.WantDirs, dirs)
}
})
}
}
func TestDirectoryCustomizationUnmarshalTOML(t *testing.T) {
testCases := []struct {
Name string
@ -543,6 +631,98 @@ func TestFileCustomizationToFsNodeFile(t *testing.T) {
}
}
func TestFileCustomizationsToFsNodeFiles(t *testing.T) {
ensureFileCreation := func(file *fsnode.File, err error) *fsnode.File {
t.Helper()
assert.NoError(t, err)
assert.NotNil(t, file)
return file
}
testCases := []struct {
Name string
Files []FileCustomization
Want []*fsnode.File
Error bool
}{
{
Name: "empty",
Files: []FileCustomization{},
Want: nil,
},
{
Name: "single-file",
Files: []FileCustomization{
{
Path: "/etc/file",
User: "root",
Group: "root",
Mode: "0700",
Data: "hello world",
},
},
Want: []*fsnode.File{
ensureFileCreation(fsnode.NewFile(
"/etc/file",
common.ToPtr(os.FileMode(0700)),
"root",
"root",
[]byte("hello world"),
)),
},
},
{
Name: "multiple-files",
Files: []FileCustomization{
{
Path: "/etc/file",
Data: "hello world",
User: "root",
Group: "root",
},
{
Path: "/etc/file2",
Data: "hello world",
User: int64(0),
Group: int64(0),
},
},
Want: []*fsnode.File{
ensureFileCreation(fsnode.NewFile("/etc/file", nil, "root", "root", []byte("hello world"))),
ensureFileCreation(fsnode.NewFile("/etc/file2", nil, int64(0), int64(0), []byte("hello world"))),
},
},
{
Name: "multiple-files-with-errors",
Files: []FileCustomization{
{
Path: "/etc/../file",
Data: "hello world",
},
{
Path: "/etc/file2",
Data: "hello world",
User: "r@@t",
},
},
Error: true,
},
}
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
files, err := FileCustomizationsToFsNodeFiles(tc.Files)
if tc.Error {
assert.Error(t, err)
assert.Nil(t, files)
} else {
assert.NoError(t, err)
assert.EqualValues(t, tc.Want, files)
}
})
}
}
func TestFileCustomizationUnmarshalTOML(t *testing.T) {
testCases := []struct {
Name string