Con rối xuất tài nguyên cho các biến tệp .erb?


8

Kịch bản: tệp cấu hình của tôi được xác định bởi một .erbtệp bao gồm đoạn mã bên dưới.

<% backupclients.each do |backup_files| -%>
Job {
  Name = "Server"
  JobDefs = "DefaultJob"
  Client = <%= backup_files %>-fd
  Pool = TeraMonth
  Write Bootstrap = "/var/lib/bacula/<%= backup_files %>.bsr"
}
<% end -%>

Tệp cấu hình của máy chủ cần một mục lặp lại cho mỗi máy chủ khách. Nếu tôi tạo một mảng đơn giản, nó sẽ hoạt động mà không có vấn đề gì. Tuy nhiên, điều tôi muốn làm là để mỗi máy chủ tự đăng ký và sau đó thu thập dữ liệu bằng cách sử dụng <<| |>>pragma tương tự như những gì người ta sẽ làm với các nagios_*loại.

Các ví dụ chuẩn cho điều này liên quan đến việc xuất khẩu một loại.

class ssh {
  @@sshkey { $hostname: type => dsa, key => $sshdsakey }
  Sshkey <<| |>>
}

Tuy nhiên, tôi hoàn toàn không thể tìm ra cách viết một loại hoặc tham chiếu nó theo cách cho phép tôi đọc mảng giá trị đó từ .erbmẫu. Có cách nào để tôi có thể sử dụng các tài nguyên được xuất kết hợp với một vòng lặp biến trong một .erbtệp không?


Họ có thực sự cần phải kết thúc trong cùng một tập tin? Tôi muốn có mỗi máy chủ lưu trữ trong một tập tin riêng biệt. Một cái gì đó như /etc/bacula/clientdefs/*.conf . Điều này sẽ dễ dàng hơn để đối phó với.
Zoredache

Câu trả lời:


5

Vì vậy, để trả lời trực tiếp câu hỏi của bạn, tôi không tin có được danh sách các tài nguyên được xuất trực tiếp từ erb là có thể. Điều này là do bản chất của tài nguyên xuất khẩu. Đối với Puppet, chúng chỉ là nhiều tài nguyên cần được tạo trên máy chủ.

Nhưng, có một cách để thực hiện những gì bạn đang muốn làm. Tôi làm điều đó ở một vài nơi trong môi trường của tôi.

Ở đây chúng tôi tạo một thư mục chứa các tệp, mỗi tệp cho mỗi máy chủ mà chúng tôi muốn gắn cờ là "bacula_client". Chúng tôi sử dụng purge, forcerecursetùy chọn để gỡ bỏ những file không được quản lý bởi Múa rối (ví dụ: nếu bạn muốn loại bỏ một hệ thống từ này "danh sách").

class bacula::client {

  @@file { "/etc/bacula_clients/$fqdn":
    ensure => present,
    content => "",
    require => File['/etc/bacula_clients'],
    tag => "bacula_client",
  }

}

class bacula::server {

  #
  # .. include whatever else the server requires, like package {} file {} service {}
  #

  file { "/etc/bacula_clients":
    ensure => directory,
    purge => true,
    recurse => true,
    force => true,
  }

  # Populate directory of client files.
  File <<| tag == "bacula_client" |>>

}

Tiếp theo, chúng tôi sử dụng một số mã Ruby trong .erb để quét thư mục này để tìm tệp và hành động theo chúng:

<% 
bacula_clients_dir = '/etc/bacula_clients'
d = Dir.open(bacula_clients_dir)

# Remove directories from the list of entries in the directory (specifically '.' and '..'):
backupclients = d.entries.delete_if { |e| File.directory? "#{bacula_clients_dir}/#{e}" }

backupclients.each do |backup_files| 
-%>
Job {
  Name = "Server"
  JobDefs = "DefaultJob"
  Client = <%= backup_files %>-fd
  Pool = TeraMonth
  Write Bootstrap = "/var/lib/bacula/<%= backup_files %>.bsr"
}
<% end -%>

Bây giờ tôi cảm thấy tồi tệ vì tôi đã viết xong kịch bản của mình hai ngày trước và nó rất gần với định dạng ... điều đó nói rằng, tôi sẽ cho phép bạn chọn liệu bạn cảm thấy câu trả lời của bạn hay câu trả lời của tôi phù hợp hơn để tôi chấp nhận.
Jeff Ferland

Tôi muốn nói câu trả lời của bạn phù hợp hơn nếu ứng dụng có hỗ trợ cho thư mục cấu hình hoặc bao gồm bởi ký tự đại diện (như bacula xuất hiện). Tôi đã sử dụng điều này trong môi trường của mình cho các tập lệnh di chuyển các tệp xung quanh thành một tập hợp các máy chủ đích. Vì vậy, các kịch bản bash chỉ đơn giản là làm ls /path/to/flag/files|while read hostname; do ssh $hostname ..; done.
Kyle Smith

4

Chà, đầu tiên tôi đã từ bỏ và thiết lập @@loại tập tin thực tế của mình. Ưu điểm là điều này vẫn đang sử dụng các biến trên máy chủ.

class bacula-client ($database = false) {
    @@file { "${hostname}-bacula-client.conf":
            mode => 600,
            owner => bacula,
            group => root,
            path => "/etc/bacula/conf.d/${hostname}-client.conf",
            content => template("bacula-dir-cliententry.erb"),
            tag => 'bacula-client',
            notify => Service[bacula-director]
    }

    ...
}

Điều này cho phép tôi sử dụng các mục trong tệp erb, chẳng hạn như:

<% if has_variable?("database") and database== "true" %>
    ...
<% end -%>

và khai báo trong tệp site.pp của tôi, chẳng hạn như: class { bacula-client: database => "true" }

Để xử lý thư mục chính nó:

class bacula-director {
        file { '/etc/bacula/conf.d':
            ensure => directory,
            owner => bacula,
            group => root,
            mode => 600,
            purge => true,
            recurse => true
        }

        ...
}

Thanh lọc và tái diễn làm sạch bất cứ điều gì không được xác định. Khi tôi đưa máy chủ ngoại tuyến, puppetstoredconfigclean $hostnamesẽ xóa thông tin và lần chạy tiếp theo của giám đốc sẽ thiết lập lại cấu hình một cách khủng bố.

Cuối cùng, chính phần mềm giám đốc Bacula cho phép tôi thực hiện các thao tác sau ở cuối tệp bacula-dir.conf của mình:

@|"sh -c 'for f in /etc/bacula/conf.d/*.conf ; do echo @${f} ; done'"

Vì vậy, dường như vẫn không phải là một cách trực tiếp để sử dụng mẫu ERB trên một tập hợp tài nguyên được thu thập, nhưng người ta có thể thu thập một loại. Điều đó có thể bao gồm các loại Augeas để nhét mọi thứ vào một tệp hoặc hack thu thập tệp vào cấu hình. Nó chưa bao gồm những gì tôi đang tìm kiếm cho câu hỏi, mặc dù.


1

Tôi đã sử dụng một phương thức sử dụng dịch vụ PuppetDB hoạt động khá tốt trong tình huống này, mặc dù có một chút hackish. Để sử dụng điều này, bạn sẽ cần phải có hoạt động PuppetDB (mà bạn nên có khi bạn đang sử dụng tài nguyên đã xuất) và API PuppetDB sẽ cần được truy xuất từ ​​Puppetmaster (localhost).

Sau đó, bạn sẽ muốn xuất tất cả các tài nguyên mà bạn muốn thu thập vào mảng của mình trong một thư mục chuyên dụng trên hệ thống tệp. Đường dẫn thư mục này sẽ được sử dụng để xác định duy nhất các tài nguyên đích.

Sau đó, trong mẫu của bạn, làm một cái gì đó như thế này:

    require 'rest_client'
    require 'json'
    resources=JSON.parse(RestClient.get("http://localhost:8080/v2/nodes/#{nodename}/resources", {:accept => :json}))

    retVal = Array.new
    resources.each do |resource|
       if resource["title"] =~ /^#{pathRegex}$/
           retVal.push(resource["title"])
       end
    end

Trong đó nút tên là FQDN của máy chủ, pathRegex là đường dẫn tìm kiếm được đề cập ở trên, được định dạng là Ruby Regex và retVal là mảng hoàn thành. Điều này tận dụng rằng mẫu được xử lý trên con rối để không yêu cầu thông tin API đặc biệt. Điều này cũng giả sử namevar tài nguyên là đường dẫn đủ điều kiện của các tệp đích, nếu bạn có các tên miền phức tạp và sử dụng thuộc tính đường dẫn thì logic phức tạp hơn sẽ được yêu cầu. Cũng lưu ý rằng điều này sẽ trả lại tất cả các tài nguyên, cả xuất khẩu và địa phương. Dữ liệu trả về có nhiều thuộc tính có thể được sử dụng cho logic phức tạp hơn nếu cần.

Một chút hacky, nhưng nó hoạt động tốt.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.