diff --git a/Batali b/Batali index a500d30..b153bad 100644 --- a/Batali +++ b/Batali @@ -37,5 +37,6 @@ Batali.define do cookbook 'timezone-ii' cookbook 'nodejs', '~> 2.4.4' cookbook 'ark' + cookbook 'logrotate' end diff --git a/batali.manifest b/batali.manifest index d903336..b0e8c5a 100644 --- a/batali.manifest +++ b/batali.manifest @@ -879,6 +879,18 @@ "url": "https://supermarket.chef.io:443/api/v1/cookbooks/timezone-ii/versions/0.2.0/download", "version": "0.2.0" } + }, + { + "name": "logrotate", + "dependencies": [ + + ], + "version": "1.9.2", + "source": { + "type": "Batali::Source::Site", + "url": "https://supermarket.chef.io:443/api/v1/cookbooks/logrotate/versions/1.9.2/download", + "version": "1.9.2" + } } ] } \ No newline at end of file diff --git a/cookbooks/logrotate/.gitignore b/cookbooks/logrotate/.gitignore new file mode 100644 index 0000000..f14bce1 --- /dev/null +++ b/cookbooks/logrotate/.gitignore @@ -0,0 +1,25 @@ +*~ +*# +.#* +\#*# +.*.sw[a-z] +*.un~ +*.tmp +*.bk +*.bkup +.kitchen.local.yml +Berksfile.lock + +.bundle/ +.cache/ +.kitchen/ +.vagrant/ +.vagrant.d/ +bin/ +tmp/ +vendor/ + +# RVM +.ruby-version +.ruby-gemset +.rvmrc \ No newline at end of file diff --git a/cookbooks/logrotate/.kitchen.yml b/cookbooks/logrotate/.kitchen.yml new file mode 100644 index 0000000..8ae0988 --- /dev/null +++ b/cookbooks/logrotate/.kitchen.yml @@ -0,0 +1,20 @@ +driver_plugin: vagrant +driver_config: + require_chef_omnibus: true + +platforms: + - name: ubuntu-12.04 + run_list: + - recipe[fake::prep] + - name: centos-6.5 + +suites: + - name: default + run_list: + - recipe[logrotate::default] + - name: definition + run_list: + - recipe[fake::definition] + - name: global + run_list: + - recipe[logrotate::global] diff --git a/cookbooks/logrotate/.rubocop.yml b/cookbooks/logrotate/.rubocop.yml new file mode 100644 index 0000000..3e61476 --- /dev/null +++ b/cookbooks/logrotate/.rubocop.yml @@ -0,0 +1,4 @@ +AllCops: + Exclude: + - vendor/** + - .kitchen/** \ No newline at end of file diff --git a/cookbooks/logrotate/.travis.yml b/cookbooks/logrotate/.travis.yml new file mode 100644 index 0000000..3b392bf --- /dev/null +++ b/cookbooks/logrotate/.travis.yml @@ -0,0 +1,6 @@ +rvm: + - 2.0.0 +script: + - bundle exec foodcritic -f any . --tags ~FC015 + - bundle exec rspec --color --format progress + - bundle exec rubocop -l diff --git a/cookbooks/logrotate/CHANGELOG.md b/cookbooks/logrotate/CHANGELOG.md new file mode 100644 index 0000000..b3fe95b --- /dev/null +++ b/cookbooks/logrotate/CHANGELOG.md @@ -0,0 +1,108 @@ +logrotate Cookbook CHANGELOG +============================ +This file is used to list changes made in each version of the +logrotate cookbook. + +v1.8.0 +------ + +### Resolved Bugs + +- `su` parameter now supported in global config. + +### Improvements + +- firstaction and lastaction attributes documented in the README +- rotate attribute documented in the README +- Use hash-rocket syntax in rspec matcher to maintain 1.9 support. + +v1.7.0 +------ + +### Bugs + +- Use `raise` rather than Application.fatal! to prevent killing a + daemonized chef-client + +### Improvements + +- Chefspec matcher for logrotate_app definition +- Support the following options: compressoptions, maxage, + shred/shredcycles, extension, tabooext +- Add Solaris support + + +v1.6.0 +------ + +### Bugs + +- Fix documentation error + +### Improvements + +- Support for options "compresscmd", "uncompresscmd", "compressext" +- Allow nodateext as parameter for logrotate_app definition +- Move to chefspec ~> 3.0 + +v1.5.0 +------ + +### Bugs +- Fix missing end tag in template +- Don't re-initialize constants. +- Fix rubocop finding + +### Improvements +- [COOK-3911] Allow to use maxsize parameter. +- [COOK-4000] Allow to use dateyesterday option. +- [COOK-4024] Allow to use su parameter. +- [COOK-4175] Allows use of the dateformat parameter. +- Loosen test-kitchen version constraint +- Add rvm files to gitignore + + +v1.4.0 +------ +### Bug +- **[COOK-3632](https://tickets.chef.io/browse/COOK-3632)** - Raise Exception when adding more than one invalid option +- **[COOK-3141](https://tickets.chef.io/browse/COOK-3141)** - Do not duplicate template entires for multiple paths +- **[COOK-3034](https://tickets.chef.io/browse/COOK-3034)** - Update logrotate_app params to accept arrays and strings + +### Improvement +- **[COOK-2646](https://tickets.chef.io/browse/COOK-2646)** - Add ability to choose file mode for logrotate template + +v1.3.0 +------ +### Improvement +- **[COOK-3341](https://tickets.chef.io/browse/COOK-3341)** - Add optional `frequency` and `rotate` params when defined globally +- **[COOK-3298](https://tickets.chef.io/browse/COOK-3298)** - Use `Array` instead of `respond_to?(:each)` +- **[COOK-3285](https://tickets.chef.io/browse/COOK-3285)** - Change `logrotate.d` config file mode to `0644` +- **[COOK-3250](https://tickets.chef.io/browse/COOK-3250)** - Add `minsize` + +### Bug +- **[COOK-3274](https://tickets.chef.io/browse/COOK-3274)** - Fix README typo that suggested the opposite action + +### New Feature +- **[COOK-2923](https://tickets.chef.io/browse/COOK-2923)** - Add `olddir` option +- **[COOK-1651](https://tickets.chef.io/browse/COOK-1651)** - Add `dateext` ability + +v1.2.2 +----- +### Bug +- [COOK-2872]: Add firstaction/lastaction ability to logrotate +- [COOK-2908]: Argument error in `logrotate_app` definition + +v1.2.0 +----- +- [COOK-2401] - Add the ability to manage the global logrotate configuration + +v1.1.0 +----- +- [COOK-2218] - Logrotate size parameter + +v1.0.2 +----- +- [COOK-1027] - Add support for pre-/post-rotate commands +- [COOK-1338] - Update log rotate for more flexibility of rotate options +- [COOK-1598] - "Create" isn't a mandatory option diff --git a/cookbooks/logrotate/CONTRIBUTING.md b/cookbooks/logrotate/CONTRIBUTING.md new file mode 100644 index 0000000..85e6c26 --- /dev/null +++ b/cookbooks/logrotate/CONTRIBUTING.md @@ -0,0 +1,16 @@ +## Contribution Guidelines + +- Please submit improvements and bug fixes via Github pull requests or + by sending an email to steve@chef.io in git's format-patch + format. + +- All patches should have well-written commit message. The first line + should summarize the change while the rest of the commit message + should explain the reason the change is needed. + +- Please ensure all tests and lint checking pass before submitting + pull requests. + +## Testing + +Please read TESTING.md for details on testing this cookbook. diff --git a/cookbooks/logrotate/Gemfile b/cookbooks/logrotate/Gemfile new file mode 100644 index 0000000..5857ea6 --- /dev/null +++ b/cookbooks/logrotate/Gemfile @@ -0,0 +1,9 @@ +source 'https://rubygems.org' +gem 'chefspec', '~> 4.0' +gem 'foodcritic', '~> 4.0' +gem 'rubocop', '~> 0.12' + +group :integration do + gem 'test-kitchen', '~> 1.0' + gem 'kitchen-vagrant', '~> 0.11' +end diff --git a/cookbooks/logrotate/Gemfile.lock b/cookbooks/logrotate/Gemfile.lock new file mode 100644 index 0000000..bdefc51 --- /dev/null +++ b/cookbooks/logrotate/Gemfile.lock @@ -0,0 +1,150 @@ +GEM + remote: https://rubygems.org/ + specs: + ast (2.0.0) + astrolabe (1.3.0) + parser (>= 2.2.0.pre.3, < 3.0) + chef (12.0.3) + chef-zero (~> 3.2) + diff-lcs (~> 1.2, >= 1.2.4) + erubis (~> 2.7) + ffi-yajl (~> 1.2) + highline (~> 1.6, >= 1.6.9) + mixlib-authentication (~> 1.3) + mixlib-cli (~> 1.4) + mixlib-config (~> 2.0) + mixlib-log (~> 1.3) + mixlib-shellout (>= 2.0.0.rc.0, < 3.0) + net-ssh (~> 2.6) + net-ssh-multi (~> 1.1) + ohai (~> 8.0) + plist (~> 3.1.0) + pry (~> 0.9) + chef-zero (3.2.1) + ffi-yajl (~> 1.1) + hashie (~> 2.0) + mixlib-log (~> 1.3) + rack + uuidtools (~> 2.1) + chefspec (4.2.0) + chef (>= 11.14) + fauxhai (~> 2.0) + rspec (~> 3.0) + coderay (1.1.0) + diff-lcs (1.2.5) + erubis (2.7.0) + fauxhai (2.3.0) + net-ssh + ohai + ffi (1.9.6) + ffi-yajl (1.4.0) + ffi (~> 1.5) + libyajl2 (~> 1.2) + foodcritic (4.0.0) + erubis + gherkin (~> 2.11) + nokogiri (~> 1.5) + rake + rufus-lru (~> 1.0) + treetop (~> 1.4) + yajl-ruby (~> 1.1) + gherkin (2.12.2) + multi_json (~> 1.3) + hashie (2.1.2) + highline (1.7.1) + ipaddress (0.8.0) + kitchen-vagrant (0.15.0) + test-kitchen (~> 1.0) + libyajl2 (1.2.0) + method_source (0.8.2) + mime-types (2.4.3) + mini_portile (0.6.2) + mixlib-authentication (1.3.0) + mixlib-log + mixlib-cli (1.5.0) + mixlib-config (2.1.0) + mixlib-log (1.6.0) + mixlib-shellout (2.0.1) + multi_json (1.10.1) + net-dhcp (1.3.2) + net-scp (1.2.1) + net-ssh (>= 2.6.5) + net-ssh (2.9.2) + net-ssh-gateway (1.2.0) + net-ssh (>= 2.6.5) + net-ssh-multi (1.2.0) + net-ssh (>= 2.6.5) + net-ssh-gateway (>= 1.2.0) + nokogiri (1.6.6.2) + mini_portile (~> 0.6.0) + ohai (8.1.1) + ffi (~> 1.9) + ffi-yajl (~> 1.1) + ipaddress + mime-types (~> 2.0) + mixlib-cli + mixlib-config (~> 2.0) + mixlib-log + mixlib-shellout (~> 2.0) + net-dhcp + rake (~> 10.1) + systemu (~> 2.6.4) + wmi-lite (~> 1.0) + parser (2.2.0.3) + ast (>= 1.1, < 3.0) + plist (3.1.0) + polyglot (0.3.5) + powerpack (0.1.0) + pry (0.10.1) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) + rack (1.6.0) + rainbow (2.0.0) + rake (10.4.2) + rspec (3.2.0) + rspec-core (~> 3.2.0) + rspec-expectations (~> 3.2.0) + rspec-mocks (~> 3.2.0) + rspec-core (3.2.0) + rspec-support (~> 3.2.0) + rspec-expectations (3.2.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.2.0) + rspec-mocks (3.2.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.2.0) + rspec-support (3.2.1) + rubocop (0.29.1) + astrolabe (~> 1.3) + parser (>= 2.2.0.1, < 3.0) + powerpack (~> 0.1) + rainbow (>= 1.99.1, < 3.0) + ruby-progressbar (~> 1.4) + ruby-progressbar (1.7.1) + rufus-lru (1.0.5) + safe_yaml (1.0.4) + slop (3.6.0) + systemu (2.6.4) + test-kitchen (1.3.1) + mixlib-shellout (>= 1.2, < 3.0) + net-scp (~> 1.1) + net-ssh (~> 2.7) + safe_yaml (~> 1.0) + thor (~> 0.18) + thor (0.19.1) + treetop (1.5.3) + polyglot (~> 0.3) + uuidtools (2.1.5) + wmi-lite (1.0.0) + yajl-ruby (1.2.1) + +PLATFORMS + ruby + +DEPENDENCIES + chefspec (~> 4.0) + foodcritic (~> 4.0) + kitchen-vagrant (~> 0.11) + rubocop (~> 0.12) + test-kitchen (~> 1.0) diff --git a/cookbooks/logrotate/LICENSE b/cookbooks/logrotate/LICENSE new file mode 100644 index 0000000..11069ed --- /dev/null +++ b/cookbooks/logrotate/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +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. diff --git a/cookbooks/logrotate/README.md b/cookbooks/logrotate/README.md new file mode 100644 index 0000000..62e1d4f --- /dev/null +++ b/cookbooks/logrotate/README.md @@ -0,0 +1,171 @@ +logrotate Cookbook +================== +[![Build Status](https://secure.travis-ci.org/stevendanna/logrotate.png?branch=master)](http://travis-ci.org/stevendanna/logrotate) + +Manages the logrotate package and provides a definition to manage application specific logrotate configuration. + + +Requirements +------------ +Should work on any platform that includes a 'logrotate' package and writes logrotate configuration to /etc/logrotate.d. Tested on Ubuntu, Debian and Red Hat/CentOS. + + +Recipes +------- +### global +Generates and controls a global `/etc/logrotate.conf` file that will include additional files generated by the `logrotate_app` definition (see below). The contents of the configuration file is controlled through node attributes under `node['logrotate']['global']`. The default attributes are based on the configuration from the Ubuntu logrotate package. + +To define a valueless directive (e.g. `compress`, `copy`) simply add an attribute named for the directive with a truthy value : + +```ruby +node['logrotate']['global']['compress'] = 'any value here' +``` + +Note that defining a valueless directive with a falsey value will not make it false, but will remove it: + +```ruby +# Removes a defaulted 'compress' directive; does not add a 'nocompress' directive. +node.override['logrotate']['global']['compress'] = false +``` + +To fully override a booleanish directive like `compress`, you should probably remove the positive form and add the negative form: + +```ruby +node.override['logrotate']['global']['compress'] = false +node.override['logrotate']['global']['nocompress'] = true +``` + +The same is true of frequency directives; to be certain the frequency directive you want is included in the global configuration, you should override the ones you don't want as false: + +```ruby +%w[ daily weekly yearly ].each do |freq| + node.override['logrotate']['global'][freq] = false +end +node.override['logrotate']['global']['monthly'] = true +``` + +To define a parameter with a value (e.g. `create`, `mail`) add an attribute with the desired value: + +```ruby +node['logrotate']['global']['create'] = '0644 root adm' +``` + +To define a path stanza in the global configuration (generally unneeded because of the `logrotate_app` definition) just add an attribute with the path as the name and a hash containing directives and parameters as described above: + +```ruby +node['logrotate']['global']['/var/log/wtmp'] = { + 'missingok' => true, + 'monthly' => true, + 'create' => '0660 root utmp', + 'rotate' => 1 +} +``` + +`firstaction`, `prerotate`, `postrotate`, and `lastaction` scripts can be defined either as arrays of the lines to put in the script or multiline strings: + +```ruby +node['logrotate']['global']['/var/log/foo/*.log'] = { + 'missingok' => true, + 'monthly' => true, + 'create' => '0660 root adm', + 'rotate' => 1, + 'prerotate' => ['service foo start_rotate', 'logger started foo service log rotation'], + 'postrotate' => <<-EOF + service foo end_rotate + logger completed foo service log rotation + EOF +} +``` + + +Definitions +----------- +### logrotate_app +This definition can be used to drop off customized logrotate config files on a per application basis. + +The definition takes the following params: + +- `path`: specifies a single path (string) or multiple paths (array) that should have logrotation stanzas created in the config file. No default, this must be specified. +- `enable`: true/false, if true it will create the template in /etc/logrotate.d. +- `frequency`: sets the frequency for rotation. Default value is 'weekly'. Valid values are: daily, weekly, monthly, yearly, see the logrotate man page for more information. +- `dateformat`: specifies date extension with %Y, %m, %d, and %s. The default value is -%Y%m%d. +- `size`: Log files are rotated when they grow bigger than size bytes. +- `maxsize`: Log files are rotated when they grow bigger than size bytes even before the additionally specified time interval. +- `su`: Rotate log files set under this user and group instead of using default user/group. +- `template`: sets the template source, default is "logrotate.erb". +- `template_mode`: the mode to create the logrotate template with (default "0440") +- `template_owner`: the owner of the logrotate template (default "root") +- `template_group`: the group of the logrotate template (default "root") +- `cookbook`: select the template source from the specified cookbook. By default it will use the template from the logrotate cookbook. +- `create`: creation parameters for the logrotate "create" config, follows the form "mode owner group". This is an optional parameter, and is nil by default. +- `firstaction`: lines to be executed once before all log files that match the wildcarded pattern are rotated, before pre-rotate script is run and only if at least one log will actually be rotated +- `postrotate`: lines to be executed after the log file is rotated +- `prerotate`: lines to be executed before the log file is rotated +- `lastaction`: lines to be executed once after all log files that match the wildcarded pattern are rotated, after postrotate script is run and only if at least one log is rotated +- `rotate`: Log files are rotated this many times before being removed or mailed. +- `sharedscripts`: if true, the sharedscripts options is specified which makes sure prescript and postscript commands are run only once (even if multiple files match the path) + + +Usage +----- +The default recipe will ensure logrotate is always up to date. + +To create application specific logrotate configs, use the `logrotate_app` definition. For example, to rotate logs for a tomcat application named myapp that writes its log file to `/var/log/tomcat/myapp.log`: + +```ruby +logrotate_app 'tomcat-myapp' do + cookbook 'logrotate' + path '/var/log/tomcat/myapp.log' + frequency 'daily' + rotate 30 + create '644 root adm' +end +``` + +To rotate multiple logfile paths, specify the path as an array: + +```ruby +logrotate_app 'tomcat-myapp' do + cookbook 'logrotate' + path ['/var/log/tomcat/myapp.log', '/opt/local/tomcat/catalina.out'] + frequency 'daily' + create '644 root adm' + rotate 7 +end +``` + +To specify which logrotate options, specify the options as an array: + +```ruby +logrotate_app 'tomcat-myapp' do + cookbook 'logrotate' + path '/var/log/tomcat/myapp.log' + options ['missingok', 'delaycompress', 'notifempty'] + frequency 'daily' + rotate 30 + create '644 root adm' +end +``` + + +License & Authors +----------------- +- Author:: Scott M. Likens () +- Author:: Joshua Timberman () + +```text +Copyright 2009, Scott M. Likens +Copyright 2011-2012, Chef Software, Inc. + +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. +``` diff --git a/cookbooks/logrotate/TESTING.md b/cookbooks/logrotate/TESTING.md new file mode 100644 index 0000000..0484b9f --- /dev/null +++ b/cookbooks/logrotate/TESTING.md @@ -0,0 +1,49 @@ +This cookbook uses a variety of testing components: + +- Unit tests: [ChefSpec](https://github.com/acrmp/chefspec) +- Integration tests: [Test Kitchen](https://github.com/chef/test-kitchen) +- Chef Style lints: [Foodcritic](https://github.com/acrmp/foodcritic) +- Ruby Style lints: [Rubocop](https://github.com/bbatsov/rubocop) + + +Prerequisites +------------- +To develop on this cookbook, you must have a sane Ruby 1.9+ environment. Given the nature of this installation process (and it's variance across multiple operating systems), we will leave this installation process to the user. + +You must also have `bundler` installed: + + $ gem install bundler + +You must also have Vagrant and VirtualBox installed: + +- [Vagrant](https://vagrantup.com) +- [VirtualBox](https://virtualbox.org) + +Once installed, you must install the `vagrant-berkshelf` plugin: + + $ vagrant plugin install vagrant-berkshelf + + +Development +----------- +1. Clone the git repository from GitHub: + + $ git clone git@github.com:stevendanna/logrotate.git + +2. Install the dependencies using bundler: + + $ bundle install + +3. Create a branch for your changes: + + $ git checkout -b my_bug_fix + +4. Make any changes +5. Write tests to support those changes. It is highly recommended you write both unit and integration tests. +6. Run the tests: + - `bundle exec rspec` + - `bundle exec foodcritic .` + - `bundle exec rubocop -l ` + - `bundle exec kitchen test` + +7. Assuming the tests pass, open a Pull Request on GitHub diff --git a/cookbooks/logrotate/attributes/default.rb b/cookbooks/logrotate/attributes/default.rb new file mode 100644 index 0000000..70f86fd --- /dev/null +++ b/cookbooks/logrotate/attributes/default.rb @@ -0,0 +1,38 @@ +# +# Cookbook Name:: logrotate +# Attribute:: default +# +# Copyright 2013, Chef +# +# 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. +# + +default['logrotate']['global'] = { + 'weekly' => true, + 'rotate' => 4, + 'create' => '', + + '/var/log/wtmp' => { + 'missingok' => true, + 'monthly' => true, + 'create' => '0664 root utmp', + 'rotate' => 1 + }, + + '/var/log/btmp' => { + 'missingok' => true, + 'monthly' => true, + 'create' => '0660 root utmp', + 'rotate' => 1 + } +} diff --git a/cookbooks/logrotate/definitions/logrotate_app.rb b/cookbooks/logrotate/definitions/logrotate_app.rb new file mode 100644 index 0000000..133a601 --- /dev/null +++ b/cookbooks/logrotate/definitions/logrotate_app.rb @@ -0,0 +1,77 @@ +# +# Cookbook Name:: logrotate +# Definition:: logrotate_instance +# +# Copyright 2009, Scott M. Likens +# +# 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. +# + +log_rotate_params = { + :enable => true, + :frequency => 'weekly', + :template => 'logrotate.erb', + :cookbook => 'logrotate', + :template_mode => '0440', + :template_owner => 'root', + :template_group => 'root', + :postrotate => nil, + :prerotate => nil, + :firstaction => nil, + :lastaction => nil, + :sharedscripts => false +} + +define(:logrotate_app, log_rotate_params) do + include_recipe 'logrotate::default' + + options_tmp = params[:options] ||= %w(missingok compress delaycompress copytruncate notifempty) + options = options_tmp.respond_to?(:each) ? options_tmp : options_tmp.split + options << 'sharedscripts' if params[:sharedscripts] + + if params[:enable] + invalid_options = options - CookbookLogrotate::DIRECTIVES + + unless invalid_options.empty? + Chef::Log.error("Invalid option(s) passed to logrotate: #{invalid_options.join(', ')}") + raise + end + + logrotate_config = { + :path => Array(params[:path]).map { |path| path.to_s.inspect }.join(' '), + :frequency => params[:frequency], + :options => options + } + CookbookLogrotate::VALUES.each do |opt_name| + logrotate_config[opt_name.to_sym] = params[opt_name.to_sym] + end + + CookbookLogrotate::SCRIPTS.each do |script_name| + logrotate_config[script_name.to_sym] = Array(params[script_name.to_sym]).join("\n") + end + + template "/etc/logrotate.d/#{params[:name]}" do + source params[:template] + cookbook params[:cookbook] + mode params[:template_mode] + owner params[:template_owner] + group params[:template_group] + backup false + variables logrotate_config + end + else + file "/etc/logrotate.d/#{params[:name]}" do + action :delete + end + end +end diff --git a/cookbooks/logrotate/libraries/logrotate_config.rb b/cookbooks/logrotate/libraries/logrotate_config.rb new file mode 100644 index 0000000..479a291 --- /dev/null +++ b/cookbooks/logrotate/libraries/logrotate_config.rb @@ -0,0 +1,88 @@ +# +# Cookbook Name:: logrotate +# Library:: CookbookLogrotate +# +# Copyright 2013, Chef +# +# 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. +# + +# Helper module for Logrotate configuration module CookbookLogrotate +module CookbookLogrotate + DIRECTIVES = %w(compress copy copytruncate daily dateext + dateyesterday delaycompress hourly ifempty mailfirst maillast + missingok monthly nocompress nocopy nocopytruncate nocreate + nodelaycompress nodateext nomail nomissingok noolddir + nosharedscripts noshred notifempty sharedscripts shred weekly + yearly) unless const_defined?(:DIRECTIVES) + + VALUES = %w(compresscmd uncompresscmd compressext compressoptions + create dateformat include mail extension maxage minsize maxsize + rotate size shredcycles start tabooext su olddir) unless const_defined?(:VALUES) + + SCRIPTS = %w(firstaction prerotate postrotate lastaction preremove) unless const_defined?(:SCRIPTS) + + DIRECTIVES_AND_VALUES = DIRECTIVES + VALUES unless const_defined?(:DIRECTIVES_AND_VALUES) + + # Helper class for creating configurations + class LogrotateConfiguration + attr_reader :directives, :values, :paths + + class << self + def from_hash(hash) + new(hash) + end + + def directives_from(hash) + hash.select { |k, v| DIRECTIVES.include?(k) && v }.keys + end + + def values_from(hash) + hash.select { |k| VALUES.include?(k) } + end + + def paths_from(hash) + hash.select { |k| !(DIRECTIVES_AND_VALUES.include?(k)) }.reduce({}) do | accum_paths, (path, config) | + accum_paths[path] = { + 'directives' => directives_from(config), + 'values' => values_from(config), + 'scripts' => scripts_from(config) + } + + accum_paths + end + end + + def scripts_from(hash) + defined_scripts = hash.select { |k| SCRIPTS.include?(k) } + defined_scripts.reduce({}) do | accum_scripts, (script, lines) | + if lines.respond_to?(:join) + accum_scripts[script] = lines.join("\n") + else + accum_scripts[script] = lines + end + + accum_scripts + end + end + end + + private + + def initialize(hash) + @directives = LogrotateConfiguration.directives_from(hash) + @values = LogrotateConfiguration.values_from(hash) + @paths = LogrotateConfiguration.paths_from(hash) + end + end +end diff --git a/cookbooks/logrotate/libraries/matchers.rb b/cookbooks/logrotate/libraries/matchers.rb new file mode 100644 index 0000000..f74034a --- /dev/null +++ b/cookbooks/logrotate/libraries/matchers.rb @@ -0,0 +1,154 @@ +if defined?(ChefSpec) + def enable_logrotate_app(name) + LogrotateAppMatcher.new(name) + end + + class LogrotateAppMatcher + def initialize(name) + @name = name + end + + def with(parameters = {}) + params.merge!(parameters) + self + end + + def at_compile_time + raise ArgumentError, 'Cannot specify both .at_converge_time and .at_compile_time!' if @converge_time + @compile_time = true + self + end + + def at_converge_time + raise ArgumentError, 'Cannot specify both .at_compile_time and .at_converge_time!' if @compile_time + @converge_time = true + self + end + + # + # Allow users to specify fancy #with matchers. + # + def method_missing(m, *args, &block) + if m.to_s =~ /^with_(.+)$/ + with($1.to_sym => args.first) + self + else + super + end + end + + def description + %Q{"enable" #{@name} "logrotate_app"} + end + + def matches?(runner) + @runner = runner + + if resource + resource.performed_action?('create') && unmatched_parameters.empty? && correct_phase? + else + false + end + end + + def failure_message + if resource + if resource.performed_action?('create') + if unmatched_parameters.empty? + if @compile_time + %Q{expected "#{resource}" to be run at compile time} + else + %Q{expected "#{resource}" to be run at converge time} + end + else + %Q{expected "#{resource}" to have parameters:} \ + "\n\n" \ + " " + unmatched_parameters.collect { |parameter, h| + "#{parameter} #{h[:expected].inspect}, was #{h[:actual].inspect}" + }.join("\n ") + end + else + %Q{expected "#{resource}" actions #{resource.performed_actions.inspect}} \ + " to include : create" + end + else + %Q{expected "logrotate_app[#{@name}] with"} \ + " enable : true to be in Chef run. Other" \ + " #{@name} resources:" \ + "\n\n" \ + " " + similar_resources.map(&:to_s).join("\n ") + "\n " + end + end + + def failure_message_when_negated + if resource + message = %Q{expected "#{resource}" actions #{resource.performed_actions.inspect} to not exist} + else + message = %Q{expected "#{resource}" to not exist} + end + + message << " at compile time" if @compile_time + message << " at converge time" if @converge_time + message + end + + private + def unmatched_parameters + return @_unmatched_parameters if @_unmatched_parameters + + @_unmatched_parameters = {} + + params.each do |parameter, expected| + unless matches_parameter?(parameter, expected) + @_unmatched_parameters[parameter] = { + :expected => expected, + :actual => safe_send(parameter), + } + end + end + + @_unmatched_parameters + end + + def matches_parameter?(parameter, expected) + # Chef 11+ stores the source parameter internally as an Array + # + case parameter + when :cookbook + expected === safe_send(parameter) + when :path + Array(expected == safe_send('variables')[parameter]) + else + expected == safe_send('variables')[parameter] + end + end + + def correct_phase? + if @compile_time + resource.performed_action('create')[:compile_time] + elsif @converge_time + resource.performed_action('create')[:converge_time] + else + true + end + end + + def safe_send(parameter) + resource.send(parameter) + rescue NoMethodError + nil + end + + def similar_resources + @_similar_resources ||= @runner.find_resources('template') + end + + def resource + @_resource ||= @runner.find_resource('template', "/etc/logrotate.d/#{@name}") + end + + def params + @_params ||= {} + end + end +end diff --git a/cookbooks/logrotate/metadata.json b/cookbooks/logrotate/metadata.json new file mode 100644 index 0000000..3bf042e --- /dev/null +++ b/cookbooks/logrotate/metadata.json @@ -0,0 +1,48 @@ +{ + "name": "logrotate", + "description": "Installs logrotate package and provides a definition for logrotate configs", + "long_description": "Installs the logrotate package, manages /etc/logrotate.conf, and provides a logrotate_app definition.", + "maintainer": "Steven Danna", + "maintainer_email": "steve@chef.io", + "license": "Apache 2.0", + "platforms": { + "amazon": ">= 0.0.0", + "centos": ">= 0.0.0", + "debian": ">= 0.0.0", + "fedora": ">= 0.0.0", + "redhat": ">= 0.0.0", + "scientific": ">= 0.0.0", + "solaris2": ">= 0.0.0", + "ubuntu": ">= 0.0.0" + }, + "dependencies": { + + }, + "recommendations": { + + }, + "suggestions": { + + }, + "conflicting": { + + }, + "providing": { + "logrotate_app": ">= 0.0.0" + }, + "replacing": { + + }, + "attributes": { + + }, + "groupings": { + + }, + "recipes": { + "logrotate": "Installs logrotate package" + }, + "version": "1.9.2", + "source_url": "", + "issues_url": "" +} diff --git a/cookbooks/logrotate/metadata.rb b/cookbooks/logrotate/metadata.rb new file mode 100644 index 0000000..dcdb9d5 --- /dev/null +++ b/cookbooks/logrotate/metadata.rb @@ -0,0 +1,14 @@ +name 'logrotate' +maintainer 'Steven Danna' +maintainer_email 'steve@chef.io' +license 'Apache 2.0' +description 'Installs logrotate package and provides a definition for logrotate configs' +long_description 'Installs the logrotate package, manages /etc/logrotate.conf, and provides a logrotate_app definition.' +version '1.9.2' + +recipe 'logrotate', 'Installs logrotate package' +provides 'logrotate_app' + +%w{amazon centos debian fedora redhat scientific solaris2 ubuntu}.each do |platform| + supports platform +end diff --git a/cookbooks/logrotate/recipes/default.rb b/cookbooks/logrotate/recipes/default.rb new file mode 100644 index 0000000..3486271 --- /dev/null +++ b/cookbooks/logrotate/recipes/default.rb @@ -0,0 +1,35 @@ +# +# Cookbook Name:: logrotate +# Recipe:: default +# +# Copyright 2009-2013, Chef Software, Inc. +# +# 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. +# + +package 'logrotate' + +directory "/etc/logrotate.d" do + owner "root" + group "root" + mode "0755" + action :create +end + +if platform? "solaris2" # ~FC023 style preference + cron "logrotate" do + minute "35" + hour "7" + command "/usr/sbin/logrotate /etc/logrotate.conf" + end +end diff --git a/cookbooks/logrotate/recipes/global.rb b/cookbooks/logrotate/recipes/global.rb new file mode 100644 index 0000000..2180c92 --- /dev/null +++ b/cookbooks/logrotate/recipes/global.rb @@ -0,0 +1,30 @@ +# +# Cookbook Name:: logrotate +# Recipe:: default +# +# Copyright 2009-2013, Chef Software, Inc. +# +# 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. +# + +include_recipe 'logrotate::default' + +parsed_configuration = CookbookLogrotate::LogrotateConfiguration.from_hash(node['logrotate']['global'].to_hash) + +template '/etc/logrotate.conf' do + source 'logrotate-global.erb' + mode '0644' + variables( + :configuration => parsed_configuration + ) +end diff --git a/cookbooks/logrotate/templates/default/logrotate-global.erb b/cookbooks/logrotate/templates/default/logrotate-global.erb new file mode 100644 index 0000000..96ba504 --- /dev/null +++ b/cookbooks/logrotate/templates/default/logrotate-global.erb @@ -0,0 +1,29 @@ +# This file was generated by Chef for <%= node['fqdn'] %>. +# Do not modify this file by hand! + +<% @configuration.directives.each do |d| -%> +<%= d %> +<% end -%> + +<% @configuration.values.each do |k, v| -%> +<%= k %> <%= v %> +<% end -%> + +include /etc/logrotate.d + +<% @configuration.paths.each do |path, path_config| -%> +<%= path %> { + <% path_config['directives'].each do |d|-%> + <%= d %> + <% end -%> + <% path_config['values'].each do | k, v | -%> + <%= k %> <%= v %> + <% end -%> + <% path_config['scripts'].each do | scripttype, body | -%> + <%= scripttype %> + <%= body %> + endscript + <% end -%> +} + +<% end -%> diff --git a/cookbooks/logrotate/templates/default/logrotate.erb b/cookbooks/logrotate/templates/default/logrotate.erb new file mode 100644 index 0000000..f8e8d8d --- /dev/null +++ b/cookbooks/logrotate/templates/default/logrotate.erb @@ -0,0 +1,23 @@ +# This file was generated by Chef for <%= node['fqdn'] %>. +# Do not modify this file by hand! + +<%= @path %> { +<%- if @frequency %> + <%= @frequency %> +<%- end %> +<%- CookbookLogrotate::VALUES.each do |opt_name| %> + <% if instance_variable_get("@#{opt_name}") %> + <%= "#{opt_name} #{instance_variable_get("@#{opt_name}")}" %> + <%- end %> +<%- end %> +<% @options.each do |o| -%> + <%= o %> +<% end -%> +<%- CookbookLogrotate::SCRIPTS.each do |script_name| %> + <% unless instance_variable_get("@#{script_name}").empty? %> + <%= script_name %> + <%= instance_variable_get("@#{script_name}") %> + endscript + <%- end %> +<%- end %> +}