4

I'm trying to package a product consisting of many packages.

I'm successful with writing all the spec files, the dependencies between the packages and so on. They're all installed and work fine.

The one thing I do not succeed to do, is to run a pre-requisition test: In certain cases, I would like the packages not to be installed at all, and the user getting an error, explaining him what he needs to fix first, before he runs the packages installation.

For example: I want to verify that the user is running in runlevel 3, and if not, abort the whole installation, and ask the user to re-install CentOS in "Minimal" profile - as I don't want all the extra packages that comes with "Desktop". (This is just an example, I have a few such tests to perform).

The way I approached this problem is this:

I've created a sort of 'meta package', that its name appears in all the other packages 'Requires:' directive, so it would be installed first by YUM, and in that package spec file, in the %pre section, I did the various tests I wanted to perform, outputting test errors when applicable, and then 'exit 1'.

The reason I chose this approach is this: "If every package depends on this package, and this package cannot be installed, the transaction must fail, as soon as the package manager wants to install a package that depends on a package that failed installation... after all, the dependency has not been met". In Gentoo, for example, if a package fails installation, for whatever reason, emerge stops completely – even not for dependency issues; And there's a special flag to tell emerge to continue despite the error returned from one of the packages.

The problem is that indeed the package fails when the tests fails (RPM specifically says that it returned code 1), BUT... YUM doesn't really seem to care that this happens - and just continues to install everything else, including packages that depend on a package that is not installed (!). At the very end, it simply reports that all the packages were installed successfully, expect for the package that deliberately failed...

I'm guessing that the reason for that is that dependency checking happens before the transaction begins, and indeed, dependencies are met from the various repositories at YUM's disposal. Still, it does not make any sense to me that if a dependency eventually failed, the installation of dependent packages would continue.

Is my logic flawed? I doubt it's a bug, as someone would have encountered it by now (this is on CentOS 6.3 if it matters...) – but all my Google-foo yielded nothing. I didn't even find someone asking the same question... maybe I'm using the wrong keywords?

Am I approaching this wrong way? Any other idea (that fits into RPM specs or other YUM repository magic, even at the YUM .repo file... – but all contained within the YUM infrastructure, without external scripts to run before 'yum install') – would be greatly appreciated!

4
  • 1
    Why is there a runlevel requirement? Also, note that runlevels are modifiable and may not exist as desired. Aug 20, 2013 at 19:50
  • I did say it is just an example, and there are other tests I'ld like to conduct... but since you asked - quite frankly the runlevel is not a requirement, but I do want to start with a minimal system, don't want redundant stuff on the machine, both from performance and from security point of view. If the machine is at runlevel 5, it is quite safe to assume that someone installed X11, which is not needed for a server. So it is kind of a hint that the user did not start with a minimal OS as the installation guide told him to. I want to try and avoid that.
    – Shimi
    Aug 21, 2013 at 5:44
  • So then why not conflict with the X server package? (Not that it's really anyone's business though...) Aug 21, 2013 at 6:11
  • Because if I go that route, I need to conflict with any other thing that's in any CentOS profile but 'Minimal', and start maintaining and following the dependency tree of the distribution, which might change in the future. A runlevel configuration in /etc/inittab is probably a safer bet. I have been using Linux for 16 years now, and the very test I'm doing today, worked back then, too. Not to mention that I might actually need some of those packages anyways, and would put them in 'Requires:' in my own meta-package. I just don't want redundant stuff, and I'm using obvious forensics to find them
    – Shimi
    Aug 21, 2013 at 6:45

2 Answers 2

2

and in that package spec file, in the %pre section, I did the various tests I wanted to perform, outputting test errors when applicable, and then 'exit 1'.

This doesn't work, rpm doesn't stop/unwind the transaction when %pre scripts fail like that. rpm doesn't behave with ACID transactions in a number of ways, of which this is one. You'll need to add conflicts to stop the transaction at the depsolve stage.

6
  • Add conflicts during a transaction in order to fail future packages? Not sure I understand. I know it doesn't work (I wouldn't have asked the question if it did work in the first place ;)) - my question is how exactly do you cause Yum to stop. For now (since nobody replied here thus far), what I did was to simply write a 'blocking' file if any of the tests fail, and have all the other packages that depends on the meta package, test for the existence of that blocking file, and if it exists, abort themselves at the %pre stage too. However, that's work-around-ing the problem, not a solution.
    – Shimi
    Aug 22, 2013 at 17:22
  • To clarify further: Those packages can all be installed at the same time. There's no actual conflict here - just a case in which I don't want ANY package installed if criteria is not met. If the runlevel example wasn't good enough, here's one that is good: I don't want the hostname to be localhost, as this will mess up the cluster initialization I'm going to do during one of those RPM installations. Hence, I want that if the hostname is localhost, nothing will get installed and thus initialized.
    – Shimi
    Aug 22, 2013 at 17:24
  • Right, I understand ... you want dynamic deps. (Eg. run script X, and it tells you if there is a conflict or not. What I'm saying is: That doesn't work in rpm. All the deps. (Eg. requires or conflicts) have to be known before the transaction starts, so you can't change them in a scriptlet and you can't have them be dynamic (Eg. based on hostname). Note esp. that for the dynamic deps. problem, even if there was a way to do it ... what do you do when the hostname if "blah", the transaction/install happens, and then the hostname is changed to "localhost". This is the most obvious problem. Aug 26, 2013 at 19:28
  • Actually, RPM is not the problem; RPM behaves fine for me. It's YUM that wraps RPM that doesn't work as one might expect... it simply assumes that every package is installed successfully... which is, IMHO, funny. Why run "Transaction Test" in the first place? Let's just assume it will work. The 'hostname' has no reason to change after install. What I want is to avoid the default (localhost) - as one of my deps (would you believe?) refuses to initialize if the name is 'localhost', because it's a clustered app, and it wants a unique name on every node, that cannot change during the cluster life.
    – Shimi
    Aug 27, 2013 at 5:23
  • So, I'll keep waiting for someone to come with the magic flag for yum ;) Meanwhile I solved the problem by doing in %pre of every package what yum should have done itself. But would still be happy to find out the right way to do this, given that there is one.
    – Shimi
    Aug 27, 2013 at 5:26
0

Basically you don't want a magic flag to yum, but some form of a %pretrans script that checks your requirements, correct? %pretrans is available since rpm 4.4. Check http://fedoraproject.org/wiki/Packaging:ScriptletSnippets#Syntax or maybe http://wiki.networksecuritytoolkit.org/nstwiki/index.php/RPM_Quick_Reference#Secret_.25pretrans_and_.25posttrans_RPM_Scriptlets

For some more information, see the discussion and downsides at https://fedorahosted.org/fpc/ticket/22

So create a %pretrans scriptlet, pile all all your tests there (runlevel, hostname) and whatever and when the total $? equals 0 the transaction will start, if not it will fail.

Although this approach definitely sounds like a logic flaw.


For your question why yum will not stop with the first package failing: Because you basically tell it to install, say a dozen packages. One of them fails, but the others do not depend on that one (as otherwise you would end up with circular dependencies which might also be tricky) so the others will be installed. That is normal behaviour. You might change all the dependent packages to say Requires(pre): yourmetapackagehere >= some.version

To change the order of the installation of all the dependencies, you can use "context marked dependencies" (ordered dependencies) check e.g. this resource

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .