mirror of
https://github.com/mudler/luet.git
synced 2025-09-09 11:10:07 +00:00
🐛 Bail out when no packages are found with default solvers (#296)
* 🐛 Bail out when no packages are found with default solvers Checking packages is more tricky when a resolver is set. Resolvers are capable of mutating the user request and remove part of the constraints in order to resolve a specific solution. This had the countereffect on a normal solver to not detect correctly packages when missing from the wanted set and not proposed during installation. This should fix all the cases above taking into consideration of resolvers and adding specific test-cases for it. * ⚙️ Pin to tag for test image
This commit is contained in:
committed by
GitHub
parent
b5da2fa7b4
commit
1006be9271
@@ -53,17 +53,18 @@ var _ = Describe("Delta", func() {
|
|||||||
var img, img2 v1.Image
|
var img, img2 v1.Image
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
ref, _ = name.ParseReference("alpine")
|
|
||||||
ref2, _ = name.ParseReference("golang:alpine")
|
|
||||||
img, _ = daemon.Image(ref)
|
|
||||||
img2, _ = daemon.Image(ref2)
|
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
ctx = context.NewContext()
|
ctx = context.NewContext()
|
||||||
|
ctx.Config.General.Debug = true
|
||||||
|
|
||||||
tmpfile, err = ioutil.TempFile("", "delta")
|
tmpfile, err = ioutil.TempFile("", "delta")
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
defer os.RemoveAll(tmpfile.Name()) // clean up
|
defer os.RemoveAll(tmpfile.Name()) // clean up
|
||||||
|
|
||||||
|
ref, _ = name.ParseReference("alpine")
|
||||||
|
ref2, _ = name.ParseReference("golang:1.16-alpine3.14")
|
||||||
|
img, _ = daemon.Image(ref)
|
||||||
|
img2, _ = daemon.Image(ref2)
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Extract all deltas", func() {
|
It("Extract all deltas", func() {
|
||||||
|
@@ -29,6 +29,6 @@ func TestImageApi(t *testing.T) {
|
|||||||
b := backend.NewSimpleDockerBackend(context.NewContext())
|
b := backend.NewSimpleDockerBackend(context.NewContext())
|
||||||
b.DownloadImage(backend.Options{ImageName: "alpine"})
|
b.DownloadImage(backend.Options{ImageName: "alpine"})
|
||||||
b.DownloadImage(backend.Options{ImageName: "golang:alpine"})
|
b.DownloadImage(backend.Options{ImageName: "golang:alpine"})
|
||||||
|
b.DownloadImage(backend.Options{ImageName: "golang:1.16-alpine3.14"})
|
||||||
RunSpecs(t, "Image API Suite")
|
RunSpecs(t, "Image API Suite")
|
||||||
}
|
}
|
||||||
|
@@ -291,6 +291,11 @@ func (p *Package) String() string {
|
|||||||
return fmt.Sprintf("%s", string(b))
|
return fmt.Sprintf("%s", string(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasVersionDefined returns true when a specific version of a package is implied
|
||||||
|
func (p *Package) HasVersionDefined() bool {
|
||||||
|
return p.Version != ">=0"
|
||||||
|
}
|
||||||
|
|
||||||
// GetFingerPrint returns a UUID of the package.
|
// GetFingerPrint returns a UUID of the package.
|
||||||
// FIXME: this needs to be unique, now just name is generalized
|
// FIXME: this needs to be unique, now just name is generalized
|
||||||
func (p *Package) GetFingerPrint() string {
|
func (p *Package) GetFingerPrint() string {
|
||||||
|
@@ -552,21 +552,28 @@ func (l *LuetInstaller) Install(cp types.Packages, s *System) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we have to process something, or return to the user an error
|
allInstalled := true
|
||||||
if len(match) == 0 {
|
|
||||||
l.Options.Context.Info("No packages to install")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// Resolvers might decide to remove some packages from being installed
|
// Resolvers might decide to remove some packages from being installed
|
||||||
if l.Options.SolverOptions.Type != solver.QLearningResolverType {
|
if !solver.IsRelaxedResolver(l.Options.SolverOptions) {
|
||||||
for _, p := range cp {
|
for _, p := range cp {
|
||||||
found := false
|
found := false
|
||||||
vers, _ := s.Database.FindPackageVersions(p) // If was installed, it is found, as it was filtered
|
|
||||||
if len(vers) >= 1 {
|
if p.HasVersionDefined() {
|
||||||
found = true
|
f, err := s.Database.FindPackage(p)
|
||||||
continue
|
if f != nil && err == nil {
|
||||||
|
found = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
vers, _ := s.Database.FindPackageVersions(p) // If was installed, it is found, as it was filtered
|
||||||
|
if len(vers) >= 1 {
|
||||||
|
found = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allInstalled = false
|
||||||
for _, m := range match {
|
for _, m := range match {
|
||||||
if m.Package.GetName() == p.GetName() {
|
if m.Package.GetName() == p.GetName() {
|
||||||
found = true
|
found = true
|
||||||
@@ -583,8 +590,17 @@ func (l *LuetInstaller) Install(cp types.Packages, s *System) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if we have to process something, or return to the user an error
|
||||||
|
if len(match) == 0 {
|
||||||
|
l.Options.Context.Info("No packages to install")
|
||||||
|
if !solver.IsRelaxedResolver(l.Options.SolverOptions) && !allInstalled {
|
||||||
|
return fmt.Errorf("could not find packages to install from the repositories in the system")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
l.Options.Context.Info("Packages that are going to be installed in the system:")
|
l.Options.Context.Info("Packages that are going to be installed in the system:")
|
||||||
//l.Options.Context.Info("Packages that are going to be installed in the system: \n ", Green(matchesToList(match)).BgBlack().String())
|
|
||||||
|
|
||||||
printMatches(match)
|
printMatches(match)
|
||||||
|
|
||||||
|
@@ -26,6 +26,7 @@ import (
|
|||||||
compiler "github.com/mudler/luet/pkg/compiler"
|
compiler "github.com/mudler/luet/pkg/compiler"
|
||||||
backend "github.com/mudler/luet/pkg/compiler/backend"
|
backend "github.com/mudler/luet/pkg/compiler/backend"
|
||||||
fileHelper "github.com/mudler/luet/pkg/helpers/file"
|
fileHelper "github.com/mudler/luet/pkg/helpers/file"
|
||||||
|
"github.com/mudler/luet/pkg/solver"
|
||||||
|
|
||||||
pkg "github.com/mudler/luet/pkg/database"
|
pkg "github.com/mudler/luet/pkg/database"
|
||||||
. "github.com/mudler/luet/pkg/installer"
|
. "github.com/mudler/luet/pkg/installer"
|
||||||
@@ -1161,6 +1162,7 @@ urls:
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
inst := NewLuetInstaller(LuetInstallerOptions{
|
inst := NewLuetInstaller(LuetInstallerOptions{
|
||||||
|
Relaxed: true,
|
||||||
Concurrency: 1, Context: ctx,
|
Concurrency: 1, Context: ctx,
|
||||||
PackageRepositories: types.LuetRepositories{*repo2.LuetRepository},
|
PackageRepositories: types.LuetRepositories{*repo2.LuetRepository},
|
||||||
})
|
})
|
||||||
@@ -1174,6 +1176,28 @@ urls:
|
|||||||
|
|
||||||
systemDB := pkg.NewBoltDatabase(filepath.Join(bolt, "db.db"))
|
systemDB := pkg.NewBoltDatabase(filepath.Join(bolt, "db.db"))
|
||||||
system := &System{Database: systemDB, Target: fakeroot}
|
system := &System{Database: systemDB, Target: fakeroot}
|
||||||
|
|
||||||
|
err = inst.Install([]*types.Package{&types.Package{Name: "b", Category: "test", Version: "1.0"}}, system)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
err = inst.Install([]*types.Package{&types.Package{Name: "b", Category: "foo", Version: "1.0"}}, system)
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err.Error()).To(ContainSubstring("where are definitions coming from"))
|
||||||
|
|
||||||
|
err = inst.Install([]*types.Package{&types.Package{Name: "b", Category: "foo", Version: ">=0"}}, system)
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err.Error()).To(ContainSubstring("package 'foo/b->=0' not found"))
|
||||||
|
|
||||||
|
inst2 := NewLuetInstaller(LuetInstallerOptions{
|
||||||
|
SolverOptions: types.LuetSolverOptions{Type: solver.QLearningResolverType},
|
||||||
|
Relaxed: true,
|
||||||
|
Concurrency: 1, Context: ctx,
|
||||||
|
PackageRepositories: types.LuetRepositories{*repo2.LuetRepository},
|
||||||
|
})
|
||||||
|
err = inst2.Install([]*types.Package{&types.Package{Name: "b"}, &types.Package{Name: "b", Category: "test", Version: ">=0"}}, system)
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err.Error()).To(ContainSubstring("where are definitions coming from"))
|
||||||
|
|
||||||
err = inst.Install([]*types.Package{&types.Package{Name: "b", Category: "test", Version: "1.0"}}, system)
|
err = inst.Install([]*types.Package{&types.Package{Name: "b", Category: "test", Version: "1.0"}}, system)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
@@ -40,6 +40,13 @@ type Solver struct {
|
|||||||
Resolver types.PackageResolver
|
Resolver types.PackageResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsRelaxedResolver returns true wether a solver might
|
||||||
|
// take action on user side, by removing some installation constraints
|
||||||
|
// or taking automated actions (e.g. qlearning)
|
||||||
|
func IsRelaxedResolver(t types.LuetSolverOptions) bool {
|
||||||
|
return t.Type == QLearningResolverType
|
||||||
|
}
|
||||||
|
|
||||||
// NewSolver accepts as argument two lists of packages, the first is the initial set,
|
// NewSolver accepts as argument two lists of packages, the first is the initial set,
|
||||||
// the second represent all the known packages.
|
// the second represent all the known packages.
|
||||||
func NewSolver(t types.SolverOptions, installed types.PackageDatabase, definitiondb types.PackageDatabase, solverdb types.PackageDatabase) types.PackageSolver {
|
func NewSolver(t types.SolverOptions, installed types.PackageDatabase, definitiondb types.PackageDatabase, solverdb types.PackageDatabase) types.PackageSolver {
|
||||||
|
@@ -57,11 +57,39 @@ EOF
|
|||||||
}
|
}
|
||||||
|
|
||||||
testInstall() {
|
testInstall() {
|
||||||
|
luet install -y --config $tmpdir/luet.yaml test/foobar
|
||||||
|
installst=$?
|
||||||
|
assertEquals 'install test fails' "$installst" "2"
|
||||||
|
|
||||||
|
luet install -y --config $tmpdir/luet.yaml test/foobar test/c
|
||||||
|
installst=$?
|
||||||
|
assertEquals 'install test fails' "$installst" "2"
|
||||||
|
|
||||||
|
luet install -y --config $tmpdir/luet.yaml test/foobar@1.0
|
||||||
|
installst=$?
|
||||||
|
assertEquals 'install test fails' "$installst" "2"
|
||||||
|
|
||||||
|
luet install -y --config $tmpdir/luet.yaml test/foobar@1.0 test/c@1.0
|
||||||
|
installst=$?
|
||||||
|
assertEquals 'install test fails' "$installst" "2"
|
||||||
|
|
||||||
|
luet install -y --config $tmpdir/luet.yaml test/foobar@1.0 test/c
|
||||||
|
installst=$?
|
||||||
|
assertEquals 'install test fails' "$installst" "2"
|
||||||
|
|
||||||
luet install -y --config $tmpdir/luet.yaml test/c
|
luet install -y --config $tmpdir/luet.yaml test/c
|
||||||
#luet install -y --config $tmpdir/luet.yaml test/c@1.0 > /dev/null
|
|
||||||
installst=$?
|
installst=$?
|
||||||
assertEquals 'install test successfully' "$installst" "0"
|
assertEquals 'install test successfully' "$installst" "0"
|
||||||
assertTrue 'package installed' "[ -e '$tmpdir/testrootfs/c' ]"
|
assertTrue 'package installed' "[ -e '$tmpdir/testrootfs/c' ]"
|
||||||
|
|
||||||
|
luet install -y --config $tmpdir/luet.yaml test/foobar test/c
|
||||||
|
installst=$?
|
||||||
|
assertEquals 'install test fails' "$installst" "2"
|
||||||
|
|
||||||
|
# Already installed
|
||||||
|
luet install -y --config $tmpdir/luet.yaml test/c@1.0
|
||||||
|
installst=$?
|
||||||
|
assertEquals 'install test fails' "$installst" "0"
|
||||||
}
|
}
|
||||||
|
|
||||||
testReInstall() {
|
testReInstall() {
|
||||||
|
Reference in New Issue
Block a user