Package With 'yum' Provider Uses 'rpm' to Remove a Package (bug?)

1,329 views
Skip to first unread message

Jon Forrest

unread,
Apr 22, 2014, 3:16:22 PM4/22/14
to puppet...@googlegroups.com
(I found a discussion from 6/22/09 on this topic, but that was a long time ago.)

Using Puppet 3.5.1 on CentOS 6.5 I recently created the following:

  package {
    [ "PackageKit"]:
      ensure => absent,
  }

However, when I ran Puppet, I got

Error: Execution of '/bin/rpm -e PackageKit-0.5.8-21.el6.x86_64' returned 1: error: Failed dependencies:
        PackageKit = 0.5.8-21.el6 is needed by (installed) PackageKit-yum-0.5.8-21.el6.x86_64
        PackageKit = 0.5.8-21.el6 is needed by (installed) PackageKit-glib-0.5.8-21.el6.x86_64
        PackageKit is needed by (installed) PackageKit-yum-plugin-0.5.8-21.el6.x86_64

Notice that the provider is running '/bin/rpm' which explains the errors. So, I explicitly added
a provider, so that the resource definition is this:

 package {
    [ "PackageKit"]:
      provider => 'yum',
      ensure => absent,
  }

There was no change!!

In the discussion from 2009, somebody suggested using "purge" instead of "absent",
so I did. But although Puppet now uses yum, it does so in a very strange way:

Error: Could not update: Execution of '/usr/bin/yum -d 0 -e 0 -y install PackageKit-purge' returned 1: Error: Nothing to do
Wrapped exception:

This looks like a bug to me.

I ended up using

  exec { "/usr/bin/yum -y remove PackageKit":
        onlyif => "/bin/rpm -qa |/bin/fgrep PackageKit",
    }

but this is a step in the wrong direction.

Comments?

Jon Forreset

Antoine Cotten

unread,
Apr 23, 2014, 11:44:40 AM4/23/14
to puppet...@googlegroups.com
Hi Jon,

this is more like a security mechanism to prevent YUM from removing dependencies in a very unexpected and unattended way.
From my experience I have already tried to achieve such thing: I wanted to get rid of sendmail but this also deleted critical packages such as cron (!). Using RPM prevents this to happen by forcing you to explicitly adding any package depending on your undesired package to the "absent" list.

jcbollinger

unread,
Apr 23, 2014, 11:54:50 AM4/23/14
to puppet...@googlegroups.com


On Tuesday, April 22, 2014 2:16:22 PM UTC-5, Jon Forrest wrote:
(I found a discussion from 6/22/09 on this topic, but that was a long time ago.)


Did the discussion give you reason to think that the behavior was unintentional or likely to change?

 

Using Puppet 3.5.1 on CentOS 6.5 I recently created the following:

  package {
    [ "PackageKit"]:
      ensure => absent,
  }

However, when I ran Puppet, I got

Error: Execution of '/bin/rpm -e PackageKit-0.5.8-21.el6.x86_64' returned 1: error: Failed dependencies:
        PackageKit = 0.5.8-21.el6 is needed by (installed) PackageKit-yum-0.5.8-21.el6.x86_64
        PackageKit = 0.5.8-21.el6 is needed by (installed) PackageKit-glib-0.5.8-21.el6.x86_64
        PackageKit is needed by (installed) PackageKit-yum-plugin-0.5.8-21.el6.x86_64

Notice that the provider is running '/bin/rpm' which explains the errors.


Yes, this is intentional.  Puppet is taking care to avoid undeclared side effects.  Such side effects can make your manifest set inconsistent in ways that Puppet cannot otherwise detect.  For example, suppose somewhere else in your manifest set you had

  package { "PackageKit-yum": ensure => 'installed' }

That declaration and your example declaration are not consistent with each other, but if Puppet provided for ensure => absent via yum then both could be applied without error.  The result would depend on the relative order in which the declarations were applied, but neither result would be fully consistent with the catalog.
 
So, I explicitly added
a provider, so that the resource definition is this:

 package {
    [ "PackageKit"]:
      provider => 'yum',
      ensure => absent,
  }

There was no change!!



