Hi,

Sorry again for my late answer.

On 17/06/2015 19:01, Henrik Lindberg wrote:

> Functions in puppet are under <module>/functions/ and not under 
> <module>/lib/puppet/functions (where only ruby functions should live).
> You do not have to change the bindings - it just called modulename::data() 
> and does not know or care if it is implemented in ruby or puppet.

Ok.

> Clear, with puppet 4 you should be able to do most things (+ merges hashes, 
> you can concatenate arrays etc), the thing you cannot do is change variables, 
> but you can always use local scopes, use the iterative functions etc. This 
> reduces the need to have spaghetti logic and code that requires variables in 
> the first place - i.e. a more functional approach.

Ok, indeed with Puppet 4 it's more flexible but sometimes
I find it's more simple to use ruby code with mutable variables.

>> Ok, I understand well the "function" paradigm but if it's just in order
>> to *read* a fact, for instance to just read the 'lsbdistcodename' fact
>> and put it in a variable, is it really a bad idea? Ok I can add a parameter
>> to my function `fct(a, b, lsbdistcodename)` but if I can avoid this and just
>> have `fct(a, b)` and just get the 'lsbdistcodename' fact value in the
>> function (just for reading), where is the problem in this specific case?
>>
> That is not a problem, it is a global variable so does not depend on calling 
> context. In puppet:
> 
> function fct($a, $b) {
>   # get a fact
>   $facts[lsbdistcodename]
> }

Ok, that's perfect.

> What you want to avoid is creating dependencies - you want your modules to 
> work independently (just it, and its dependencies) without making assumptions 
> that certain data must be bound in hiera in a particular way across all 
> environments.
> 
> As an example if you have a data function for modulea and want to give the 
> default value - you could do:
> 
> function mymodule::data() {
>   { thekey => lookup('network::ip') }
> }
> 
> Now you depend on 'network::ip' existing in hiera and having a value.
> You could specify a default value if the key is missing. Now you have a 
> default value embedded in your module and if you need to change the default, 
> you need to find all such places to change it.
> 
> If you instead make modulea depend on a module 'networking' and let 
> networking contain the default values, you have specified something that is 
> consistent in terms of dependencies (no need to add a default to the lookup). 
> If you want to update the defaults for all usage of network::ip, create a new 
> version of the network module.
> 
> If you need to override that in one environment, add an environment::data() 
> function that returns the ip specific for that environment.
> 
> And, finaly, in a pinch, if you need to change something across all 
> environments Right Now (you need to do it right away and do not have time to 
> make the code changes/check in etc.), then change the network::ip key in 
> hiera.

Err... I'm not sure to well understand. I will explain below with a real 
example.
 
>> Ok, if I understand well with lookup function I allow overriding but
>> with module_b::data() this is not the case.
>>
> Not sure I understand what you are saying. The lookup function looks up the 
> value in hiera, environment, module
> - the looked up key with the highest precedence wins (by default). So 
> overrides are possible. The data function
> just specifies the data for what it is in (a module, or the environment)

If I understand well with lookup('foo::var') in the ::foo class, there will be
a look up:
- in hiera with the foo::var entry;
- in the environment with the environment::data() function (look up the value
of 'foo::var');
- in the foo module with the foo::data() function (look up the value of 
'foo::var'.

Is it correct?

But what happens if I have just lookup('var') (ie the key is unqualified) in the
::foo class? Is there only a lookup in hiera? Because unqualified key seems to 
be
not allowed in a *::data() function?

> If you want to modularize in a good way, and use the style of "theme" and 
> functional decomposition, then you want to avoid using hiera since it only 
> looks up data across all environments. You have to start including the 
> environment in your hierarchy and have hiera "dip into" environments to find 
> data there.
> 
> You then only use hiera for installation specific overrides, and panic 
> changes, everything else is data in modules and environments.

In fact, I'm not sure to understand well. I take an real example.
I have a "network" module with the ::network class:

-------------------------------------
class network ( $interfaces, ) {
  # Configure the file /etc/network/interfaces of a Debian host.
}
-------------------------------------

If I understand well I can set default values in the "data" function
of the "network" module and set the default like this (for instance):

-------------------------------------
network::interfaces = { 
                       'eth0' => { 'method' => 'dhcp' }
                      }
-------------------------------------

And if I want to have another parameters for a specific node, I can put these
in the $fqdn.yaml of the node:

-------------------------------------
network::interfaces:
  eth0:
    method: 'static'
    options:
      address: '172.31.1.2'
      netmask: '255.255.0.0'
      gateway: '172.31.0.1'
  eth1:
    method: 'static'
    options:
      address: '10.0.0.2'
      netmask: '255.0.0.0'
-------------------------------------

Is it correct?

But, now, imagine I want to improve the "network" module. Currently, for each
node which have an address in the "172.31.0.0/16" network, I will probably use
the same gateway ie 172.31.0.1 and I want to avoid it. So I put this in the
"common.yaml" file:

-------------------------------------
# The list of all my networks with some specific values such as
# the gateway (if it exists) or the dns etc.
network-inventory:
  mgt-network:
    address: '172.31.0.0/16'
    gateway: '172.31.0.1'
    dns: [ '172.31.0.1', '172.31.0.2' ]
  web-network:
    address: '192.168.0.0/24'
    gateway: '192.168.0.1'
  nfs-network:
    address: '10.0.0.0/8'
-------------------------------------

And I want to just put something like this in the $fqdn.yaml files:

-------------------------------------
# For each node, I don't want to repeat the same gateway, the
# same netmask etc. 'default' will be replaced by the correct
# value in the corresponding network in "network-inventory".
network::interfaces:
  eth0:
    method: 'static'
    options:
      address: '172.31.1.2/16'
      netmask: 'default'
      gateway: 'default'
  eth1:
    method: 'static'
    options:
      address: '10.0.0.2/8'
      netmask: 'default'
-------------------------------------

And to "auto-complete" the 'default' values above, I have  a 
'::network::profile'
class in the 'network' module with something like that:

-------------------------------------
class network::profile {

  $network_inventory = hiera('network-inventory')
  $interfaces        = hiera('network::interfaces')

  class { '::network':
    interfaces => network::complete_interfaces($interfaces, $network_inventory)
  }

}
-------------------------------------

where 'network::complete_interfaces' is a "smart" function which replaces each
'default' value by the right value (the function will use the CIDR address to
find the good network in $network_inventory hash and to replace a 'default'
value correctly).

How can I do that if I want to modularize in a good way (with the "data 
binding"),
and use the style of "theme" and functional decomposition etc.? If I understand 
well,
it's not a good idea to have hiera lookups in a module and it's exactly that I 
have
made in the example ::network::profile above. So how can I correctly do what I 
want
in a way that respects the Puppet 4 patterns? 

> (At some point I should write some blog posts about this, but I don't have 
> time at the moment).

The lack of time is an argument that I really can understand. ;)
No problem, your help has already been very useful for me.
Thx Henrik.

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 [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/puppet-users/558B8140.8020204%40gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to