From c2a40f0fcb2a288d66f848dcd4bc1da995d194ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Guimar=C3=A3es=20Malucelli?= Date: Tue, 31 Jan 2017 17:13:41 -0200 Subject: [PATCH] implementing a better way to handle aws cloudWatch logs configurations --- .kitchen.yml | 2 +- .rubocop_todo.yml | 67 ----------------------------- CHANGELOG.md | 7 ++- README.md | 35 ++++++++++----- attributes/default.rb | 8 ++-- libraries/matchers.rb | 28 ++++++++++++ metadata.rb | 2 +- providers/aws_cwlogs.rb | 45 +++++++++++++++++++ recipes/config.rb | 19 ++++---- recipes/default.rb | 8 ++-- recipes/install.rb | 20 ++++----- resources/aws_cwlogs.rb | 28 ++++++++++++ templates/default/awslogs.conf.erb | 11 ----- templates/default/template.conf.erb | 10 +++++ 14 files changed, 170 insertions(+), 120 deletions(-) delete mode 100644 .rubocop_todo.yml create mode 100644 libraries/matchers.rb create mode 100644 providers/aws_cwlogs.rb create mode 100644 resources/aws_cwlogs.rb create mode 100644 templates/default/template.conf.erb diff --git a/.kitchen.yml b/.kitchen.yml index b039542..4780b9d 100644 --- a/.kitchen.yml +++ b/.kitchen.yml @@ -3,7 +3,7 @@ driver: name: vagrant provisioner: - name: chef_zero + name: chef_solo platforms: - name: ubuntu-14.04 diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml deleted file mode 100644 index 5361324..0000000 --- a/.rubocop_todo.yml +++ /dev/null @@ -1,67 +0,0 @@ -# This configuration was generated by -# `rubocop --auto-gen-config` -# on 2016-10-11 09:04:13 -0300 using RuboCop version 0.43.0. -# The point is for the user to remove these configuration records -# one by one as the offenses are removed from the code base. -# Note that changes in the inspected code, or installation of new -# versions of RuboCop, may require this file to be generated again. - -# Offense count: 2 -Lint/ParenthesesAsGroupedExpression: - Exclude: - - 'recipes/config.rb' - -# Offense count: 4 -# Configuration parameters: AllowHeredoc, AllowURI, URISchemes. -# URISchemes: http, https -Metrics/LineLength: - Max: 155 - -# Offense count: 4 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, UseHashRocketsWithSymbolValues, PreferHashRocketsForNonAlnumEndingSymbols. -# SupportedStyles: ruby19, hash_rockets, no_mixed_keys, ruby19_no_mixed_keys -Style/HashSyntax: - Exclude: - - 'recipes/config.rb' - -# Offense count: 3 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. -# SupportedStyles: special_inside_parentheses, consistent, align_braces -Style/IndentHash: - Exclude: - - 'attributes/default.rb' - - 'recipes/config.rb' - -# Offense count: 5 -# Cop supports --auto-correct. -# Configuration parameters: Width. -Style/IndentationWidth: - Exclude: - - 'recipes/config.rb' - - 'recipes/install.rb' - -# Offense count: 7 -# Cop supports --auto-correct. -Style/LeadingCommentSpace: - Exclude: - - 'attributes/default.rb' - - 'recipes/default.rb' - -# Offense count: 3 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedOctalStyle, SupportedOctalStyles. -# SupportedOctalStyles: zero_with_o, zero_only -Style/NumericLiteralPrefix: - Exclude: - - 'recipes/config.rb' - - 'recipes/install.rb' - -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, ConsistentQuotesInMultiline. -# SupportedStyles: single_quotes, double_quotes -Style/StringLiterals: - Exclude: - - 'recipes/install.rb' diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b31f35..8b0ff15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,13 @@ Changes ======= +# 1.1.5 / 2017-01-31 +* Implementing a better way to handle AWS CloudWatch Logs configurations, + now each log has a configuration file that is provisioned via Chef Resources. + # 1.1.4 / 2016-11-07 -* Implementing `logging_config_file` configuration, that overrides the default logging configuration to a WARNING value. +* Implementing `logging_config_file` configuration, that overrides the default + logging configuration to a WARNING value. # 1.1.3 / 2016-10-31 * Fixing `aws_access_key_id` and `aws_secret_access_key` attributes values. diff --git a/README.md b/README.md index e44db92..8f5de69 100644 --- a/README.md +++ b/README.md @@ -9,18 +9,18 @@ Agent and deploy it's configurations automatically. Add this cookbook to your base recipe: ```ruby -cookbook 'aws-cloudwatchlogs', '~> 1.1.4' +cookbook 'aws-cloudwatchlogs', '~> 1.1.5' ``` You need to configure the following node attributes via an `environment` or `role`: ```ruby default_attributes( - 'aws-cwlogs' => { + 'aws_cwlogs' => { 'region' => 'your_aws_region', 'aws_access_key_id' => 'your_aws_access_key', 'aws_secret_access_key' => 'your_aws_secret_key', - 'log_files' => { - '/var/log/syslog' => { + 'log' => { + 'syslog' => { 'datetime_format' => '%b %d %H:%M:%S', 'file' => '/var/log/syslog', 'buffer_duration' => '5000', @@ -35,10 +35,10 @@ default_attributes( Or you can also configure by declaring it in another cookbook at a higher precedence level: ```ruby -default['aws-cwlogs']['region'] = 'your_aws_region' -default['aws-cwlogs']['aws_access_key_id'] = 'your_aws_access_key' -default['aws-cwlogs']['aws_secret_access_key'] = 'your_aws_secret_key' -default['aws-cwlogs']['log_files']['/var/log/syslog'] = { +default['aws_cwlogs']['region'] = 'your_aws_region' +default['aws_cwlogs']['aws_access_key_id'] = 'your_aws_access_key' +default['aws_cwlogs']['aws_secret_access_key'] = 'your_aws_secret_key' +default['aws_cwlogs']['log']['syslog'] = { 'datetime_format' => '%b %d %H:%M:%S', 'file' => '/var/log/syslog', 'buffer_duration' => '5000', @@ -48,7 +48,22 @@ default['aws-cwlogs']['log_files']['/var/log/syslog'] = { } ``` -**Remember**: You can configure as many logs as you need with `log_files` attribute. +Once you defined the attributes, you will need to reference `aws_cwlogs` resource in your recipe: +```ruby +include_recipe 'aws-cloudwatchlogs' + +aws_cwlogs 'syslog' do + log node['aws_cwlogs']['log']['syslog'] +end + +aws_cwlogs 'messages' do + log node['aws_cwlogs']['log']['messages'] +end +``` + +This will create a unique configuration file in AWS CloudWatch Logs that will be stored in `etc/config` directory. + +**Remember**: You can configure as many logs as you need with `log` attribute. **Note**: We are not making use of `data_bags` for AWS Credentials in this recipe at this time. @@ -57,7 +72,7 @@ default['aws-cwlogs']['log_files']['/var/log/syslog'] = { Those attributes used before will generate the AWS CloudWatch Logs configuration below: ```ini -[/var/log/syslog] +[syslog] datetime_format = %b %d %H:%M:%S file = /var/log/syslog buffer_duration = 5000 diff --git a/attributes/default.rb b/attributes/default.rb index 6eca5dc..d8d5130 100644 --- a/attributes/default.rb +++ b/attributes/default.rb @@ -18,9 +18,9 @@ # # AWS Credentials -default['aws-cwlogs']['region'] = nil -default['aws-cwlogs']['aws_access_key_id'] = nil -default['aws-cwlogs']['aws_secret_access_key'] = nil +default['aws_cwlogs']['region'] = nil +default['aws_cwlogs']['aws_access_key_id'] = nil +default['aws_cwlogs']['aws_secret_access_key'] = nil # AWS CloudWatch Logs -default['aws-cwlogs']['path'] = '/var/awslogs' +default['aws_cwlogs']['path'] = '/var/awslogs' diff --git a/libraries/matchers.rb b/libraries/matchers.rb new file mode 100644 index 0000000..eaa4994 --- /dev/null +++ b/libraries/matchers.rb @@ -0,0 +1,28 @@ +# +# Cookbook Name:: aws-cloudwatchlogs +# Libraries:: matchers +# +# Copyright 2016, Alexandre Malucelli, All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +if defined?(ChefSpec) + def add_aws_cwlogs(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:aws_cwlogs, :add, resource_name) + end + + def remove_aws_cwlogs(resource_name) + ChefSpec::Matchers::ResourceMatcher.new(:aws_cwlogs, :remove, resource_name) + end +end diff --git a/metadata.rb b/metadata.rb index 833a3a4..dfc7545 100644 --- a/metadata.rb +++ b/metadata.rb @@ -4,6 +4,6 @@ license 'Apache 2.0' description 'Installs/Configures AWS CloudWatch Logs Agent' long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) -version '1.1.4' +version '1.1.5' source_url 'https://github.com/amalucelli/chef-cloudwatchlogs' if respond_to? :source_url issues_url 'https://github.com/amalucelli/chef-cloudwatchlogs/issues' if respond_to? :issues_url diff --git a/providers/aws_cwlogs.rb b/providers/aws_cwlogs.rb new file mode 100644 index 0000000..5e5aaaa --- /dev/null +++ b/providers/aws_cwlogs.rb @@ -0,0 +1,45 @@ +# +# Cookbook Name:: aws-cloudwatchlogs +# Providers:: aws_cwlogs +# +# Copyright 2016, Alexandre Malucelli, All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +provides :aws_cwlogs if respond_to?(:provides) +use_inline_resources if defined?(use_inline_resources) + +action :add do + Chef::Log.debug "Adding configuration for #{new_resource.name}" + template ::File.join(node['aws_cwlogs']['path'], 'etc/config', "#{new_resource.name}.conf") do + owner 'root' + mode 00600 + source 'template.conf.erb' + variables ({ + logName: new_resource.name, + logConfig: new_resource.log + }) + cookbook new_resource.cookbook + notifies :restart, 'service[awslogs]', :delayed + end +end + +action :remove do + conf_path = ::File.join(node['aws_cwlogs']['path'], 'etc/config') + Chef::Log.debug "Removing #{new_resource.name} from #{conf_path}" + file ::File.join(node['aws_cwlogs']['path'], 'etc/config', "#{new_resource.name}.conf") do + action :delete + notifies :restart, 'service[awslogs]', :delayed + end +end diff --git a/recipes/config.rb b/recipes/config.rb index 8da9967..1fc0645 100644 --- a/recipes/config.rb +++ b/recipes/config.rb @@ -18,20 +18,20 @@ # # always keep aws.conf updated -template "#{node['aws-cwlogs']['path']}/etc/aws.conf" do +template "#{node['aws_cwlogs']['path']}/etc/aws.conf" do source 'aws.conf.erb' owner 'root' group 'root' mode 0600 variables ({ - :awsRegion => node['aws-cwlogs']['region'], - :awsAccessKey => node['aws-cwlogs']['aws_access_key_id'], - :awsSecretKey => node['aws-cwlogs']['aws_secret_access_key'] + :awsRegion => node['aws_cwlogs']['region'], + :awsAccessKey => node['aws_cwlogs']['aws_access_key_id'], + :awsSecretKey => node['aws_cwlogs']['aws_secret_access_key'] }) end # always keep logging.conf updated -template "#{node['aws-cwlogs']['path']}/etc/logging.conf" do +template "#{node['aws_cwlogs']['path']}/etc/logging.conf" do source 'logging.conf.erb' owner 'root' group 'root' @@ -40,18 +40,17 @@ # always generate awslogs.conf based on default # attributes related to log files -template "#{node['aws-cwlogs']['path']}/etc/awslogs.conf" do +template "#{node['aws_cwlogs']['path']}/etc/awslogs.conf" do source 'awslogs.conf.erb' owner 'root' group 'root' mode 0644 - variables ({ - :logFiles => node['aws-cwlogs']['log_files'] - }) end # always restart aws cloudwatch logs agent # after the configuration files were updated service 'awslogs' do - action [:restart] + action [:enable, :restart] + supports :restart => true, :status => true, :start => true, :stop => true + subscribes :restart, "template [#{node['aws_cwlogs']['path']}/etc/awslogs.conf]", :delayed end diff --git a/recipes/default.rb b/recipes/default.rb index d718742..a3c14be 100644 --- a/recipes/default.rb +++ b/recipes/default.rb @@ -17,22 +17,22 @@ # limitations under the License. # -if node['aws-cwlogs']['region'].nil? +if node['aws_cwlogs']['region'].nil? log('AWS Region is necessary for this cookbook.') { level :error } return end -if node['aws-cwlogs']['aws_access_key_id'].nil? +if node['aws_cwlogs']['aws_access_key_id'].nil? log('AWS Access Key is necessary for this cookbook.') { level :error } return end -if node['aws-cwlogs']['aws_secret_access_key'].nil? +if node['aws_cwlogs']['aws_secret_access_key'].nil? log('AWS Secret Access Key is necessary for this cookbook.') { level :error } return end # only install if it isn't installed -include_recipe 'aws-cloudwatchlogs::install' unless ::File.exist?(node['aws-cwlogs']['path']) +include_recipe 'aws-cloudwatchlogs::install' unless ::File.exist?(node['aws_cwlogs']['path']) # always reconfigure aws cloudwatch logs configuration files include_recipe 'aws-cloudwatchlogs::config' diff --git a/recipes/install.rb b/recipes/install.rb index ef18580..3103769 100644 --- a/recipes/install.rb +++ b/recipes/install.rb @@ -18,23 +18,23 @@ # # create base directory of agent even if it isn't installed yet -directory "#{node['aws-cwlogs']['path']}/etc" do +directory "#{node['aws_cwlogs']['path']}/etc" do recursive true end -template "#{node['aws-cwlogs']['path']}/etc/aws.conf" do +template "#{node['aws_cwlogs']['path']}/etc/aws.conf" do source 'aws.conf.erb' owner 'root' group 'root' mode 0600 variables ({ - :awsRegion => node['aws-cwlogs']['region'], - :awsAccessKey => node['aws-cwlogs']['aws_access_key_id'], - :awsSecretKey => node['aws-cwlogs']['aws_secret_access_key'] + :awsRegion => node['aws_cwlogs']['region'], + :awsAccessKey => node['aws_cwlogs']['aws_access_key_id'], + :awsSecretKey => node['aws_cwlogs']['aws_secret_access_key'] }) end -template "#{node['aws-cwlogs']['path']}/etc/logging.conf" do +template "#{node['aws_cwlogs']['path']}/etc/logging.conf" do source 'logging.conf.erb' owner 'root' group 'root' @@ -46,13 +46,10 @@ owner 'root' group 'root' mode 0644 - variables ({ - :logFiles => node['aws-cwlogs']['log_files'] - }) end # download setup script that will install aws cloudwatch logs agent -remote_file "#{node['aws-cwlogs']['path']}/awslogs-agent-setup.py" do +remote_file "#{node['aws_cwlogs']['path']}/awslogs-agent-setup.py" do source 'https://s3.amazonaws.com/aws-cloudwatch/downloads/latest/awslogs-agent-setup.py' owner 'root' group 'root' @@ -61,7 +58,7 @@ # install aws cloudwatch logs agent execute 'Install CloudWatch Logs Agent' do - command "#{node['aws-cwlogs']['path']}/awslogs-agent-setup.py -n -r #{node['aws-cwlogs']['region']} -c /tmp/awslogs.cfg" + command "#{node['aws_cwlogs']['path']}/awslogs-agent-setup.py -n -r #{node['aws_cwlogs']['region']} -c /tmp/awslogs.cfg" not_if { system 'pgrep -f awslogs' } end @@ -69,4 +66,5 @@ # the agent will run with the custom configurations service 'awslogs' do action [:enable, :restart] + supports :restart => true, :status => true, :start => true, :stop => true end diff --git a/resources/aws_cwlogs.rb b/resources/aws_cwlogs.rb new file mode 100644 index 0000000..b2a0fa4 --- /dev/null +++ b/resources/aws_cwlogs.rb @@ -0,0 +1,28 @@ +# +# Cookbook Name:: aws-cloudwatchlogs +# Resources:: aws_cwlogs +# +# Copyright 2016, Alexandre Malucelli, All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +resource_name :aws_cwlogs if respond_to?(:resource_name) +provides :aws_cwlogs if respond_to?(:provides) + +actions :add, :remove +default_action :add if defined?(default_action) + +attribute :name, :kind_of => String, :name_attribute => true +attribute :cookbook, :kind_of => String, :default => 'aws-cloudwatchlogs' +attribute :log, :kind_of => Hash, :required => true, :default => {} diff --git a/templates/default/awslogs.conf.erb b/templates/default/awslogs.conf.erb index e1f9f01..74cceb1 100644 --- a/templates/default/awslogs.conf.erb +++ b/templates/default/awslogs.conf.erb @@ -117,14 +117,3 @@ logging_config_file = /var/awslogs/etc/logging.conf # ---------------------------------------------------------------------------------------------------------------------- # %c Locale's appropriate date and time representation. Tue Aug 16 21:30:00 1988 (en_US) # ---------------------------------------------------------------------------------------------------------------------- - -<% unless @logFiles.nil? -%> -<% @logFiles.each do |logName, logConfig| %> - -<%= '[' + logName + ']' %> -<% logConfig.each do |key,value| %> -<%= key %> = <%= value %> -<% end %> - -<% end %> -<% end -%> diff --git a/templates/default/template.conf.erb b/templates/default/template.conf.erb new file mode 100644 index 0000000..d71a238 --- /dev/null +++ b/templates/default/template.conf.erb @@ -0,0 +1,10 @@ +<% unless @logName.nil? -%> +<% unless @logConfig.nil? -%> + +<%= '[' + @logName + ']' %> +<% @logConfig.each do |key,value| %> +<%= key %> = <%= value %> +<% end %> + +<% end %> +<% end %>