customizations: custom repo utility functions

Create some utility functions that will be used for implementing
custom repo configuration files. This commit adds these functions:
- a helper to get the filename of a custom repo, or the
  `<repo-id>.repo` if the filename is empty
- a function to convert the custom repos to a map of `RepoConfig`.
  This function also creates an `fsnode.File` for each inline gpg
  key set in the customizations and swaps the inline key for the
  file path. The function returns the map of `RepoConfig` and a list
  of `fsnode.File` containing the inline gpg keys.
This commit is contained in:
Gianluca Zuccarelli 2023-04-17 21:13:09 +01:00 committed by Tomáš Hozza
parent 3b6fddb14a
commit 29643c2e06
2 changed files with 324 additions and 0 deletions

View file

@ -2,6 +2,10 @@ package blueprint
import (
"fmt"
"net/url"
"github.com/osbuild/osbuild-composer/internal/fsnode"
"github.com/osbuild/osbuild-composer/internal/rpmmd"
)
type RepositoryCustomization struct {
@ -33,3 +37,68 @@ func validateCustomRepository(repo *RepositoryCustomization) error {
}
return nil
}
func (rc *RepositoryCustomization) getFilename() string {
if rc.Filename == "" {
return fmt.Sprintf("%s.repo", rc.Id)
}
return rc.Filename
}
func RepoCustomizationsToRepoConfigAndGPGKeyFiles(repos []RepositoryCustomization) (map[string][]rpmmd.RepoConfig, []*fsnode.File, error) {
if len(repos) == 0 {
return nil, nil, nil
}
repoMap := make(map[string][]rpmmd.RepoConfig, len(repos))
var gpgKeyFiles []*fsnode.File
for _, repo := range repos {
filename := repo.getFilename()
convertedRepo := repo.customRepoToRepoConfig()
// convert any inline gpgkeys to fsnode.File and
// replace the gpgkey with the file path
for idx, gpgkey := range repo.GPGKeys {
if _, ok := url.ParseRequestURI(gpgkey); ok != nil {
// create the file path
path := fmt.Sprintf("/etc/pki/rpm-gpg/RPM-GPG-KEY-%s-%d", repo.Id, idx)
// replace the gpgkey with the file path
convertedRepo.GPGKeys[idx] = fmt.Sprintf("file://%s", path)
// create the fsnode for the gpgkey keyFile
keyFile, err := fsnode.NewFile(path, nil, nil, nil, []byte(gpgkey))
if err != nil {
return nil, nil, err
}
gpgKeyFiles = append(gpgKeyFiles, keyFile)
}
}
repoMap[filename] = append(repoMap[filename], convertedRepo)
}
return repoMap, gpgKeyFiles, nil
}
func (repo RepositoryCustomization) customRepoToRepoConfig() rpmmd.RepoConfig {
urls := make([]string, len(repo.BaseURLs))
copy(urls, repo.BaseURLs)
keys := make([]string, len(repo.GPGKeys))
copy(keys, repo.GPGKeys)
repoConfig := rpmmd.RepoConfig{
Id: repo.Id,
BaseURLs: urls,
GPGKeys: keys,
Name: repo.Name,
Metalink: repo.Metalink,
MirrorList: repo.Mirrorlist,
CheckGPG: repo.GPGCheck,
CheckRepoGPG: repo.RepoGPGCheck,
Priority: repo.Priority,
Enabled: repo.Enabled,
IgnoreSSL: !repo.SSLVerify,
}
return repoConfig
}

View file

