weldr: Expand package name globs in the frozen blueprint
When a blueprint containing package name globs is frozen it was failing because it could not find the string in the dependency list. This fixes it by replacing the package glob with all of the matching packages from the dependency list. This removes the setPkgEVRA function and adds a new expandBlueprintGlobs function that handles the package name glob expansion, and replacement of the version globs with the dependency EVRA. Also includes testing for the new function.
This commit is contained in:
parent
f378ff6367
commit
468c63d433
2 changed files with 185 additions and 64 deletions
|
|
@ -1567,27 +1567,54 @@ func (api *API) blueprintsDepsolveHandler(writer http.ResponseWriter, request *h
|
|||
common.PanicOnError(err)
|
||||
}
|
||||
|
||||
// setPkgEVRA replaces the version globs in the blueprint with their EVRA values from the dependencies
|
||||
//
|
||||
// The dependencies must be pre-sorted for this function to work properly
|
||||
// It will return an error if it cannot find a package in the dependencies
|
||||
func setPkgEVRA(dependencies []rpmmd.PackageSpec, packages []blueprint.Package) error {
|
||||
for pkgIndex, pkg := range packages {
|
||||
i := sort.Search(len(dependencies), func(i int) bool {
|
||||
return dependencies[i].Name >= pkg.Name
|
||||
})
|
||||
if i < len(dependencies) && dependencies[i].Name == pkg.Name {
|
||||
if dependencies[i].Epoch == 0 {
|
||||
packages[pkgIndex].Version = fmt.Sprintf("%s-%s.%s", dependencies[i].Version, dependencies[i].Release, dependencies[i].Arch)
|
||||
} else {
|
||||
packages[pkgIndex].Version = fmt.Sprintf("%d:%s-%s.%s", dependencies[i].Epoch, dependencies[i].Version, dependencies[i].Release, dependencies[i].Arch)
|
||||
// expandBlueprintGlobs will expand package name globs and versions using the depsolve results
|
||||
// The result is a sorted list of Package structs with the full package name and version
|
||||
// It will return an error if it cannot find a non-glob package name in the dependency list
|
||||
func expandBlueprintGlobs(dependencies []rpmmd.PackageSpec, packages []blueprint.Package) ([]blueprint.Package, error) {
|
||||
newPackages := make(map[string]blueprint.Package)
|
||||
|
||||
for _, pkg := range packages {
|
||||
if !strings.ContainsAny(pkg.Name, "*?") {
|
||||
// No glob characters, find an exact match in dependencies
|
||||
i := sort.Search(len(dependencies), func(i int) bool {
|
||||
return dependencies[i].Name >= pkg.Name
|
||||
})
|
||||
if i >= len(dependencies) || dependencies[i].Name != pkg.Name {
|
||||
// Packages should not be missing from the depsolve results
|
||||
return nil, fmt.Errorf("%s missing from depsolve results", pkg.Name)
|
||||
}
|
||||
newPackages[dependencies[i].GetNEVRA()] = blueprint.Package{
|
||||
Name: dependencies[i].Name,
|
||||
Version: dependencies[i].GetEVRA(),
|
||||
}
|
||||
} else {
|
||||
// Packages should not be missing from the depsolve results
|
||||
return fmt.Errorf("%s missing from depsolve results", pkg.Name)
|
||||
// Add all the packages matching the glob
|
||||
g, err := glob.Compile(pkg.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, d := range dependencies {
|
||||
if g.Match(d.Name) {
|
||||
newPackages[d.GetNEVRA()] = blueprint.Package{
|
||||
Name: d.Name,
|
||||
Version: d.GetEVRA(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
// Return a sorted slice of the Packages
|
||||
np := make([]blueprint.Package, 0, len(newPackages))
|
||||
for _, pkg := range newPackages {
|
||||
np = append(np, pkg)
|
||||
}
|
||||
sort.Slice(np, func(i, j int) bool {
|
||||
return np[i].Name < np[j].Name
|
||||
})
|
||||
|
||||
return np, nil
|
||||
}
|
||||
|
||||
func (api *API) blueprintsFreezeHandler(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
|
||||
|
|
@ -1650,7 +1677,8 @@ func (api *API) blueprintsFreezeHandler(writer http.ResponseWriter, request *htt
|
|||
return dependencies[i].Name < dependencies[j].Name
|
||||
})
|
||||
|
||||
err = setPkgEVRA(dependencies, blueprint.Packages)
|
||||
// Expand any package name globs and set the package version
|
||||
newPackages, err := expandBlueprintGlobs(dependencies, blueprint.Packages)
|
||||
if err != nil {
|
||||
rerr := responseError{
|
||||
ID: "BlueprintsError",
|
||||
|
|
@ -1659,8 +1687,10 @@ func (api *API) blueprintsFreezeHandler(writer http.ResponseWriter, request *htt
|
|||
errors = append(errors, rerr)
|
||||
break
|
||||
}
|
||||
blueprint.Packages = newPackages
|
||||
|
||||
err = setPkgEVRA(dependencies, blueprint.Modules)
|
||||
// Expand any module name globs and set the module version
|
||||
newModules, err := expandBlueprintGlobs(dependencies, blueprint.Modules)
|
||||
if err != nil {
|
||||
rerr := responseError{
|
||||
ID: "BlueprintsError",
|
||||
|
|
@ -1669,6 +1699,7 @@ func (api *API) blueprintsFreezeHandler(writer http.ResponseWriter, request *htt
|
|||
errors = append(errors, rerr)
|
||||
break
|
||||
}
|
||||
blueprint.Modules = newModules
|
||||
blueprints = append(blueprints, blueprintFrozen{blueprint})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import (
|
|||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
|
@ -617,51 +618,6 @@ func TestNonExistentBlueprintsInfoToml(t *testing.T) {
|
|||
require.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
||||
}
|
||||
|
||||
func TestSetPkgEVRA(t *testing.T) {
|
||||
|
||||
// Sorted list of dependencies
|
||||
deps := []rpmmd.PackageSpec{
|
||||
{
|
||||
Name: "dep-package1",
|
||||
Epoch: 0,
|
||||
Version: "1.33",
|
||||
Release: "2.fc30",
|
||||
Arch: "x86_64",
|
||||
},
|
||||
{
|
||||
Name: "dep-package2",
|
||||
Epoch: 0,
|
||||
Version: "2.9",
|
||||
Release: "1.fc30",
|
||||
Arch: "x86_64",
|
||||
},
|
||||
{
|
||||
Name: "dep-package3",
|
||||
Epoch: 7,
|
||||
Version: "3.0.3",
|
||||
Release: "1.fc30",
|
||||
Arch: "x86_64",
|
||||
},
|
||||
}
|
||||
pkgs := []blueprint.Package{
|
||||
{Name: "dep-package1", Version: "*"},
|
||||
{Name: "dep-package2", Version: "*"},
|
||||
}
|
||||
// Replace globs with dependencies
|
||||
err := setPkgEVRA(deps, pkgs)
|
||||
require.NoErrorf(t, err, "setPkgEVRA failed")
|
||||
require.Equalf(t, "1.33-2.fc30.x86_64", pkgs[0].Version, "setPkgEVRA Unexpected pkg version")
|
||||
require.Equalf(t, "2.9-1.fc30.x86_64", pkgs[1].Version, "setPkgEVRA Unexpected pkg version")
|
||||
|
||||
// Test that a missing package in deps returns an error
|
||||
pkgs = []blueprint.Package{
|
||||
{Name: "dep-package1", Version: "*"},
|
||||
{Name: "dep-package0", Version: "*"},
|
||||
}
|
||||
err = setPkgEVRA(deps, pkgs)
|
||||
require.EqualErrorf(t, err, "dep-package0 missing from depsolve results", "setPkgEVRA missing package failed to return error")
|
||||
}
|
||||
|
||||
func TestBlueprintsFreeze(t *testing.T) {
|
||||
t.Run("json", func(t *testing.T) {
|
||||
var cases = []struct {
|
||||
|
|
@ -2223,6 +2179,140 @@ func TestComposePOST_ImageTypeDenylist(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
func TestExpandBlueprintNoGlob(t *testing.T) {
|
||||
packages := []blueprint.Package{
|
||||
{Name: "tmux", Version: "3.3a"},
|
||||
{Name: "openssh-server", Version: "*"},
|
||||
{Name: "grub2", Version: "*"},
|
||||
}
|
||||
// Sorted list of dependencies
|
||||
dependencies := []rpmmd.PackageSpec{
|
||||
{
|
||||
Name: "grub2",
|
||||
Epoch: 1,
|
||||
Version: "2.06",
|
||||
Release: "94.fc38",
|
||||
Arch: "noarch",
|
||||
},
|
||||
{
|
||||
Name: "openssh-server",
|
||||
Epoch: 0,
|
||||
Version: "9.0p1",
|
||||
Release: "15.fc38",
|
||||
Arch: "x86_64",
|
||||
},
|
||||
{
|
||||
Name: "tmux",
|
||||
Epoch: 0,
|
||||
Version: "3.3a",
|
||||
Release: "3.fc38",
|
||||
Arch: "x86_64",
|
||||
},
|
||||
}
|
||||
|
||||
newPackages, err := expandBlueprintGlobs(dependencies, packages)
|
||||
require.NoError(t, err, "Error expanding globs")
|
||||
expected := []blueprint.Package{
|
||||
{Name: "grub2", Version: "1:2.06-94.fc38.noarch"},
|
||||
{Name: "openssh-server", Version: "9.0p1-15.fc38.x86_64"},
|
||||
{Name: "tmux", Version: "3.3a-3.fc38.x86_64"},
|
||||
}
|
||||
assert.Equal(t, expected, newPackages)
|
||||
}
|
||||
|
||||
func TestExpandBlueprintError(t *testing.T) {
|
||||
// Test that a missing package in deps returns an error
|
||||
packages := []blueprint.Package{
|
||||
{Name: "tmux", Version: "*"},
|
||||
{Name: "dep-package0", Version: "*"},
|
||||
}
|
||||
// Sorted list of dependencies
|
||||
dependencies := []rpmmd.PackageSpec{
|
||||
{
|
||||
Name: "openssh-server",
|
||||
Epoch: 0,
|
||||
Version: "9.0p1",
|
||||
Release: "15.fc38",
|
||||
Arch: "x86_64",
|
||||
},
|
||||
{
|
||||
Name: "tmux",
|
||||
Epoch: 0,
|
||||
Version: "3.3a",
|
||||
Release: "3.fc38",
|
||||
Arch: "x86_64",
|
||||
},
|
||||
}
|
||||
_, err := expandBlueprintGlobs(dependencies, packages)
|
||||
require.EqualError(t, err, "dep-package0 missing from depsolve results")
|
||||
}
|
||||
|
||||
func TestExpandBlueprintGlobs(t *testing.T) {
|
||||
packages := []blueprint.Package{
|
||||
{Name: "tmux", Version: "*"},
|
||||
{Name: "openssh-*", Version: "*"},
|
||||
{Name: "test-?-*", Version: "*"},
|
||||
{Name: "test-three-*", Version: "11.1"},
|
||||
{Name: "test-*", Version: "*"},
|
||||
}
|
||||
// Sorted list of dependencies
|
||||
dependencies := []rpmmd.PackageSpec{
|
||||
{
|
||||
Name: "openssh-clients",
|
||||
Epoch: 0,
|
||||
Version: "9.0p1",
|
||||
Release: "15.fc38",
|
||||
Arch: "x86_64",
|
||||
},
|
||||
{
|
||||
Name: "openssh-server",
|
||||
Epoch: 0,
|
||||
Version: "9.0p1",
|
||||
Release: "15.fc38",
|
||||
Arch: "x86_64",
|
||||
},
|
||||
{
|
||||
Name: "test-1-one",
|
||||
Epoch: 0,
|
||||
Version: "1.0.0",
|
||||
Release: "1.fc38",
|
||||
Arch: "x86_64",
|
||||
},
|
||||
{
|
||||
Name: "test-2-two",
|
||||
Epoch: 2,
|
||||
Version: "1.0.0",
|
||||
Release: "1.fc38",
|
||||
Arch: "x86_64",
|
||||
},
|
||||
{
|
||||
Name: "test-three-3",
|
||||
Epoch: 0,
|
||||
Version: "11.1",
|
||||
Release: "1.fc38",
|
||||
Arch: "x86_64",
|
||||
},
|
||||
{
|
||||
Name: "tmux",
|
||||
Epoch: 0,
|
||||
Version: "3.3a",
|
||||
Release: "3.fc38",
|
||||
Arch: "x86_64",
|
||||
},
|
||||
}
|
||||
|
||||
newPackages, err := expandBlueprintGlobs(dependencies, packages)
|
||||
require.NoError(t, err, "Error expanding globs")
|
||||
expected := []blueprint.Package{
|
||||
{Name: "openssh-clients", Version: "9.0p1-15.fc38.x86_64"},
|
||||
{Name: "openssh-server", Version: "9.0p1-15.fc38.x86_64"},
|
||||
{Name: "test-1-one", Version: "1.0.0-1.fc38.x86_64"},
|
||||
{Name: "test-2-two", Version: "2:1.0.0-1.fc38.x86_64"},
|
||||
{Name: "test-three-3", Version: "11.1-1.fc38.x86_64"},
|
||||
{Name: "tmux", Version: "3.3a-3.fc38.x86_64"},
|
||||
}
|
||||
assert.Equal(t, expected, newPackages)
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
setupDNFJSON()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue