OpsWorks - Custom Chef JSON

Чтобы передать в OpsWorks свои переменные в Chef-рецепт нужно использовать Custom Chef JSON. В случае использования AWS-консоли эта опция находится в Advanced:

Раскрыв пункт, добавляем свои переменные в JSON, например, в моём текущем рецепте aws_logger, используемом для добавления CloudWatcher-логов для виртулки, они выглядят так:

Код:

{
    "awslogs_conf": {
        "SysLog": {
            "datetime_format": "%b %d %H:%M:%S",
            "file": "/var/log/syslog",
            "buffer_duration": "5000",
            "log_stream_name": "turn3.linuxcmd.ru",
            "initial_position": "start_of_file",
            "log_group_name": "SysLog"
        },
        "FS_logs": {
            "datetime_format": "%b %d %H:%M:%S",
            "file": "/var/log/turn.log",
            "buffer_duration": "5000",
            "log_stream_name": "turn3.linuxcmd.ru",
            "initial_position": "start_of_file",
            "log_group_name": "FS_logs"
        }
    }
}

В результате в рецепте это можно получить и обработать следующим образом (пример из рабочего рецепта):


Код:

if defined?(node['awslogs_conf'])
    Chef::Log.info("*** node['awslogs_conf'] defined and is '#{node['awslogs_conf']}' ***")
    awslogs_conf_data = node['awslogs_conf']
end

default_aws_log = {
    "datetime_format": "%b %d %H:%M:%S",
    "file": "/var/log/syslog",
    "buffer_duration": "5000",
    "log_stream_name": "linuxcmd.ru",
    "initial_position": "start_of_file",
    "log_group_name": "SysLog"
}
if awslogs_conf_data.nil?
    Chef::Log.info("*** node['awslogs_conf'] is nil ***")
    awslogs_conf_data = { 'default_aws_log': default_aws_log}
end

Chef::Log.info("*** awslogs_conf_data = '#{awslogs_conf_data}' ***")

stack = search("aws_opsworks_stack").first
cur_region = stack['region']
stack_name = stack['name']
Chef::Log.info("*** The stack's name is '#{stack_name}', region = '#{cur_region}' ***")

instance = search("aws_opsworks_instance", "self:true").first
cur_hostname = instance['hostname']
Chef::Log.info("*** The instance's hostname is '#{cur_hostname}' ***")

template node["aws_logger"]["config_file"] do
  source "awslogs.conf.erb"
  variables({
    :awslogs_conf_data => awslogs_conf_data,
    :state_file => node["aws_logger"]["state_file"],
  })
  owner "root"
  group "root"
  mode 0644
end

Как видно из кода, добавлена обработка if defined?(node['awslogs_conf']) и if awslogs_conf_data.nil?, чтобы не получать ошибки а-ля "undefined method `each' for nil:NilClass", которые будут появляться при запуске рецепта без передачи в него переменных через JSON, в результате чего они будут либо не определены либо равны нулю.

Конечный шаблон awslogs.conf.erb выглядит так:

[general]
state_file = <%= @state_file %>

<% @awslogs_conf_data.each do |log_conf_name, cur_log| %>
[<%= log_conf_name %> ]
datetime_format     = <%= cur_log[:datetime_format] %>
file                = <%= cur_log[:file] %>
buffer_duration     = <%= cur_log[:buffer_duration] %>
log_stream_name     = <%= cur_log[:log_stream_name] %>
initial_position    = <%= cur_log[:initial_position] %>
log_group_name      = <%= cur_log[:log_group_name] %>

<% end %>

При таком подходе, даже если мы забудем вставить JSON, то всё чётко отработает:

 

Если вам помогла или просто понравилась статья - плюсаните/поделитесь, пожалуйста.

Добавить комментарий