No, because the agent was selecting the yum provider already.  The yum provider ensures absent by use of 'rpm -e'.  Again, this is intentional.
 

In the discussion from 2009, somebody suggested using "purge" instead of "absent",
so I did.


And if you are willing to accept the risk of inconsistency described above, then that is what you should do.  But it's spelled "purged", not "purge".

 
But although Puppet now uses yum, it does so in a very strange way:

Error: Could not update: Execution of '/usr/bin/yum -d 0 -e 0 -y install PackageKit-purge' returned 1: Error: Nothing to do
Wrapped exception:

This looks like a bug to me.


You misspelled "purged" for your 'ensure' parameter, and therefore Puppet interpreted it as a package version.
 

I ended up using

  exec { "/usr/bin/yum -y remove PackageKit":
        onlyif => "/bin/rpm -qa |/bin/fgrep PackageKit",
    }

but this is a step in the wrong direction.

Comments?



You are looking for this:

  package { 'PackageKit':
      ensure => 'purged'
  }


John

Jon Forrest

unread,
Apr 23, 2014, 12:41:22 PM4/23/14
to puppet-users
On Wed, Apr 23, 2014 at 8:54 AM, jcbollinger <John.Bo...@stjude.org> wrote:
>
>
> On Tuesday, April 22, 2014 2:16:22 PM UTC-5, Jon Forrest wrote:
>>
>> (I found a discussion from 6/22/09 on this topic, but that was a long time
>> ago.)
>
> Did the discussion give you reason to think that the behavior was
> unintentional or likely to change?

I didn't think that whatever my reaction was to a 5 year old discussion
would matter now. Puppet changes. People change.

>> Using Puppet 3.5.1 on CentOS 6.5 I recently created the following:
>>
>> package {
>> [ "PackageKit"]:
>> ensure => absent,
>> }
>>
>> However, when I ran Puppet, I got
>>
>> Error: Execution of '/bin/rpm -e PackageKit-0.5.8-21.el6.x86_64' returned
>> 1: error: Failed dependencies:
>> PackageKit = 0.5.8-21.el6 is needed by (installed)
>> PackageKit-yum-0.5.8-21.el6.x86_64
>> PackageKit = 0.5.8-21.el6 is needed by (installed)
>> PackageKit-glib-0.5.8-21.el6.x86_64
>> PackageKit is needed by (installed)
>> PackageKit-yum-plugin-0.5.8-21.el6.x86_64
>>
>> Notice that the provider is running '/bin/rpm' which explains the errors.
>
>
>
> Yes, this is intentional. Puppet is taking care to avoid undeclared side
> effects. Such side effects can make your manifest set inconsistent in ways
> that Puppet cannot otherwise detect. For example, suppose somewhere else in
> your manifest set you had
>
> package { "PackageKit-yum": ensure => 'installed' }
>
> That declaration and your example declaration are not consistent with each
> other, but if Puppet provided for ensure => absent via yum then both could
> be applied without error. The result would depend on the relative order in
> which the declarations were applied, but neither result would be fully
> consistent with the catalog.

OK. See below.

>>
>> So, I explicitly added
>> a provider, so that the resource definition is this:
>>
>> package {
>> [ "PackageKit"]:
>> provider => 'yum',
>> ensure => absent,
>> }
>>
>> There was no change!!
>>
>
>
> No, because the agent was selecting the yum provider already. The yum
> provider ensures absent by use of 'rpm -e'. Again, this is intentional.

Apparently. But still, I was hoping there would be a way to somehow express
that I really truly wanted yum to remove a package, the same way it would
if I ran yum on the command line. In this case, there are no
conflicting resource
definitions so there would be no problem with the catalog being consistent.

My perhaps naive assumption would be that if I explicitly used the 'yum'
provider Puppet would follow my direction. I'm clearly wrong. Again,
see below.

>> In the discussion from 2009, somebody suggested using "purge" instead of
>> "absent",
>> so I did.
>
> And if you are willing to accept the risk of inconsistency described above,
> then that is what you should do. But it's spelled "purged", not "purge".

Oops. You're right. My mistake, although would it be reasonable to expect
Puppet to show an error?

So, apart from my stupid syntax error, it seems like my problem was caused
by not understanding the difference between "absent" and "purged" when
the "yum" provider is used. I just googled

"puppet difference between purged and absent"

and I didn't find an explanation. I also checked the Puppet Type
Reference manual
and I didn't find anything there. Can you point me to anything?

Thanks,
Jon Forrest

jcbollinger

unread,
Apr 24, 2014, 10:01:34 AM4/24/14
to puppet...@googlegroups.com


On Wednesday, April 23, 2014 11:41:22 AM UTC-5, Jon Forrest wrote:
On Wed, Apr 23, 2014 at 8:54 AM, jcbollinger <John.Bo...@stjude.org> wrote:
>
>
> On Tuesday, April 22, 2014 2:16:22 PM UTC-5, Jon Forrest wrote:
>>
>> So, I explicitly added
>> a provider, so that the resource definition is this:
>>
>>  package {
>>     [ "PackageKit"]:
>>       provider => 'yum',
>>       ensure => absent,
>>   }
>>
>> There was no change!!
>>
>
>
> No, because the agent was selecting the yum provider already.  The yum
> provider ensures absent by use of 'rpm -e'.  Again, this is intentional.

Apparently. But still, I was hoping there would be a way to somehow express
that I really truly wanted yum to remove a package, the same way it would
if I ran yum on the command line. In this case, there are no
conflicting resource
definitions so there would be no problem with the catalog being consistent.

My perhaps naive assumption would be that if I explicitly used the 'yum'
provider Puppet would follow my direction. I'm clearly wrong. Again,
see below.



That's not necessarily a naive assumption, but it does suggest that you haven't fully grasped the Puppet paradigm.  You seem to be thinking in terms of how to persuade Puppet to execute specific commands, but you should be thinking in terms of how to accurately express the desired target state.  I often describe that issue this way: Puppet is not a script engine.  I keep coming back to that because it is a fundamental aspect of the Puppet architecture, and you will have the greatest success with Puppet if you understand and embrace that.

Given that, then, declaring to Puppet that you want a package "absent" is a statement about that package alone.  Declaring that you want it "purged" says that you want not only that package absent, but also all its configuration files and any other packages that depend on it.

 
>> In the discussion from 2009, somebody suggested using "purge" instead of
>> "absent",
>> so I did.
>
> And if you are willing to accept the risk of inconsistency described above,
> then that is what you should do.  But it's spelled "purged", not "purge".

Oops. You're right. My mistake, although would it be reasonable to expect
Puppet to show an error?



It does show an error, as you reported.  It just does not diagnose the problem as misspelled keyword.  It is a slightly quirky but documented and long-established feature of the Package provider that you can specify a package version as the 'ensure' value to express that that particular version should be present.  There is no general standard for package version codes, so when you write "ensure => 'purge'" Puppet has no reliable way to recognize it as a misspelling -- the problem could instead be that you need an additional package repository configured, for example.

 
So, apart from my stupid syntax error, it seems like my problem was caused
by not understanding the difference between "absent" and "purged" when
the "yum" provider is used. I just googled

"puppet difference between purged and absent"

and I didn't find an explanation. I also checked the Puppet Type
Reference manual
and I didn't find anything there. Can you point me to anything?

Jon Forrest

unread,
Apr 24, 2014, 11:12:30 PM4/24/14
to puppet...@googlegroups.com
On 4/24/2014 7:01 AM, jcbollinger wrote:

> That's not necessarily a naive assumption, but it does suggest that you
> haven't fully grasped the Puppet paradigm. You seem to be thinking in
> terms of how to persuade Puppet to execute specific commands, but you
> should be thinking in terms of how to accurately express the desired
> target state.

I think I did, but that didn't work. So, I had to get fancy.

> Given that, then, declaring to Puppet that you want a package "absent"
> is a statement about that package alone. Declaring that you want it
> "purged" says that you want not only that package absent, but also all
> its configuration files and any other packages that depend on it.

This is indeed the critical fact that I wasn't aware of. Thanks
for clearing this up.

Jon

Reply all
Reply to author
Forward
0 new messages