@ -5,6 +5,8 @@ import (
"testing"
"github.com/osbuild/osbuild-composer/internal/common"
"github.com/osbuild/osbuild-composer/internal/fsnode"
"github.com/osbuild/osbuild-composer/internal/rpmmd"
"github.com/stretchr/testify/assert"
)
@ -78,3 +80,256 @@ func TestGetCustomRepositories(t *testing.T) {
})
}
}
func TestCustomRepoFilename(t *testing.T) {
testCases := []struct {
Name string
Repo RepositoryCustomization
WantFilename string
}{
{
Name: "Test default filename #1",
Repo: RepositoryCustomization{
Id: "example-1",
BaseURLs: []string{"http://example-1.com"},
},
WantFilename: "example-1.repo",
},
{
Name: "Test default filename #2",
Repo: RepositoryCustomization{
Id: "example-2",
BaseURLs: []string{"http://example-1.com"},
},
WantFilename: "example-2.repo",
},
{
Name: "Test custom filename",
Repo: RepositoryCustomization{
Id: "example-1",
BaseURLs: []string{"http://example-1.com"},
Filename: "test.repo",
},
WantFilename: "test.repo",
},
}
for _, tt := range testCases {
t.Run(tt.Name, func(t *testing.T) {
got := tt.Repo.getFilename()
assert.Equal(t, tt.WantFilename, got)
})
}
}
func TestCustomRepoToRepoConfigAndGPGKeys(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
Repos []RepositoryCustomization
WantRepoConfig map[string][]rpmmd.RepoConfig
WantGPGKeys []*fsnode.File
}{
{
Name: "Test no gpg keys, no filenames",
Repos: []RepositoryCustomization{
{
Id: "example-1",
BaseURLs: []string{"http://example-1.com"},
SSLVerify: true,
},
{
Id: "example-2",
BaseURLs: []string{"http://example-2.com"},
SSLVerify: true,
},
},
WantRepoConfig: map[string][]rpmmd.RepoConfig{
"example-1.repo": {
{
Id: "example-1",
BaseURLs: []string{"http://example-1.com"},
GPGKeys: []string{},
},
},
"example-2.repo": {
{
Id: "example-2",
BaseURLs: []string{"http://example-2.com"},
GPGKeys: []string{},
},
},
},
WantGPGKeys: nil,
},
{
Name: "Test no gpg keys, filenames",
Repos: []RepositoryCustomization{
{
Id: "example-1",
BaseURLs: []string{"http://example-1.com"},
SSLVerify: true,
Filename: "test-1.repo",
},
{
Id: "example-2",
BaseURLs: []string{"http://example-2.com"},
SSLVerify: true,
Filename: "test-2.repo",
},
},
WantRepoConfig: map[string][]rpmmd.RepoConfig{
"test-1.repo": {
{
Id: "example-1",
BaseURLs: []string{"http://example-1.com"},
GPGKeys: []string{},
},
},
"test-2.repo": {
{
Id: "example-2",
BaseURLs: []string{"http://example-2.com"},
GPGKeys: []string{},
},
},
},
WantGPGKeys: nil,
},
{
Name: "Test remote gpgkeys",
Repos: []RepositoryCustomization{
{
Id: "example-1",
BaseURLs: []string{"http://example-1.com"},
GPGKeys: []string{"http://example-1.com/gpgkey"},
GPGCheck: common.ToPtr(true),
SSLVerify: true,
},
{
Id: "example-2",
BaseURLs: []string{"http://example-2.com"},
GPGKeys: []string{"http://example-2.com/gpgkey"},
GPGCheck: common.ToPtr(true),
SSLVerify: true,
},
},
WantRepoConfig: map[string][]rpmmd.RepoConfig{
"example-1.repo": {
{
Id: "example-1",
BaseURLs: []string{"http://example-1.com"},
GPGKeys: []string{"http://example-1.com/gpgkey"},
CheckGPG: common.ToPtr(true),
},
},
"example-2.repo": {
{
Id: "example-2",
BaseURLs: []string{"http://example-2.com"},
GPGKeys: []string{"http://example-2.com/gpgkey"},
CheckGPG: common.ToPtr(true),
},
},
},
WantGPGKeys: nil,
},
{
Name: "Test inline gpgkeys",
Repos: []RepositoryCustomization{
{
Id: "example-1",
BaseURLs: []string{"http://example-1.com"},
GPGKeys: []string{"fake-gpg-key-1"},
GPGCheck: common.ToPtr(true),
SSLVerify: true,
},
{
Id: "example-2",
BaseURLs: []string{"http://example-2.com"},
GPGKeys: []string{"fake-gpg-key-2"},
GPGCheck: common.ToPtr(true),
SSLVerify: true,
},
},
WantRepoConfig: map[string][]rpmmd.RepoConfig{
"example-1.repo": {
{
Id: "example-1",
BaseURLs: []string{"http://example-1.com"},
GPGKeys: []string{"file:///etc/pki/rpm-gpg/RPM-GPG-KEY-example-1-0"},
CheckGPG: common.ToPtr(true),
},
},
"example-2.repo": {
{
Id: "example-2",
BaseURLs: []string{"http://example-2.com"},
GPGKeys: []string{"file:///etc/pki/rpm-gpg/RPM-GPG-KEY-example-2-0"},
CheckGPG: common.ToPtr(true),
},
},
},
WantGPGKeys: []*fsnode.File{
ensureFileCreation(fsnode.NewFile("/etc/pki/rpm-gpg/RPM-GPG-KEY-example-1-0", nil, nil, nil, []byte("fake-gpg-key-1"))),
ensureFileCreation(fsnode.NewFile("/etc/pki/rpm-gpg/RPM-GPG-KEY-example-2-0", nil, nil, nil, []byte("fake-gpg-key-1"))),
},
},
{
Name: "Test multiple inline gpgkeys",
Repos: []RepositoryCustomization{
{
Id: "example-1",
BaseURLs: []string{"http://example-1.com"},
GPGKeys: []string{"fake-gpg-key-1", "fake-gpg-key-2"},
GPGCheck: common.ToPtr(true),
SSLVerify: true,
},
{
Id: "example-2",
BaseURLs: []string{"http://example-2.com"},
GPGKeys: []string{"fake-gpg-key-1", "fake-gpg-key-2"},
GPGCheck: common.ToPtr(true),
SSLVerify: true,
},
},
WantRepoConfig: map[string][]rpmmd.RepoConfig{
"example-1.repo": {
{
Id: "example-1",
BaseURLs: []string{"http://example-1.com"},
GPGKeys: []string{"file:///etc/pki/rpm-gpg/RPM-GPG-KEY-example-1-0", "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-example-1-1"},
CheckGPG: common.ToPtr(true),
},
},
"example-2.repo": {
{
Id: "example-2",
BaseURLs: []string{"http://example-2.com"},
GPGKeys: []string{"file:///etc/pki/rpm-gpg/RPM-GPG-KEY-example-2-0", "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-example-2-1"},
CheckGPG: common.ToPtr(true),
},
},
},
WantGPGKeys: []*fsnode.File{
ensureFileCreation(fsnode.NewFile("/etc/pki/rpm-gpg/RPM-GPG-KEY-example-1-0", nil, nil, nil, []byte("fake-gpg-key-1"))),
ensureFileCreation(fsnode.NewFile("/etc/pki/rpm-gpg/RPM-GPG-KEY-example-1-1", nil, nil, nil, []byte("fake-gpg-key-2"))),
ensureFileCreation(fsnode.NewFile("/etc/pki/rpm-gpg/RPM-GPG-KEY-example-2-0", nil, nil, nil, []byte("fake-gpg-key-1"))),
ensureFileCreation(fsnode.NewFile("/etc/pki/rpm-gpg/RPM-GPG-KEY-example-2-1", nil, nil, nil, []byte("fake-gpg-key-2"))),
},
},
}
for _, tt := range testCases {
t.Run(tt.Name, func(t *testing.T) {
got, _, err := RepoCustomizationsToRepoConfigAndGPGKeyFiles(tt.Repos)
assert.NoError(t, err)
assert.Equal(t, tt.WantRepoConfig, got)
})
}
}