Infraestrutura Ágil

Soluções e métodos inteligentes para sua infra

Puppet Resource Type File e Múltiplos Sources

| Comments

Há alguns dias um amigo (Elcimar Freitas) me disse que havia criado uma classe usando o modelo em trio, porém ele queria que certas máquinas recebessem arquivos personalizados, em um primeiro momento ele estava pensando em usar condicionais ou case para resolver o problema, o que é realmente possível, porém, não é muito prático, acabei dando uma dica que aprendi com o mago @dscobral - vulgo gandalf. Aqui neste post vamos resolver o problema dentro do recurso File, acompanhe a explicação e a solução.

Estudando o problema

Veja abaixo um exemplo típico de configuração em trio:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class ntp {

  package { 'ntp':
      ensure => present
  }

  file { '/etc/ntp.conf':
      ensure  => present,
      mode    => 644,
      owner   => root,
      group   => root,
      require => Package['ntp'],
      notify  => Service['ntp'],
      source  => "puppet:///files/ntp/ntp.conf"
  }
  
  service { 'ntp':
      ensure     => running,
      enable     => true,
      hasrestart => true,
      hasstatus  => true,
      require    => File['/etc/ntp.conf'],
  }

}

Poderíamos utilizar tratamento condicional para enviar diferentes arquivos para diferentes nodes, veja um exemplo abaixo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class ntp {

  if $fqdn == 'servidor1.hacklab' {
      $ntpfile = "ntp.conf.servidor1"
  }
  elsif $fqdn == "servidor2.hacklab" {
      $ntpfile = "ntp.conf.servidor2"
  }
  else {
      $ntpfile = "ntp.conf"
  }

  package { 'ntp':
      ensure => present
  }

  file { '/etc/ntp.conf':
      ensure  => present,
      mode    => 644,
      owner   => root,
      group   => root,
      require => Package['ntp'],
      notify  => Service['ntp'],
      source  => "puppet:///files/ntp/${ntpfile}"
  }
  
  service { 'ntp':
      ensure     => running,
      enable     => true,
      hasrestart => true,
      hasstatus  => true,
      require    => File['/etc/ntp.conf'],
  }

}

Ou então poderíamos utilizar o case para tratar a mesma questão de forma diferente, veja o exemplo abaixo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class ntp {

  case $fdqn {
      servidor1.hacklab: { $ntpfile = "ntp.conf.servidor1" }
      servidor2.hacklab: { $ntpfile = "ntp.conf.servidor2" }
      default:    { $ntpfile = "ntp.conf" }
  }

  package { 'ntp':
      ensure => present
  }

  file { '/etc/ntp.conf':
      ensure  => present,
      mode    => 644,
      owner   => root,
      group   => root,
      require => Package['ntp'],
      notify  => Service['ntp'],
      source  => "puppet:///files/ntp/${ntpfile}"
  }
  
  service { 'ntp':
      ensure     => running,
      enable     => true,
      hasrestart => true,
      hasstatus  => true,
      require    => File['/etc/ntp.conf'],
  }

}

Daria até para usar seletores, abaixo mais um exemplo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class ntp {

  package { 'ntp':
      ensure => present
  }

  file { 'ntp.conf':
      ensure  => present,
      mode    => 644,
      owner   => root,
      group   => root,
      require => Package['ntp'],
      notify  => Service['ntp'],
      source    => $fqdn ? {
          'sevidor1.hacklab'   => 'puppet:///files/ntp/ntp.conf.servidor1',
          'servidor2.hacklab'  => 'puppet:///files/ntp/ntp.conf.servidor1',
           default             => 'puppet:///files/ntp/ntp.conf',
      },
  
  }
  
  service { 'ntp':
      ensure     => running,
      enable     => true,
      hasrestart => true,
      hasstatus  => true,
      require    => File['ntp.conf'],
  }

}

Solucionando o problema

Porém nos três casos teríamos que escrever muitas linhas caso fosse necessário ter arquivos diferentes para vários servidores, seria repetitivo e cansativo, e nós utilizamos o puppet justamente para evitar o trabalho repetitivo.

Se lermos com cuidado o manual de resource types, ou se você tiver a sorte de ter um gandalf (@dcsobral) fazendo mentoria de puppet contigo, você poderá encontrar a solução dentro do resource type file, veja como fica a solução mais elegante - na minha opinião.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class ntp {

  package { 'ntp':
      ensure => present
  }

  file { 'ntp.conf':
      ensure  => present,
      mode    => 644,
      owner   => root,
      group   => root,
      require => Package['ntp'],
      notify  => Service['ntp'],
      source  => [
                   "puppet:///files/ntp/ntp.conf.${fqdn}",
                   "puppet:///files/ntp/ntp.conf",
                   ],
  }
  
  service { 'ntp':
      ensure     => running,
      enable     => true,
      hasrestart => true,
      hasstatus  => true,
      require    => File['ntp.conf'],
  }

}

Observe que dentro de source eu declarei que se houver um arquivo chamado ntp.conf.nomedamaquina.dominio, ele vai usar esse arquivo, do contrário, se não existir algum arquivo com $fqdn no nome, ele passa para a próxima opção que seria o arquivo ntp.conf padrão.

Com este tipo de configuração podemos ter dezenas de arquivos de configuração no diretório /etc/puppet/files/ntp, cada um terminando com o nome da máquina a que se destina, isso seria entendido pelo source e processado na ordem determinada.

Eu chamo isso de múltiplos sources, veja mais um exemplo retirado do site da puppetlabs:

1
2
3
4
5
6
7
file { "/etc/nfs.conf":
  source => [
    "puppet:///modules/nfs/conf.$host",
    "puppet:///modules/nfs/conf.$operatingsystem",
    "puppet:///modules/nfs/conf"
  ]
}

No exemplo acima podem existir arquivos terminando com o nome da máquina, sistema operacional ou então a opção final é o arquivo padrão.

Dá para ver que existem muitas formas de se fazer a mesma coisa, o desafio é encontrar a mais eficiente para sua necessidade.

Eu normalmente uso CASE e SELETORES quando tenho que tratar nomes - diferentes - de pacotes em distros linux distintas, ou mesmo PATH para um arquivo de configuração que é diferente no Debian e no CENTOS, nestes casos são muito úteis de fato.

Referências

  • http://docs.puppetlabs.com
  • http://gutocarvalho.net/dokuwiki/doku.php?id=puppet_serverless#case

[s]
Guto

Comments