Puppet 2.7.x - Variável global - Append

4

Sem ir muito longe nas ervas daninhas, o Nginx está forçando minha mão para realizar alguma mágica com vhosts e com a diretiva map .

Existe uma solução elegante (relativa) para compartilhar uma variável entre várias chamadas de definição, que permite que cada chamada de definição anexe seus dados à variável global? No software, isso seria conhecido como singleton.

- As ervas daninhas -

O Nginx tem uma diretiva map que dita para qual pool de servidores upstream a solicitação deve ser passada, assim:

map $http_host $upstream_pool {

    hostnames;

    blog.example.com     blog_example_com;
    repo.example.com     repo_example_com;

    default example_com;
}

Como você pode ver, todas as solicitações de blog.example.com serão passadas para o pool de servidores upstream blog_example_com (por meio de proxy_pass ).

O problema é que a sintaxe da diretiva map é que ela só pode ser incluída no bloco http principal (nginx.conf), enquanto diretivas específicas do vhost como upstream e location podem ser incluídas no server block de uma configuração vhost.

Meu manifesto nodes.pp é parecido com isto:

 service-a-1.example.com inherits project_dev {

     nginx::vhost { 'mothership': }
     nginx::vhost { 'mothership_blog': }
     nginx::vhost { 'repo': }
}

Como você pode ver, depois de uma corrida de marionetes bem-sucedida, eu deveria acabar com 3 arquivos de configuração vhost distintos em /etc/nginx/vhost.d/ dir.

O problema que estou tendo é que, para que a diretiva map funcione, eu preciso saber quais vhosts foram carregados, para que eu possa adicionar seus respectivos IDs upstream à diretiva map , que defini em a configuração principal: /etc/nginx/nginx.conf dentro do bloco http (do qual só pode haver um).

- O que tentei - -

Eu tenho um arquivo global.pp que faz algumas "bootstrapping" e neste arquivo eu adicionei uma sintaxe $singleton = '' , então no nginx :: vhost define, eu adicionei esta sintaxe:

$tpl_upstream_pool_labels = inline_template("<% tpl_upstream_pools.keys.sort.each do |role| %><%= role %>_<%= tpl_domain_primary %>_<%= tpl_domain_top_level %>|<% end %>")

$singleton = "${singleton}${tpl_upstream_pool_labels}"

notify { "\n--------------------- Nginx::Conf::Vhost::Touch | Timestamp: ${timestamp} | Pool labels: ${singleton} -------------------------\n": }

Qual deve resultar em uma lista delimitada por pipe de IDs upstream. Como mencionado anteriormente, no manifesto nodes.pp, faço três chamadas para nginx :: vhost e esperaria que a variável global $singleton fosse anexada a cada chamada, mas não é, ela contém apenas os dados da última chamada.

Eu também tentei contornar isso escrevendo um arquivo temporário assim:

$temp_file_upstream_pool_labels_uri = "/tmp/puppet_known_upstreams_${timestamp}.txt"

exec { "event_record_known_upstream_${name}" :            
    command     => "touch ${temp_file_upstream_pool_labels_uri} && echo ${tpl_upstream_pool_labels} >> ${temp_file_upstream_pool_labels_uri}",            
    provider    => 'shell'
}

Em seguida, no nginx :: conf :: touch define, onde a configuração primária nginx.conf deve ser escrita pelo fantoche, eu tentei isto:

$temp_file_upstream_pool_labels_uri = "/tmp/puppet_known_upstreams_${timestamp}.txt"

$contents = file($temp_file_upstream_pool_labels_uri)

O qual deve, teoricamente, carregar o conteúdo do arquivo na variável $ contents. Mas quando eu corro fantoche usando essa abordagem, recebo um erro que o arquivo não existe. Eu assegurei que a chamada nginx :: conf :: touch não é feita até que todos os vhosts fossem considerados, mas ainda sem sucesso.

    
por Mike Purcell 17.09.2014 / 07:02

2 respostas

1

O problema com as variáveis globais no Puppet é que você não pode realmente anexá-las. A sintaxe += é permitida, mas cria uma cópia local do global, com o valor do lado direito anexado.

Implementei um padrão que faz o que você quer, mas não me orgulho disso e não posso recomendar o uso dele. Ainda assim, desde que você está perguntando, aqui vai:

class nginx::conf {
    $global = ''
    file { '/etc/nginx/nginx.conf':
        content => template(...)
    }
}

A variável da classe pode ser anexada, pelo menos em 2.7.x .

define nginx::vhost(...) {
    include nginx::conf

    $nginx::conf::global += "new content here"
    nginx::override_conf_content { "for-vhost-$name": }
}

A mágica acontece na misteriosa linha final, que instancia ainda outro define .

define nginx::override_conf_content() {
    include nginx::conf
    $global = $nginx::conf::global
    File<| title == '/etc/nginx/nginx.conf' |> { 
        content => template(...)
    }
}

A propriedade content para nginx.conf é substituída pelo resultado de outra avaliação do modelo, com o novo valor da variável.

Divulgação completa, não sei por que isso funciona. Provavelmente não deveria, e pode confiar em um bug obscuro. Pode parar de funcionar em versões futuras.

Observe que eu chamei de $global em vez de $singleton , porque é isso. Singletons podem ser usados para implementar a semântica dos globals, mas eles não são a mesma coisa.

Finalmente, mesmo que eu possa sentir sua dor enfrentando a atualização do Puppet 3, você deve realmente tomar o tempo e colocá-la em andamento. Todos nós provavelmente não conseguiremos arcar 2.x por muito mais tempo.

    
por 18.09.2014 / 23:46
1

Adicionando outra resposta para manter os problemas separados.

A abordagem que combina exec e file() é falha porque eles funcionam em níveis muito diferentes.

O recurso exec é adicionado ao catálogo e enviado ao agente, onde é avaliado após a conclusão da compilação. Como você está tentando coletar informações durante tempo de compilação (antes de coletá-las usando a função file() ), você não pode confiar em nenhum recurso.

Deve ser possível criar o que você tem em mente confiando na função gerar em vez de exec resources.

    
por 18.09.2014 / 23:50