Resources sharing across different classes.

677 views
Skip to first unread message

Afroz Hussain

unread,
Mar 31, 2016, 7:43:46 AM3/31/16
to Puppet Users
Hi All,

I am facing an issue to notify a service from different module whenever file changes.
Example:
I have a addfile module which creates a file and want to notify tomcat service which is present in tomcat module. 

class addfile {
   file {"/tmp/hello":
     ensure => file,
     content => "hello",
     notify   => Service["tomcat'],
   }
}


it is throwing an error as tomcat service is not in catalog.

I have 3.6.2 version of puppet and using ENC.

Any help will be appreciated

Thanks,
Afroz Hussain

Afroz Hussain

unread,
Mar 31, 2016, 7:48:57 AM3/31/16
to Puppet Users
Error as below:

Error: Could not retrieve catalog from remote server: Error 400 on SERVER: Invalid relationship: File[/tmp/hello] { notify => Service[tomcat] }, because Service[tomcat] doesn't seem to be in the catalog

Martin Alfke

unread,
Mar 31, 2016, 8:10:27 AM3/31/16
to puppet...@googlegroups.com
Hi Arfoz,

this is the best example on how to _not_ do classes.
Every class should be self contained - as long as possible.
In your case you have a hard reference from one resource inside a class to another resource inside another class.
I always tell my training course attendees that they should never do this unless they don’t like themselves and they want to have Puppet nightmares.

In your case you can do the following hack:

make the add file class a parameterised class, set the parameter to the default behaviour:

class addfile (
$enable_notify => Service[’tomcat’],
) {
file {‘/tmp/hello’:
ensure => file,
notify => $enable_notify,
}
}

On systems where you don’t have tomcat class included you have to declare the class add file with parameter set to undef.

But: be aware that even this is not a good solution.
It’s just a hack.
Try to refacter your modules.

Best,
Martin
> --
> 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...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-users/02cfc06d-d306-48a2-a917-7144606a1509%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Afroz Hussain

unread,
Apr 1, 2016, 5:57:02 AM4/1/16
to Puppet Users
Hi Martin,

Thanks for your help. I have tried your hack but didn't work, still same error,
class addfile ( 
  $enable_notify => Service[’tomcat’], 
) { 
  file {‘/tmp/hello’: 
    ensure => file, 
    notify => $enable_notify,
  }
}

Technically, we can all any resource from any classes since all resources are unique across modules.

Thanks,
Afroz Hussain

jcbollinger

unread,
Apr 1, 2016, 10:11:34 AM4/1/16
to Puppet Users


On Friday, April 1, 2016 at 4:57:02 AM UTC-5, Afroz Hussain wrote:
Hi Martin,

Thanks for your help. I have tried your hack but didn't work, still same error,
class addfile ( 
  $enable_notify => Service[’tomcat’], 
) { 
  file {‘/tmp/hello’: 
    ensure => file, 
    notify => $enable_notify,
  }
}

Technically, we can all any resource from any classes since all resources are unique across modules.


Yes, once declared, resources have global scope.  You can refer to them from any class, in any module or no module.  Martin did not suggest differently.

But the fact the you CAN access resources from anywhere does not mean it's a good idea to do so.  Whether it's reasonable in this particular case is unclear, but doubtful, as for the most part the identities of the resources declared by a given class should be considered implementation details of that class, and depending on another class's implementation details makes your class brittle.

That's not even the most significant problem here, however.  Your (original) Addfile class depends on there is a resource Service['tomcat'] declared for the target node.  If this is sensible in all cases, then it would be best for that class to take its own measures to ensure that its requirement is satisfied, which would be best done by declaring the appropriate class.  For example, if Tomcat is managed via a "tomcat" class, then you might use

class addfile {
  include
'tomcat'
 
# ...
}

But that's a half measure.  Remember that we should avoid depending on implementation details of other classes.  If you are prepared to rely on the tomcat class to provide the needed service resource, then it is probably best to make that class the target of the notification relationship, instead of anything within that you rely on it to declare:

class addfile {
  include
'tomcat'


  file
{"/tmp/hello":
   
ensure => file,
    content
=> "hello"
 
}

 
~>
 
Class['tomcat']
}

Note, among other things, that that works fine if the name of the Tomcat service differs from node to node, and that it does not break if the service name changes (e.g. to "apache-tomcat") in the future.

Much of that is predicated on the idea that signaling Tomcat is a hard requirement, however, and the nature of the error you reported suggests that that might not be the case.  If you want to use your Addfile class on machines where Tomcat is not being managed, and on those machines, therefore, not to notify Service['tomcat'], then you probably need a much deeper re-design than just one class.  Something along the lines of Martin's suggested modification to your class could well be part of such a redesign, but you need rather more.

Indeed, I suspect that the reason Martin's suggestion did not work for you is that you do not appreciate how to use it.  Modifying the class definition as he described will not, in itself, make any difference at all.  To address your problem via his version of the class, you need to also cause the correct data for the target node to be bound to the new class parameter.  But if that's as far as you go then it's just a stopgap.  I think you have deeper problems.


John

Reply all
Reply to author
Forward
0 new messages