Назад | Перейти на главную страницу

Puppet 2.7.x - Глобальная переменная - Добавить

Не вдаваясь глубоко в сорняки, Nginx заставляет мою руку совершить некую магию с vhosts и map директива.

Есть ли элегантное (относительное) решение для совместного использования переменной несколькими вызовами определения, которое позволяет каждому вызову определения добавлять данные в глобальную переменную? В программном обеспечении это будет известно как синглтон.

- Сорняки -

Nginx имеет map директива, которая определяет, в какой пул серверов восходящего направления следует передать запрос, например:

map $http_host $upstream_pool {

    hostnames;

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

    default example_com;
}

Как видите, любые запросы для blog.example.com будут передаваться в пул вышестоящих серверов blog_example_com (посредством proxy_pass).

Проблема в том map синтаксис директивы таков, что он может быть включен только в основной http block (nginx.conf), тогда как специфические директивы vhost, такие как upstream и location может быть включен в server блок конфига vhost.

Мой манифест node.pp выглядит примерно так:

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

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

Как видите, после успешного запуска марионетки я должен получить 3 отдельных файла конфигурации vhost в /etc/nginx/vhost.d/ реж.

Проблема, с которой я столкнулся, заключается в том, что для того, чтобы map для работы, мне нужно знать, какие vhosts были загружены, поэтому я могу добавить их соответствующие идентификаторы восходящего потока в map директива, которую я определил в основной конфигурации: /etc/nginx/nginx.conf в пределах http блок (из которых может быть только один).

- Что я пробовал --

У меня есть файл global.pp, который выполняет некоторую "загрузку", и в этот файл я добавил $singleton = '' синтаксис, то в определении nginx :: vhost я добавил этот синтаксис:

$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": }

В результате должен получиться список идентификаторов восходящего потока, разделенных вертикальной чертой. Как упоминалось ранее, в манифесте nodes.pp я делаю три вызова nginx :: vhost и ожидаю, что $singleton глобальная переменная, которая будет добавляться для каждого вызова, но это не так, она содержит только данные последнего вызова.

Я также попытался обойти это, написав временный файл следующим образом:

$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'
}

Затем в определении nginx :: conf :: touch, где основная конфигурация nginx.conf должна быть написана марионеткой, я попробовал следующее:

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

$contents = file($temp_file_upstream_pool_labels_uri)

Теоретически это должно загрузить содержимое файла в переменную $ contents. Но когда я запускаю марионетку, используя этот подход, я получаю сообщение об ошибке, что файл не существует. Я убедился, что вызов nginx :: conf :: touch не будет выполняться до тех пор, пока не будут рассмотрены все vhosts, но все равно безрезультатно.

Добавляем еще один ответ, чтобы вопросы были разделены.

Подход, сочетающий exec и file() ошибочен, потому что они работают на самых разных уровнях.

В exec ресурс добавляется в каталог и отправляется агенту, где он оценивается после завершения компиляции. Поскольку вы пытаетесь собрать информацию в течение время компиляции (перед тем, как собрать его с помощью file() функция), вы не можете полагаться ни на какие ресурсы.

Должно быть возможно построить то, что вы задумали, полагаясь на генерировать функция вместо exec Ресурсы.

Проблема с глобальными переменными в Puppet заключается в том, что вы не можете добавить к ним. В += синтаксис разрешен, но он создает локальная копия глобального значения с добавленным значением правой стороны.

Я реализовал шаблон, который делает то, что вы хотите, но я не горжусь им и не могу рекомендовать его использовать. Тем не менее, раз уж вы спрашиваете, вот что:

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

Переменная из класса жестяная банка быть добавленным, по крайней мере, в 2.7.x.

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

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

Магия происходит в загадочной последней строке, которая создает еще один экземпляр. define.

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

В content собственность для nginx.conf заменяется результатом другой оценки шаблона с новым значением переменной.

Полное раскрытие, я не уверен, почему это работает. Вероятно, этого не должно быть, и это может быть связано с неясной ошибкой. Он может перестать работать в будущих версиях.

Обратите внимание, что я назвал это $global вместо того $singleton, потому что это то, что есть. Синглтоны могут использоваться для реализации семантики глобальных объектов, но это не одно и то же.

Наконец, даже несмотря на то, что я чувствую вашу боль перед обновлением Puppet 3, вам действительно стоит потратить время и приступить к нему. Мы все, скорее всего, не сможем позволить себе бегать 2.x намного длиннее.