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.