Hi John
On 14/06/2013, at 12:06 AM, jcbollinger wrote:

On Wednesday, June 12, 2013 9:15:22 AM UTC-5, Tom Lanyon wrote:
On 05/06/2013, at 11:51 PM, jcbollinger [...] wrote:
I don't much like that general approach in the first place on account of the $requested_package parameter. That you encounter difficulty when you try something a bit dodgy should not be surprising.
Can you explain this further so I can understand the issue?
Initially, it was mostly a gut feeling. After having had time to step back from the issue and return to it fresh, I think it's a combination of things, mostly revolving around what you're actually modeling, and how you're modeling it.

Basically, the 'myapp' definition represents one package chosen from a list of mutually exclusive packages. If that's all it is, then its name is misleading -- it should be more generic -- and it should probably take the exclusive list as a second parameter. On the other hand, if it is indeed supposed to be something specific, then it doesn't take much advantage of that. In particular -- and here's where my previous comment came from -- if it supposed to represent something specific to your application, then why doesn't it know anything about the application's package names?

Also, if the point is supposed to be that only one version of the application can be installed at a time, and the definition is specific to that application, then it really ought to be a class instead.
Alas, the whole intention of this is that multiple versions of the package must be installed at the same time. This is where the problem lies, in that we have no way to clean up old unused versions once they're no longer needed.

We have instances of an application MyApp, which utilise a shared Package in many to one relationship:

     Package[one] ___ MyApp[app1]

     Package[two] ___ MyApp[app2]
                 \___ MyApp[app3]

     Package[three] _ MyApp[app4]
                   \_ MyApp[app5]
                   \_ MyApp[app6]

In the above example, if we upgraded MyApp[app2] and MyApp[app3] to Package[three], we'd still have Package[two] installed on all of the hosts but no MyApp instances would be using it. This is the unused Package we're trying to clean up with Puppet (there's no longer a MyApp resource definition which references Package[two]).

There is no mutually exclusive packages or any other such conflicts.

In fact, despite my dissatisfaction with your approach, you can indeed do this without defined(), and without even disrupting your current structure very much. Here's one way I think would work:

# This class ensures all known app packages are
# by default purged
class app::packages {
$apps = split($::app_packages, ',')
package { $apps:
ensure => 'purged'

# Overrides the requested package to be declared
# present instead of purged.
define app::myapp($requested_package) {
include 'app::packages'
Package<| title == $requested_package |> {
ensure => 'present'

# no separate package_cleanup required

OK, I wondered whether we could do something like this however - forgive my naivety - I still can't see how this could be a complete solution without something like defined().

As an example... your above snippet works fine to ensure already installed packages remain installed, but what if we wanted to install a brand new version of app::myapp? Because a 'package' resource with title $requested_package does not yet exist, the Package<||> collector matches no resources and the new package is not installed. The only solution that I can come up with is to check whether such a resource is already defined and, if not, define one.
You appear to have a serious misunderstanding. Resource collectors have no direct relationship with or dependency on which resources are already installed on the target system. They work exclusively with resource declarations in your manifests, and they do so at catalog compilation time. Moreover, they are independent of parse order (though the example anyway ensures a parse order that would work if collectors were parse-order dependent).
No, I understand this.
Explanation of the example:
• class app::packages declares all of the possible application packages, specifying the intended state for each one as 'purged'. If that is the only thing applied to the target node then it will cause the removal of each and every one of those packages that is installed. ('purged' is stronger than 'absent'. The former is more sure to remove the specified package, but the latter takes care to avoid causing any other packages to be removed, and therefore fails if any other package depends on the target package.) It is necessary that the list of possible packages include every one that you may want to have installed, so it needs to be updated whenever you introduce a new one that you want to manage. That was already a requirement for you, however, whether you recognized it or not.
This is where it fell apart for me before, I didn't realise that you assumed $::app_packages was every possible package; in my first post I'd specified that $::app_packages was a fact generated on each node from the list of *currently installed* packages, so it contains all of the packages which have been previously been installed but not packages which may be installed in the future.

I think it's going to be a managerial nightmare to update some such list of all possible packages, so might look for an alternate solution. I don't think Puppet really meets our needs here, unless there's a way we can programmatically parse out all of the versions of the package specified in our manifests to include them in the $::app_packages (so they get defined as 'purged') before building the rest of the catalog which would override them as 'present'. This feels like something that might be possible with the use of some combination of defined() or stages, but I'm keen to not run up against any caveats you've mentioned with those features.
• Resources of defined type app::myapp ensure that class app::packages is declared on the target node (by declaring it itself)
• Resources of defined type app::myapp override the declaration of the target package (made by class app::packages) so that its target state is 'present' instead of 'purged'. This will cause it to be installed if it is not already present, and will avoid removing it if it is present.
• To use the example, simply declare one or more instances of app::myapp for the target node, either in a node block or in some class assigned to the node. You may also declare class app::packages directly for any node, whether or not they declare any app::myapp instances. That is useful if you have nodes on which you want to ensure that no version of the application is installed.

Thanks for your help.


You received this message because you are subscribed to the Google Groups "Puppet Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users+unsubscribe@googlegroups.com.
To post to this group, send email to puppet-users@googlegroups.com.
Visit this group at http://groups.google.com/group/puppet-users.
For more options, visit https://groups.google.com/groups/opt_out.

Search Discussions

Discussion Posts


Follow ups

Related Discussions

Discussion Navigation
viewthread | post
posts ‹ prev | 7 of 9 | next ›
Discussion Overview
grouppuppet-users @
postedJun 4, '13 at 6:23a
activeJun 14, '13 at 2:28p

2 users in discussion

Jcbollinger: 5 posts Tom Lanyon: 4 posts



site design / logo © 2022 Grokbase