Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolve rpm (rich) dependencies via libsolv #1122

Merged
merged 1 commit into from Jul 17, 2018

Conversation

dparalen
Copy link

@dparalen dparalen commented Jun 19, 2018

Please note this requires a libsolv version exposing Python bindings necessary to support fileprovides deps. @ignatenkobrain made an F26 build with which I was able to test this PR manually.
Without it will just blow-up O:-)

@pep8speaks
Copy link

pep8speaks commented Jun 19, 2018

Hello @dparalen! Thanks for updating the PR.

Cheers ! There are no PEP8 issues in this Pull Request. 🍻

Comment last updated on July 16, 2018 at 16:39 Hours UTC

@pulpbot
Copy link
Member

pulpbot commented Jun 19, 2018

Can one of the admins verify this patch?

1 similar comment
@pulpbot
Copy link
Member

pulpbot commented Jun 19, 2018

Can one of the admins verify this patch?

@ignatenkobrain
Copy link

I'm looking for this.

elif unit_flags == 'GE':
rel_flags = solv.REL_EQ | solv.REL_GT
else:
# fancier flags; might not be needed actually

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, this should be an error

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack; will raise something here instead

pool = solvable.repo.pool
if unit_name.startswith('('):
# the Rich/Boolean dependencies have just the 'name' attribute
# this is always in the form: '(foo >= 1.2 AND bar != 0.9)'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(foo >= 1.2 with foo < 2.0) should be better example

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right; will update

def find_dependent_rpms(self, units):
solver = self.pool.Solver()
if self.target_repo:
# to avoid dependency conflicts between units being copied into a repository

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

meh, sounds hacky

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IKR O:-)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so I guess since we don't really track these in the Mongo I can drop it actually

@dparalen dparalen force-pushed the issue_3715_steel branch 3 times, most recently from a8657e8 to c8bd2d4 Compare June 22, 2018 17:59
'_content_type_id',
'id',
])
rpm_exclude_fields = set([
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the thing is, RPM.objects.only('provides').as_pymongo() doesn't expand the list of provides objects. I couldn't get it working in any other way than RPM.objects.exclude(...).as_pymongo() :-/

@dparalen dparalen force-pushed the issue_3715_steel branch 3 times, most recently from 45ad7f7 to e7b058c Compare June 25, 2018 14:12
@dparalen
Copy link
Author

dparalen commented Jun 25, 2018

we might have to consider implementing the libsolv solver as a (default) alternative to the current solver; this is what I've encountered testing on Fedora28 content:

[milan@pulp2F28 pulp_rpm]$ pulp-admin rpm repo copy group -f f_everything -t foo --str-eq='id=gnome-desktop' --recursive
This command may be exited via ctrl+c without affecting the request.


[|]
Running...

Task Failed

Encountered problems solving: nothing provides /etc/xdg/autostart needed by
xdg-user-dirs-0:0.17-1.fc28.x86_64

[milan@pulp2F28 pulp_rpm]$

i.e there might be issues in the users repo content that could be considered repo copy regressions by them if we only provide the libsolv solver :-/
Another option would be to enforce the action no matter missing dependencies but I don't yet know how to do that.

--->%---EDITED---

Turns out I'm not processing directories in file-provides... but the concern remains about a repo being not properly "closed" for dependencies, rendering the recursive copies unsatisfiable. A user might consider this a regression with the libsolv solver.

repodata = solvable.repo.first_repodata()
unit_dirs = unit.get('files', {}).get('dir', [])
for dirname in unit_dirs:
repodata.str2dir(dirname.encode('utf-8'), create=True)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here you need just /, and then use add_dirstr() with the directory.

@jlsherrill
Copy link
Contributor

@dparalen i think it will actually be fairly 'normal' for repos to not completely solve. Things like epel, optional, or extras do not provide all their dependencies, they depend on some base os repo which would not be part of the solver. I think we still have to copy what we know about in those instances.

@dparalen
Copy link
Author

@jlsherrill yeah, I thought so. My implementation is more strict right now but libsolv can be tricked into the behaviour of the "old" solver if the hard requirements are treated as weak e.g requires -> recommends or probably by mocking the unsatisfied dependencies and retrying the solving.

These tricks will affect the set of the reported dependent packages. Once we implement weak dependency processing in Pulp, pulling-in all the recommended dependencies all the time because of the requires->recommends shift will result in a different set of packages being resolved than the strict requires alone would have pulled.

My gut feeling is though to expose these behaviour options as settings thru the REST API to the user to chose their preferred solver behaviour for a particular (repository) case. Folks might as well be interested in seeing what particular content would have been mocked to satisfy the dependencies for some sort of content sanity checking. But it may be out of scope for this PR.

What do you think?

Thanks,
milan

@dparalen
Copy link
Author

I'll investigate how to just ignore the problems the solver reported...

@dparalen
Copy link
Author

So it seems it's fine to just "ignore" the problems ;)

"""A specific, rpm-unit-type filelist attribute conversion."""
repodata = solvable.repo.first_repodata()
unit_files = unit.get('files', {}).get('file', [])
unit_files.extend(unit.get('files', {}).get('dir', []))
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

both the rpm.files['file'] and rpm.files['dir'] have to be processed the same os.path.dirname(); os.path.basename() way for libsolv to understand.

Copy link
Member

@dkliban dkliban left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me.

However, I don't think we can merge this until the required changes for libsolv Python bindings have been released. If we merge this now, our nightly test runners will start failing until the newer libsolv bindings are available for EL7 and F28. We also will not be able to release this code until that dependency is available.

@dralley
Copy link
Contributor

dralley commented Jul 10, 2018

Jenkins tests are failing for no module named "solv"

@dparalen
Copy link
Author

@dralley, thanks a lot for test!
I shall update the requirements, stay tuned!

dparalen added a commit to dparalen/pulp-packaging that referenced this pull request Jul 11, 2018
The Pulp RPM plugin switches depsolving implementation to a libsolv-based
one[1].  This patch adds a dependency on the python2 libsolv bindings that
include necessary functionality, esp. the file-provides Python libsolv
API.

[1] pulp/pulp_rpm#1122
@dparalen
Copy link
Author

OK test

@ipanova
Copy link
Member

ipanova commented Jul 11, 2018

ok test

1 similar comment
@dparalen
Copy link
Author

ok test

@daviddavis
Copy link
Contributor

ok test

plain_attribute_factory('arch'),
plain_attribute_factory('vendor'),
rpm_dependency_attribute_factory('requires'),
rpm_dependency_attribute_factory('conflicts'),
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I shall remove the unused fields for now; if in the future required, we'd better add on an as-needed basis.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How come that conflicts do not exist?!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't track these in Mongo so it has no effect; Can a repo have conflicting units inside? I guess it can, or?

Copy link
Member

@dkliban dkliban left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for putting this together.

I tested using pulp-smash tests for recursively copying units between repos.

@dkliban
Copy link
Member

dkliban commented Jul 13, 2018

Please add a release note stating that we added libsolv as a dependency and that it's now being used when RPMs are being copied recursively between repos.

@dparalen dparalen force-pushed the issue_3715_steel branch 2 times, most recently from b176364 to 0d718dd Compare July 13, 2018 15:38
@dparalen
Copy link
Author

dparalen commented Jul 13, 2018

OK, so I had a private chat with @ignatenkobrain and turns out we have to process the "negative" dependencies too:

  • foo depends on webserver but conflicts with libnginx
  • nginx provides webserver but also libnginx
  • the source repo contains both the nginx and httpd
  • recursive copy of foo might pick up nginx since Pulp ignores the conflicts field
  • dnf installing from the target repo would panic

This unfortunately is the case with the current code so I hope I'm not making it worse.
I'd say we should correct this sooner than later tho.

Thanks @ignatenkobrain for pointing it out

@ignatenkobrain
Copy link

nginx provides webserver but also libnginx

Missing Requires libnginx here ;)

And also you missed some input that httpd also Provides: webserver

@dkliban
Copy link
Member

dkliban commented Jul 13, 2018

We should file an issue in pulp.plan.io about this. This is not a regression.

@dparalen
Copy link
Author

@dkliban, I've just created https://pulp.plan.io/issues/3853

* The rich/boolean dependency solving is now supported when e.g recursively
copying RPM content between repositories.

* More conservative dependency solving is now supported when e.g recursively
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you explain 'conservative dependency solving'?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a literal copy from the related issue headline; would you like me rephrasing it in the release note?

solver = pulp_solv.Solver(source_repo, target_repo=dest_repo)
solver.load()
else:
solver = None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about getting rid of unnecessary if statement on L#52 and:

    if recursive:
        solver = pulp_solv.Solver(source_repo, target_repo=dest_repo)
        solver.load()
    else:
        solver = None
        recursive = False

in my understanding this option is a boolean which is whether true or false.
in addition i noticed that this option is not documented in technical reference at all https://docs.pulpproject.org/plugins/pulp_rpm/tech-reference/yum-plugins.html#yum-importer

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'd also set a default value to False:

# get config items that we care about
recursive = config.get(constants.CONFIG_RECURSIVE, False)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lemme update

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you could also update the tech. reference docs would be great

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure I'll check it


# FIXME: not really true anymore:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you just remove the fixme since it's a not a problem and just leaving the note of silent skip of unresolvable deps.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will do

repo_controller.associate_single_unit(repository=dest_repo, unit=unit)
unit_set.add(unit)
_LOGGER.debug('Copying unit: %s', unit)
# FIXME: this should be done in bulks
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the status of this fixme?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will call it TODO:

@dparalen
Copy link
Author

@ipanova thanks for the review!

Pulp now uses libsolv as a dependency solver to address recursive RPM unit
dependency solving during e.g unit copy

Fixes: #3715
https://pulp.plan.io/issues/3715

Fixes: pulp#2478
https://pulp.plan.io/issues/2478
@dparalen
Copy link
Author

updated; hopefully I didn't miss anything

@ipanova
Copy link
Member

ipanova commented Jul 17, 2018

ok test

@ipanova ipanova merged commit 17a2f5d into pulp:2-master Jul 17, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants