What you've stumbled on is the concept of public and private classes. 
Public and private
classes are implemented very differently. A public class is your module's 
entry point,
this is how people interact with your module. A public class is where you 
define your
module's API. Private classes, on the other hand, are not meant to be 
called outside your
module. Private classes are the meat of your module. This is where you will 
actually
implement your module's functionality. A public class should be the only 
way a user can
interact with your private classes. Public classes should generally do very 
little. I
typically limit my public classes to validating the inputs received by my 
parameters and
calling my private classes. Since examples speak louder than words, here's 
an example:

# my_module/manifests/init.pp
class my_module (
  $var1 = $my_module::params::var1, 
  $var2 = $my_module::params::var2, 
  $var3 = $my_module::params::var3, 
) inherits my_module::params { 

  # Validate my parameters
  validate_string($var1)
  validate_array($var2)
  validate_bool($var3)

  # Call my 'private' classes
  class { 'my_module::install': } ->
  class {'my_module::config': } ~>
  class {'my_module::service'} ->
  Class['my_module']

}

The 'my_module' class is my public class. It has three parameters. All this 
class does is
validate my three parameters and call my private classes. Let's take a look 
at those
private classes:

# my_module/manifests/install.pp
class my_module::install (
  $var1 = $my_module::var1,
  $var2 = $my_module::var2,
) {

  private()

  # Body of the class

  ...

}

# my_module/manifests/config.pp
class my_module::config (
  $var2 = $my_module::var2,
  $var3 = $my_module::var3,
) {

  private()

  # Body of the class

  ...

}

# my_module/manifests/service.pp
class my_module::service (
  $var1 = $my_module::var1,
  $var2 = $my_module::var2,
  $var3 = $my_module::var3,
) {

  private()
  
  # Body of the class

  ...

}


As you can see, I've marked my private classes with the private function. 
This function
has not yet been released in stdlib, but is available in trunk
(https://github.com/puppetlabs/puppetlabs-stdlib#private). Google can show 
you how
to implement this functionality in the DSL, if you prefer. The private 
classes concept
allows us to make some assumptions that affect the design of this module, 
specifically,
calling the variables in my_module without inheriting it first. We're 
assuming that, since
this is a private class, it will not be called independently of my_module, 
and those
variables will always be accessible.

This pattern can be found in a number of modules on the forge. Note, that 
these modules
don't use the private function since it hasn't been released yet. They 
assume that the
private classes are only being called inside their module. Here are some 
examples:

https://github.com/garethr/garethr-docker
https://github.com/puppetlabs/puppetlabs-mysql
https://github.com/puppetlabs/puppetlabs-ntp

This is emerging very quickly as a good design pattern that fosters 
modularity,
simplicity, good separation of concerns, and clear data flow.


On Monday, September 22, 2014 4:01:19 AM UTC-7, François Lafont wrote:
>
> Hi, 
>
> Le 19/09/2014 17:36, jcbollinger a écrit : 
>
> > The main points I am trying to get across 
>
> And I thnink that you have succeeded now. ;) 
>
> > are these: 
> > 
> >    1. References to *non-local* variables should always be performed via 
> >    qualified names, even when class inheritance makes the variable in 
> question 
> >    accessible also via its unqualified name. 
> >    2. All qualified names used should accurately reflect the location of 
> >    the referenced entity's declaration (some variables have multiple, 
> distinct 
> >    qualified names). 
> >    3. If a class or defined type refers to a variable belonging to a 
> >    different class then it should ensure via 'include' / 'require' / 
> 'contain' 
> >    or via class inheritance that the variable is initialized first. 
>
> It's very clear. Thanks. 
>
> > I am not saying that references to variables declared *locally* should 
> use 
> > qualified names, but if you want to adopt that practice then it's fine. 
> > 
> > With respect to other classes' variables, though, I seem not to be 
> > successfully communicating point (2). 
>
> Now I have understood the 3 rules. 
>
> >> I use $::test::xxx in class::internal not $::test::params::xxx 
> >> because when xxx is "var1" or "var2", I want to have the value of 
> >> var1 and var2 given as parameters of the test class (I don't want 
> >> the default value of var1 and var2). 
> >> 
> > 
> > 
> > Yes, that's fine for var1 and var2, but not for foo1 and foo2 which are 
> not 
> > declared by class test.  I don't see any particular purpose for foo1 and 
> > foo2 to live in test::params anyway, however, if they are not to be used 
> as 
> > class parameter defaults.  You could as easily put them directly in 
> class 
> > test, and then continue to refer to them as you are now doing. 
>
> Yes, it's good idea. 
> Finally, as regards your comments, I think follow this pattern where I 
> follow 
> your 3 rules, it seems ;): 
>
> ----------------------------------------------------- 
> # Example of declaration for the "test" class. 
> class { test: 
>   var1 => 'specific_var1', 
> } 
>
> #### test module with its classes #### 
>
> class test::params { 
>
>   # API of the module with the default values. 
>   $var1 = 'default_var1' 
>   $var2 = 'default_var2' 
>
> } 
>
> # The *main* class of the module 
> class test ( 
>   $var1 = $::test::params::var1, 
>   $var2 = $::test::params::var2, 
> ) inherits test::params { 
>
>   # Shared variables in all classes of the module. 
>   $foo1 = 'value_foo1' 
>   $foo2 = 'value_foo2' 
>
>   include ::test::internal 
>
>   # Here, I could use $var1, $var2, $foo1, $foo2 
>   # (only in the main class of the module). 
>   notify { 'v1': message => "var1 = $::test::var1", } 
>   notify { 'v2': message => "var2 = $::test::var2", } 
>   notify { 'f1': message => "foo1 = $::test::foo1", } 
>   notify { 'f2': message => "foo2 = $::test::foo2", } 
>
>   # etc. 
>
> } 
>
> class test::internal { 
>
>   # It's an internal class of the module test which will be 
>   # never called by the "user". So, the line below is useless. 
>   # It's just for self-documenting. 
>   # Maybe I could remove this line, I don't know... 
>   require ::test 
>
>   notify { 'iv1': message => "Internal var1 = $::test::var1", } 
>   notify { 'iv2': message => "Internal var2 = $::test::var2", } 
>   notify { 'if1': message => "Internal foo1 = $::test::foo1", } 
>   notify { 'if2': message => "Internal foo2 = $::test::foo2", } 
>
>   # So, in templates, I use the syntax scope['::test::var'] 
>   file { '/tmp/internal.txt': 
>     content => inline_template("var1=<%= scope['::test::var1'] 
> %>\nfoo2=<%= scope['::test::foo2'] %>\n"), 
>   } 
> } 
> ----------------------------------------------------- 
>
> > By the way, don't be confused about the meaning of the 'include' 
> statement, 
> > or its siblings 'require' and 'contain'.  'Include' says that the named 
> > class must be included *in the catalog*; it does NOT interpolate the 
> named 
> > class's body in place of the include statement (i.e. it is not analogous 
> to 
> > a C preprocessor #include directive).  A given class can be the subject 
> of 
> > any number of 'include', 'require', and 'contain' statements; no class 
> will 
> > appear in the catalog more than once. 
>
> Yes, it's clear and even clearer with your link below. 
>
> > In part, it looks like you are running into bug 1220 
> > <https://tickets.puppetlabs.com/browse/PUP-1220>.   
>
> Yes, this is exactly my problem! 
>
> > That was reported fixed 
> > in Puppet 3.5.0, but if I understand correctly, you need to enable the 
> > future parser to actually activate the bug fix (which would make the 
> > variable reference in your template fail to resolve in both cases). 
>
> I confirm. If I put: 
>
>     parser = future 
>
> in the puppet.conf (in [main] section), I have the expected behaviour. 
> To my mind, the execpted behaviour (explained in the puppet documentation) 
> occurs with "parser = future" which is *not* enabled by default. 
> It's curious, but not a problem for me. I guess it's a backward 
> compatibility problem... 
>
> >> And in this case, I don't understand. I thought that : 
> >> 
> >>   $var1 = "value_var1"       # LINE A 
> >>   include ::test::internal   # LINE B 
> >> 
> >> and 
> >> 
> >>   include ::test::internal   # LINE B 
> >>   $var1 = "value_var1"       # LINE A 
> >> 
> >> was completely equivalent. Am I wrong? 
> >> 
> >> 
> > 
> > Yes, you are wrong, but the reason is a bit subtle.  For a comprehensive 
> > explanation, see 
> > 
> http://puppet-on-the-edge.blogspot.com/2014/04/getting-your-puppet-ducks-in-row.html
>  
>
> Thanks for this link which I read and read again. Very interesting. 
> This link has helped me to understand a lot of things in Puppet. 
> For intance, it's too simple to say "puppet is declarative". 
> No, this is not exact. There a phase, the evaluation of manifests 
> and the building of the catalog where puppet is deeply imperative. 
> Very interesting... 
>
> > both at the same time.  You really ought to consider externalizing your 
> > data and accessing via Hiera.   
>
> I will ;) ... but not in module, only in "profiles" as explained in the 
> link below: 
>
> http://garylarizza.com/blog/2014/02/17/puppet-workflow-part-2/ 
>
> I don't want Hiera lookups in modules but only in profiles. 
>
> I have really learned a lot of things in this thread. Sincerely 
> thank you for all your long and detailed explanations. Although 
> I have cut lot of quotes of your messages, I have really read 
> everything very carefully. 
>
> Thank you again for your help. :) 
>
> François Lafont 
>
>

-- 
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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/puppet-users/03257138-944b-47a9-ae98-15ae0f487e57%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to