Рекурсивно создавать дерево каталогов в марионетке без очистки
Я хочу создать структуру каталогов /var/www/apps/example/current/public
, если она не существует, используя марионетку. Если он уже существует, я не хочу очищать содержимое каталогов. Как мне это сделать? Ниже я до сих пор:
file { "/var/www/apps/example/current/public":
owner => 'deploy',
group => 'users',
ensure => "directory",
purge => false,
recurse => true
}
Это дает мне
Cannot create /var/www/apps/example/current/public; parent directory /var/www/apps/example/current does not exist
Ответы
Ответ 1
Параметр recurse
не позволяет создавать родительские каталоги. Он используется для принудительного ввода значений свойств, таких как owner
, mode
и т.д. В содержимое каталога и подкаталоги рекурсивно.
file { '/var/www':
owner => 'www-data',
recurse => true,
}
На самом деле, Puppet в настоящее время не может автоматически создавать все родительские каталоги. Вы должны добавить все соответствующие каталоги в качестве ресурсов.
file { [ '/var/www/apps',
'/var/www/apps/example',
'/var/www/apps/example/current',
'/var/www/apps/example/current/public', ]:
ensure => directory,
...
}
Существующий контент останется без изменений. Нет необходимости передавать параметр purge
.
Ответ 2
exec { "Create ${mydir}":
creates => $mydir,
command => "mkdir -p ${mydir}",
path => $::path
} -> file { $mydir : }
Последняя строка состоит в том, что другие ресурсы (например, файлы для создания внутри $mydir
) могут зависеть от File[$mydir]
, как если бы можно было создать его с помощью простого старого блока file {}
, который он действительно должен.
Ответ 3
Это правда, что марионетка не будет создавать родительские каталоги для вас, но вы можете легко создать файлового поставщика, который это сделает. Например, я создал настраиваемый тип и провайдер, чтобы в основном запускать "mkdir -p" в системах POSIX: https://docs.puppetlabs.com/puppet/latest/reference/lang_namespaces.html
Тем не менее, действительно хорошая причина в том, что Puppet не делает этого по умолчанию. Это потому, что Puppet не хочет отвечать за ваши разрешения в нескольких каталогах, поскольку агент работает от имени root. Это может быть плохо, если вы предоставляете /var/www или что-то в этом роде.
Параметр файла recuse действительно предназначен для управления параметрами дерева каталогов: https://docs.puppetlabs.com/references/latest/type.html#file-attribute-recurse
Вы можете создать дерево каталогов и выполнить его, используя, например, source = > 'puppet:///' uri, установить recurse в true и использовать все режимы файлов, которые устанавливаются в дереве каталогов, служил.
Ответ 4
Я попытался найти хорошее решение, но не смог. Поэтому я сам понял путь. Надеюсь, это полезно для других людей.
Следующая функция будет генерировать список родительских каталогов, а затем мы можем использовать список для создания родительских папок. Первый аргумент - это путь, который используется в качестве отправной точки для поиска родительских каталогов; второй аргумент является необязательным и используется как конечная точка (исключение), чтобы остановить поиск:
module Puppet::Parser::Functions
newfunction(:parentdirs, :type => :rvalue, :doc => <<-EOS
Build a list of all its parent directories.
EOS
) do |arguments|
raise(Puppet::ParseError, "parentdirs(): Wrong number of arguments " +
"given (#{arguments.size} for 1)") if arguments.size < 1
$dir_until = arguments.size > 1 ? arguments[1] : nil
$cur = File.dirname(arguments[0])
$result = []
begin
$result.unshift($cur)
$last = $cur
$cur = File.dirname($cur)
end while $cur != $last and !$cur.end_with?('/') and $cur != $dir_until
return $result
end
end
Вот пример того, как его использовать:
$my_folder = '/var/www/apps/example/current/public'
$parent_dirs = parentdirs($my_folder, '/var/www/apps')
file { $parent_dirs:
ensure => 'directory',
owner => 'deploy',
group => 'users'
}
file { $my_folder:
ensure => 'directory',
owner => 'deploy',
group => 'anonymous'
}
Приведенные выше коды обеспечат создание папок '/var/www/apps/example' и '/var/www/apps/example/current', созданных до создания '/var/www/apps/example/current/public' while '/var/www/apps/example' и выше остаются не затронутыми.
Я тестировал его только в Windows. Но он должен работать в среде Linux.
Это не идеально. Но это лучше, чем перечисление всех родителей один за другим вручную.
Ответ 5
Если вы используете "define", вы можете иметь что-то вроде этого:
mymodule::recursive_dir { "My Directory" :
drive => "C:",
path => "/path/to/folder",
}
Где я определяю "define" в mymodule.rb:
define mymodule::recursive_dir ($drive, $path) {
$folders = split($path, "/")
$folders.each |$index, $folder| {
$calculated_folder = inline_template("<%= @folders[0, @index + 1].join('/') %>")
$full_path = "${drive}${calculated_folder}"
if (! defined(File[$full_path]) and $full_path != $drive) {
file { $full_path :
ensure => directory,
}
}
}
}
Это разделяет путь и создает каждый каталог, поскольку он помещает путь обратно вместе, не пытаясь создать сам диск.
Ответ 6
Спасибо Энтони.
Я не знал, куда поместить код для его функции, и в результате моего исследования я переписал все это с использованием более нового синтаксиса, но сохранил его логику.
Мне потребовалось довольно много времени, чтобы решить все это, поэтому я решил, что было бы хорошо опубликовать это здесь.... Я бы просто добавил его в качестве комментария к его ответу, но, видимо, для этого мне нужно 50 баллов, а не ноль.
Код должен быть сохранен в своем собственном файле в каталоге среды Puppet следующим образом:
lib/puppet/functions/parentdirs.rb
... так что полный путь будет примерно таким (на сервере Ubuntu 18.04 с использованием пакетов Puppet, а не репо):
/etc/puppetlabs/code/environments/testing/lib/puppet/functions/parentdirs.rb
... кажется, есть и другие места, где вы можете это выразить, но это то, что я сделал.
Обратите внимание, что это файл .rb
, а не .pp
(потому что это код Ruby, а не Puppet).
Я получил большую часть своей информации с https://puppet.com/docs/puppet/5.5/functions_ruby_overview.html и с подстраниц.
Использование такое же, как и в оригинальной функции, и несколько пересмотрено в комментариях
# Returns an array of the parent directories to the given file or directory. This can then be passed to File to create the directory tree require for a dynamic path value.
# Parameter 2 is an optional, higher level of the same path. These higher level directories will not be in the array.
# Example 1: parameter 1 is '/var/www/mysite'; parameter 2 is not given; returns array ['/var', '/var/www']
# Example 2: parameter 1 is '/var/www/mysite'; parameter 2 is '/var'; returns array ['/var/www']
Puppet::Functions.create_function(:parentdirs) do
dispatch :parents do
required_param 'String', :target_dir
optional_param 'String', :dir_until
return_type 'Array'
end
def parents(target_dir, dir_until = '')
cur = File.dirname(target_dir)
result = []
begin
result.unshift(cur)
last = cur
cur = File.dirname(cur)
end while cur != last and !cur.end_with?('/') and cur != dir_until
return result
end
end
Ответ 7
Вот чисто кукольное решение для mkdir -p $(dirname $file_path)
$file_path = '/tmp/foo/bar/bob.conf' # assumes file_path is Stdlib::Unixpath
# strip leading '/' then split and loop
$dirs = $file_path[1,-1].dirname.split('/').reduce([]) |$memo, $subdir| {
$_dir = $memo.empty ? {
true => "/${subdir}",
default => "${$memo[-1]}/${subdir}",
}
concat($memo, $_dir)
}
file {$dirs:
ensure => directory,
}