diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..781a4a8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +tmp/* +.rake_test_cache diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..11069ed --- /dev/null +++ b/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/NOTICE b/NOTICE new file mode 100644 index 0000000..37657ea --- /dev/null +++ b/NOTICE @@ -0,0 +1,15 @@ +========================= +Opscode Cookbooks Notices +========================= + +Developed at Opscode (http://www.opscode.com). + +Contributors and Copyright holders: + + * Copyright 2008-2009, Opscode + * Copyright 2008-2009, Adam Jacob + * Copyright 2008-2009, Joshua Timberman + * Copyright 2009, Joe Williams + * Copyright 2009, Joshua Sierles + * Copyright 2009, Matthew Kent + \ No newline at end of file diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..c3ad879 --- /dev/null +++ b/Rakefile @@ -0,0 +1,46 @@ +require 'rubygems' +require 'chef' +require 'json' + + +TOPDIR = File.expand_path(File.join(File.dirname(__FILE__), "..")) +TEST_CACHE = File.expand_path(File.join(TOPDIR, ".rake_test_cache")) +COMPANY_NAME = "Opscode, Inc." +SSL_EMAIL_ADDRESS = "cookbooks@opscode.com" +NEW_COOKBOOK_LICENSE = :apachev2 + +load 'chef/tasks/chef_repo.rake' +task :default => [ :test ] + +desc "Build a bootstrap.tar.gz" +task :build_bootstrap do + bootstrap_files = Rake::FileList.new + %w(apache2 runit couchdb stompserver chef passenger ruby packages).each do |cookbook| + bootstrap_files.include "#{cookbook}/**/*" + end + + tmp_dir = "tmp" + cookbooks_dir = File.join(tmp_dir, "cookbooks") + rm_rf tmp_dir + mkdir_p cookbooks_dir + bootstrap_files.each do |fn| + f = File.join(cookbooks_dir, fn) + fdir = File.dirname(f) + mkdir_p(fdir) if !File.exist?(fdir) + if File.directory?(fn) + mkdir_p(f) + else + rm_f f + safe_ln(fn, f) + end + end + + chdir(tmp_dir) do + sh %{tar zcvf bootstrap.tar.gz cookbooks} + end +end + +# remove unnecessary tasks +%w{update install roles ssl_cert}.each do |t| + Rake.application.instance_variable_get('@tasks').delete(t.to_s) +end diff --git a/activemq/README.rdoc b/activemq/README.rdoc new file mode 100644 index 0000000..6156892 --- /dev/null +++ b/activemq/README.rdoc @@ -0,0 +1,39 @@ += DESCRIPTION: + +Installs activemq and sets up a runit service. + += REQUIREMENTS: + +Tested on Ubuntu 9.04. + +Opscode cookbooks: + +* java +* runit + += ATTRIBUTES: + +* activemq[:mirror] - download URL up to the apache/activemq/apache-activemq directory. +* activemq[:version] - version to install. + += USAGE: + +Include the default recipe on systems where you want to run activemq. At this time the cookbook doesn't use any custom configuration for activemq. + += LICENSE AND AUTHOR: + +Author:: Joshua Timberman () + +Copyright:: 2009, Opscode, 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/activemq/attributes/activemq.rb b/activemq/attributes/activemq.rb new file mode 100644 index 0000000..c319462 --- /dev/null +++ b/activemq/attributes/activemq.rb @@ -0,0 +1,21 @@ +# +# Cookbook Name:: activemq +# Attributes:: activemq +# +# Copyright 2009, Opscode, 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. +# + +set_unless[:activemq][:mirror] = "http://mirrors.ibiblio.org/pub/mirrors" +set_unless[:activemq][:version] = "5.3.0" diff --git a/activemq/metadata.json b/activemq/metadata.json new file mode 100644 index 0000000..22ef9ed --- /dev/null +++ b/activemq/metadata.json @@ -0,0 +1,51 @@ +{ + "dependencies": { + "java": [ + + ], + "runit": [ + + ] + }, + "maintainer_email": "cookbooks@opscode.com", + "conflicting": { + + }, + "description": "Installs activemq and sets it up as a runit service", + "recipes": { + "activemq": "" + }, + "providing": { + "activemq": [ + + ] + }, + "platforms": { + "ubuntu": [ + + ], + "debian": [ + + ] + }, + "version": "0.2.0", + "name": "activemq", + "replacing": { + + }, + "groupings": { + + }, + "long_description": "= DESCRIPTION:\n\nInstalls activemq and sets up a runit service.\n\n= REQUIREMENTS:\n\nTested on Ubuntu 9.04.\n\nOpscode cookbooks:\n\n* java\n* runit\n\n= ATTRIBUTES:\n\n* activemq[:mirror] - download URL up to the apache/activemq/apache-activemq directory.\n* activemq[:version] - version to install.\n\n= USAGE:\n\nInclude the default recipe on systems where you want to run activemq. At this time the cookbook doesn't use any custom configuration for activemq.\n\n= LICENSE AND AUTHOR:\n\nAuthor:: Joshua Timberman ()\n\nCopyright:: 2009, Opscode, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n", + "attributes": { + + }, + "recommendations": { + + }, + "license": "Apache 2.0", + "maintainer": "Opscode, Inc.", + "suggestions": { + + } +} \ No newline at end of file diff --git a/activemq/metadata.rb b/activemq/metadata.rb new file mode 100644 index 0000000..add2bfe --- /dev/null +++ b/activemq/metadata.rb @@ -0,0 +1,14 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs activemq and sets it up as a runit service" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.2" + +%w{ubuntu debian}.each do |os| + supports os +end + +%w{java runit}.each do |cb| + depends cb +end diff --git a/activemq/recipes/default.rb b/activemq/recipes/default.rb new file mode 100644 index 0000000..b9aaff3 --- /dev/null +++ b/activemq/recipes/default.rb @@ -0,0 +1,42 @@ +# +# Cookbook Name:: activemq +# Recipe:: default +# +# Copyright 2009, Opscode, 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 "java" + +version = node[:activemq][:version] +mirror = node[:activemq][:mirror] + +unless File.exists?("/opt/apache-activemq-#{version}/bin/activemq") + remote_file "/tmp/apache-activemq-#{version}-bin.tar.gz" do + source "#{mirror}/apache/activemq/apache-activemq/#{version}/apache-activemq-#{version}-bin.tar.gz" + mode "0644" + end + + execute "tar zxf /tmp/apache-activemq-#{version}-bin.tar.gz" do + cwd "/opt" + end +end + +file "/opt/apache-activemq-#{version}/bin/activemq" do + owner "root" + group "root" + mode "0755" +end + +runit_service "activemq" diff --git a/activemq/templates/default/sv-activemq-log-run.erb b/activemq/templates/default/sv-activemq-log-run.erb new file mode 100644 index 0000000..a79a518 --- /dev/null +++ b/activemq/templates/default/sv-activemq-log-run.erb @@ -0,0 +1,2 @@ +#!/bin/sh +exec svlogd -tt ./main diff --git a/activemq/templates/default/sv-activemq-run.erb b/activemq/templates/default/sv-activemq-run.erb new file mode 100644 index 0000000..3982bbc --- /dev/null +++ b/activemq/templates/default/sv-activemq-run.erb @@ -0,0 +1,3 @@ +#!/bin/sh +exec 2>&1 +exec /opt/apache-activemq-<%= @node[:activemq][:version] %>/bin/activemq diff --git a/apache2/README.rdoc b/apache2/README.rdoc new file mode 100644 index 0000000..db31d20 --- /dev/null +++ b/apache2/README.rdoc @@ -0,0 +1,78 @@ += DESCRIPTION: + +Complete Debian/Ubuntu style Apache2 configuration. + += REQUIREMENTS: + +Debian or Ubuntu preferred. + +Red Hat/CentOS and Fedora can be used but will be converted to a Debian/Ubuntu style Apache as it's far easier to manage with chef. + += ATTRIBUTES: + +The file attributes/apache.rb contains the following attribute types: + +* platform specific locations and settings. +* general settings +* prefork attributes +* worker attributes + +General settings and prefork/worker attributes are tunable. + += USAGE: + +Include the apache2 recipe to install Apache2 and get 'sane' default settings. Configuration is modularized through Apache vhost sites a la Debian style configuration. + +For Red Hat, CentOS and Fedora you should first disable selinux as it's not supported (yet), then remove the stock httpd and all it's dependencies prior to attempting to use this recipe. Many packages in these distributions drop conflicting configs into conf.d, all of which haven't been accounted for yet. Starting from scratch will also make it far easier to debug. + +== Defines: + +* apache_module: sets up an Apache module. +* apache_conf: sets up a config file for an apache module. +* apache_site: sets up a vhost site. The conf file must be available. +* web_app: copies the template for a web app and enables it as a site via apache_site. + +== Web Apps: + +Various applications that can be set up with Apache as the front end, such as PHP, Django, Rails and others can use the web_app define to set up the template and the Apache site. The define is kind of dumb, so the template needs have the application implementation settings, since we don't know what your app is or what is needed from Apache. + +We only prototype one parameter for the web_app define, "template". This is used to specify the name of the template to use in the current cookbook. When you use web_app, you can set up any parameters you want to use in your template. They will get passed to the template through the params hash. For example, the sample web_app.conf.erb template in this cookbook makes use of these. + +* docroot +* server_name +* server_aliases + +These are available as @params[:docroot], @params[:server_name], @params[:server_aliases] within the template. + +If 'cookbook' and 'template' are not specified, the current cookbook's templates/default/web_app.conf.erb will be used. If this template is not suitable for your application, copy it to your cookbook and customize as needed. + +== God Monitor: + +There's a new recipe, apache2::god_monitor. You will need to make sure to include the 'god' recipe before using the apache2::god_monitor recipe in your cookbook. + +== OpenID Auth + +Installs the mod_auth_openid module from source. Specify an array of OpenIDs that are allowed to authenticate with the attribute apache[:allowed_openids]. Use the following in a vhost to protect with OpenID authentication: + + AuthOpenIDEnabled On + AuthOpenIDDBLocation /var/cache/apache2/mod_auth_openid.db + AuthOpenIDUserProgram /usr/local/bin/mod_auth_openid.rb + +Change the DBLocation as appropriate for your platform. You'll need to change the file in the recipe to match. The UserProgram is optional if you don't want to limit access by certain OpenIDs. + += LICENSE & AUTHOR: + +Author:: Joshua Timberman () +Copyright:: 2009, Opscode, 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/apache2/attributes/apache.rb b/apache2/attributes/apache.rb new file mode 100644 index 0000000..d6a8f76 --- /dev/null +++ b/apache2/attributes/apache.rb @@ -0,0 +1,77 @@ +# +# Cookbook Name:: apache2 +# Attributes:: apache +# +# Copyright 2008-2009, Opscode, 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. +# + +# Where the various parts of apache are +case platform +when "redhat","centos","fedora","suse" + set[:apache][:dir] = "/etc/httpd" + set[:apache][:log_dir] = "/var/log/httpd" + set[:apache][:user] = "apache" + set[:apache][:binary] = "/usr/sbin/httpd" + set[:apache][:icondir] = "/var/www/icons/" +when "debian","ubuntu" + set[:apache][:dir] = "/etc/apache2" + set[:apache][:log_dir] = "/var/log/apache2" + set[:apache][:user] = "www-data" + set[:apache][:binary] = "/usr/sbin/apache2" + set[:apache][:icondir] = "/usr/share/apache2/icons" +else + set[:apache][:dir] = "/etc/apache2" + set[:apache][:log_dir] = "/var/log/apache2" + set[:apache][:user] = "www-data" + set[:apache][:binary] = "/usr/sbin/apache2" + set[:apache][:icondir] = "/usr/share/apache2/icons" +end + +### +# These settings need the unless, since we want them to be tunable, +# and we don't want to override the tunings. +### + +# General settings +set_unless[:apache][:listen_ports] = [ "80","443" ] +set_unless[:apache][:contact] = "ops@example.com" +set_unless[:apache][:timeout] = 300 +set_unless[:apache][:keepalive] = "On" +set_unless[:apache][:keepaliverequests] = 100 +set_unless[:apache][:keepalivetimeout] = 5 + +# Security +set_unless[:apache][:servertokens] = "Prod" +set_unless[:apache][:serversignature] = "On" +set_unless[:apache][:traceenable] = "On" + +# mod_auth_openids +set_unless[:apache][:allowed_openids] = Array.new + +# Prefork Attributes +set_unless[:apache][:prefork][:startservers] = 16 +set_unless[:apache][:prefork][:minspareservers] = 16 +set_unless[:apache][:prefork][:maxspareservers] = 32 +set_unless[:apache][:prefork][:serverlimit] = 400 +set_unless[:apache][:prefork][:maxclients] = 400 +set_unless[:apache][:prefork][:maxrequestsperchild] = 10000 + +# Worker Attributes +set_unless[:apache][:worker][:startservers] = 4 +set_unless[:apache][:worker][:maxclients] = 1024 +set_unless[:apache][:worker][:minsparethreads] = 64 +set_unless[:apache][:worker][:maxsparethreads] = 192 +set_unless[:apache][:worker][:threadsperchild] = 64 +set_unless[:apache][:worker][:maxrequestsperchild] = 0 diff --git a/apache2/definitions/apache_conf.rb b/apache2/definitions/apache_conf.rb new file mode 100644 index 0000000..2439289 --- /dev/null +++ b/apache2/definitions/apache_conf.rb @@ -0,0 +1,25 @@ +# +# Cookbook Name:: apache2 +# Definition:: apache_conf +# +# Copyright 2008-2009, Opscode, 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. +# + +define :apache_conf do + template "#{node[:apache][:dir]}/mods-available/#{params[:name]}.conf" do + source "mods/#{params[:name]}.conf.erb" + notifies :restart, resources(:service => "apache2") + end +end diff --git a/apache2/definitions/apache_module.rb b/apache2/definitions/apache_module.rb new file mode 100644 index 0000000..2bd739e --- /dev/null +++ b/apache2/definitions/apache_module.rb @@ -0,0 +1,43 @@ +# +# Cookbook Name:: apache2 +# Definition:: apache_module +# +# Copyright 2008-2009, Opscode, 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. +# + +define :apache_module, :enable => true, :conf => false do + include_recipe "apache2" + + if params[:conf] + apache_conf params[:name] + end + + if params[:enable] + execute "a2enmod #{params[:name]}" do + command "/usr/sbin/a2enmod #{params[:name]}" + notifies :restart, resources(:service => "apache2") + not_if do (File.symlink?("#{node[:apache][:dir]}/mods-enabled/#{params[:name]}.load") and + ((File.exists?("#{node[:apache][:dir]}/mods-available/#{params[:name]}.conf"))? + (File.symlink?("#{node[:apache][:dir]}/mods-enabled/#{params[:name]}.conf")):(true))) + end + end + else + execute "a2dismod #{params[:name]}" do + command "/usr/sbin/a2dismod #{params[:name]}" + notifies :restart, resources(:service => "apache2") + only_if do File.symlink?("#{node[:apache][:dir]}/mods-enabled/#{params[:name]}.load") end + end + end +end diff --git a/apache2/definitions/apache_site.rb b/apache2/definitions/apache_site.rb new file mode 100644 index 0000000..7316e01 --- /dev/null +++ b/apache2/definitions/apache_site.rb @@ -0,0 +1,40 @@ +# +# Cookbook Name:: apache2 +# Definition:: apache_site +# +# Copyright 2008-2009, Opscode, 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. +# + +define :apache_site, :enable => true do + include_recipe "apache2" + + if params[:enable] + execute "a2ensite #{params[:name]}" do + command "/usr/sbin/a2ensite #{params[:name]}" + notifies :restart, resources(:service => "apache2") + not_if do + File.symlink?("#{node[:apache][:dir]}/sites-enabled/#{params[:name]}") or + File.symlink?("#{node[:apache][:dir]}/sites-enabled/000-#{params[:name]}") + end + only_if do File.exists?("#{node[:apache][:dir]}/sites-available/#{params[:name]}") end + end + else + execute "a2dissite #{params[:name]}" do + command "/usr/sbin/a2dissite #{params[:name]}" + notifies :restart, resources(:service => "apache2") + only_if do File.symlink?("#{node[:apache][:dir]}/sites-enabled/#{params[:name]}") end + end + end +end diff --git a/apache2/definitions/web_app.rb b/apache2/definitions/web_app.rb new file mode 100644 index 0000000..b532708 --- /dev/null +++ b/apache2/definitions/web_app.rb @@ -0,0 +1,49 @@ +# +# Cookbook Name:: apache2 +# Definition:: web_app +# +# Copyright 2008-2009, Opscode, 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. +# + +define :web_app, :template => "web_app.conf.erb" do + + application_name = params[:name] + + include_recipe "apache2" + include_recipe "apache2::mod_rewrite" + include_recipe "apache2::mod_deflate" + include_recipe "apache2::mod_headers" + + template "#{node[:apache][:dir]}/sites-available/#{application_name}.conf" do + source params[:template] + owner "root" + group "root" + mode 0644 + if params[:cookbook] + cookbook params[:cookbook] + end + variables( + :application_name => application_name, + :params => params + ) + if File.exists?("#{node[:apache][:dir]}/sites-enabled/#{application_name}.conf") + notifies :reload, resources(:service => "apache2"), :delayed + end + end + + apache_site "#{params[:name]}.conf" do + enable enable_setting + end +end diff --git a/apache2/files/default/apache2_module_conf_generate.pl b/apache2/files/default/apache2_module_conf_generate.pl new file mode 100644 index 0000000..83f849e --- /dev/null +++ b/apache2/files/default/apache2_module_conf_generate.pl @@ -0,0 +1,41 @@ +#!/usr/bin/perl + +=begin + +Generates Ubuntu style module.load files. + +./apache2_module_conf_generate.pl /usr/lib64/httpd/modules /etc/httpd/mods-available + +ARGV[0] is the apache modules directory, ARGV[1] is where you want 'em. + +=cut + +use File::Find; + +use strict; +use warnings; + +die "Must have '/path/to/modules' and '/path/to/modules.load'" + unless $ARGV[0] && $ARGV[1]; + +find( + { + wanted => sub { + return 1 if $File::Find::name !~ /\.so$/; + my $modfile = $_; + $modfile =~ /(lib|mod_)(.+)\.so$/; + my $modname = $2; + my $filename = "$ARGV[1]/$modname.load"; + unless ( -f $filename ) { + open( FILE, ">", $filename ) or die "Cannot open $filename"; + print FILE "LoadModule " . $modname . "_module $File::Find::name\n"; + close(FILE); + } + }, + follow => 1, + }, + $ARGV[0] +); + +exit 0; + diff --git a/apache2/metadata.json b/apache2/metadata.json new file mode 100644 index 0000000..ad20aee --- /dev/null +++ b/apache2/metadata.json @@ -0,0 +1,523 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs and configures all aspects of apache2 using Debian style symlinks with helper definitions", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "apache2::mod_python": "Apache module 'python'", + "apache2::mod_authn_file": "Apache module 'authn_file'", + "apache2::mod_dir": "Apache module 'dir' with config file", + "apache2::mod_php5": "Apache module 'php5'", + "apache2::mod_proxy_balancer": "Apache module 'proxy_balancer'", + "apache2::mod_dav": "Apache module 'dav'", + "apache2::mod_authz_groupfile": "Apache module 'authz_groupfile'", + "apache2::mod_auth_basic": "Apache module 'auth_basic'", + "apache2::mod_setenvif": "Apache module 'setenvif' with config file", + "apache2::mod_authz_user": "Apache module 'authz_user'", + "apache2::mod_deflate": "Apache module 'deflate' with config file", + "apache2::mod_ssl": "Apache module 'ssl' with config file, adds port 443 to listen_ports", + "apache2::mod_negotiation": "Apache module 'negotiation' with config file", + "apache2::mod_dav_svn": "Apache module 'dav_svn'", + "apache2::mod_authz_host": "Apache module 'authz_host'", + "apache2::mod_rewrite": "Apache module 'rewrite'", + "apache2::mod_cgi": "Apache module 'cgi'", + "apache2::mod_fcgid": "Apache module 'fcgid', package on ubuntu\/debian, rhel\/centos, compile source on suse; with config file", + "apache2::mod_auth_digest": "Apache module 'auth_digest'", + "apache2::mod_env": "Apache module 'env'", + "apache2::mod_headers": "Apache module 'headers'", + "apache2::mod_autoindex": "Apache module 'autoindex' with config file", + "apache2::mod_authnz_ldap": "Apache module 'authnz_ldap'", + "apache2::mod_proxy_connect": "Apache module 'proxy_connect'", + "apache2::mod_proxy": "Apache module 'proxy' with config file", + "apache2": "Main Apache configuration", + "apache2::mod_alias": "Apache module 'alias' with config file", + "apache2::mod_status": "Apache module 'status' with config file", + "apache2::mod_ldap": "Apache module 'ldap'", + "apache2::mod_authz_default": "Apache module 'authz_default'", + "apache2::mod_log_config": "Apache module 'log_config'", + "apache2::mod_expires": "Apache module 'expires'", + "apache2::god_monitor": "", + "apache2::mod_proxy_http": "Apache module 'proxy_http'", + "apache2::mod_auth_openid": "Apache module 'authopenid'", + "apache2::mod_mime": "Apache module 'mime' with config file", + "apache2::mod_proxy_ajp": "Apache module 'proxy_ajp'", + "apache2": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "centos": [ + + ], + "debian": [ + + ], + "redhat": [ + + ] + }, + "version": "0.10.0", + "name": "apache2", + "conflicting": { + + }, + "attributes": { + "apache\/traceenable": { + "default": "On", + "type": "string", + "multiple_values": false, + "description": "Determine behavior of TRACE requests", + "display_name": "Apache Trace Enable", + "recipes": [ + + ], + "required": false + }, + "apache\/timeout": { + "default": "300", + "type": "string", + "multiple_values": false, + "description": "Connection timeout value", + "display_name": "Apache Timeout", + "recipes": [ + + ], + "required": false + }, + "apache\/icondir": { + "default": "\/usr\/share\/apache2\/icons", + "type": "string", + "multiple_values": false, + "description": "Directory location for icons", + "display_name": "Apache Icondir", + "recipes": [ + + ], + "required": false + }, + "apache\/user": { + "default": "www-data", + "type": "string", + "multiple_values": false, + "description": "User Apache runs as", + "display_name": "Apache User", + "recipes": [ + + ], + "required": false + }, + "apache\/worker\/threadsperchild": { + "default": "64", + "type": "string", + "multiple_values": false, + "description": "Constant number of worker threads in each server process", + "display_name": "Apache Worker MPM ThreadsPerChild", + "recipes": [ + + ], + "required": false + }, + "apache\/worker\/maxclients": { + "default": "1024", + "type": "string", + "multiple_values": false, + "description": "Maximum number of simultaneous connections", + "display_name": "Apache Worker MPM MaxClients", + "recipes": [ + + ], + "required": false + }, + "apache\/worker": { + "type": "hash", + "multiple_values": false, + "description": "Hash of Apache prefork tuning attributes.", + "display_name": "Apache Worker", + "recipes": [ + + ], + "required": false + }, + "apache\/contact": { + "default": "ops@example.com", + "type": "string", + "multiple_values": false, + "description": "Email address of webmaster", + "display_name": "Apache Contact", + "recipes": [ + + ], + "required": false + }, + "apache\/prefork\/startservers": { + "default": "16", + "type": "string", + "multiple_values": false, + "description": "Number of MPM servers to start", + "display_name": "Apache Prefork MPM StartServers", + "recipes": [ + + ], + "required": false + }, + "apache\/prefork\/minspareservers": { + "default": "16", + "type": "string", + "multiple_values": false, + "description": "Minimum number of spare server processes", + "display_name": "Apache Prefork MPM MinSpareServers", + "recipes": [ + + ], + "required": false + }, + "apache\/allowed_openids": { + "default": "", + "type": "string", + "multiple_values": false, + "description": "Array of OpenIDs allowed to authenticate", + "display_name": "Apache Allowed OpenIDs", + "recipes": [ + + ], + "required": false + }, + "apache\/keepalivetimeout": { + "default": "5", + "type": "string", + "multiple_values": false, + "description": "Time to wait for requests on persistent connection", + "display_name": "Apache Keepalive Timeout", + "recipes": [ + + ], + "required": false + }, + "apache\/keepaliverequests": { + "default": "100", + "type": "string", + "multiple_values": false, + "description": "Number of requests allowed on a persistent connection", + "display_name": "Apache Keepalive Requests", + "recipes": [ + + ], + "required": false + }, + "apache\/worker\/maxrequestsperchild": { + "default": "0", + "type": "string", + "multiple_values": false, + "description": "Maximum number of request a child process will handle", + "display_name": "Apache Worker MPM MaxRequestsPerChild", + "recipes": [ + + ], + "required": false + }, + "apache\/listen_ports": { + "default": [ + "80", + "443" + ], + "type": "array", + "multiple_values": false, + "description": "Ports that Apache should listen on", + "display_name": "Apache Listen Ports", + "recipes": [ + + ], + "required": false + }, + "apache\/dir": { + "default": "\/etc\/apache2", + "type": "string", + "multiple_values": false, + "description": "Location for Apache configuration", + "display_name": "Apache Directory", + "recipes": [ + + ], + "required": false + }, + "apache\/worker\/maxsparethreads": { + "default": "192", + "type": "string", + "multiple_values": false, + "description": "Maximum number of spare worker threads", + "display_name": "Apache Worker MPM MaxSpareThreads", + "recipes": [ + + ], + "required": false + }, + "apache\/prefork\/maxrequestsperchild": { + "default": "10000", + "type": "string", + "multiple_values": false, + "description": "Maximum number of request a child process will handle", + "display_name": "Apache Prefork MPM MaxRequestsPerChild", + "recipes": [ + + ], + "required": false + }, + "apache\/prefork\/serverlimit": { + "default": "400", + "type": "string", + "multiple_values": false, + "description": "Upper limit on configurable server processes", + "display_name": "Apache Prefork MPM ServerLimit", + "recipes": [ + + ], + "required": false + }, + "apache\/binary": { + "default": "\/usr\/sbin\/apache2", + "type": "string", + "multiple_values": false, + "description": "Apache server daemon program", + "display_name": "Apache Binary", + "recipes": [ + + ], + "required": false + }, + "apache\/prefork\/maxspareservers": { + "default": "32", + "type": "string", + "multiple_values": false, + "description": "Maximum number of spare server processes", + "display_name": "Apache Prefork MPM MaxSpareServers", + "recipes": [ + + ], + "required": false + }, + "apache\/keepalive": { + "default": "On", + "type": "string", + "multiple_values": false, + "description": "HTTP persistent connections", + "display_name": "Apache Keepalive", + "recipes": [ + + ], + "required": false + }, + "apache": { + "type": "hash", + "multiple_values": false, + "description": "Hash of Apache attributes", + "display_name": "Apache Hash", + "recipes": [ + + ], + "required": false + }, + "apache\/worker\/startservers": { + "default": "4", + "type": "string", + "multiple_values": false, + "description": "Initial number of server processes to start", + "display_name": "Apache Worker MPM StartServers", + "recipes": [ + + ], + "required": false + }, + "apache\/prefork\/maxclients": { + "default": "400", + "type": "string", + "multiple_values": false, + "description": "Maximum number of simultaneous connections", + "display_name": "Apache Prefork MPM MaxClients", + "recipes": [ + + ], + "required": false + }, + "apache\/prefork": { + "type": "hash", + "multiple_values": false, + "description": "Hash of Apache prefork tuning attributes.", + "display_name": "Apache Prefork", + "recipes": [ + + ], + "required": false + }, + "apache\/servertokens": { + "default": "Prod", + "type": "string", + "multiple_values": false, + "description": "Server response header", + "display_name": "Apache Server Tokens", + "recipes": [ + + ], + "required": false + }, + "apache\/worker\/minsparethreads": { + "default": "64", + "type": "string", + "multiple_values": false, + "description": "Minimum number of spare worker threads", + "display_name": "Apache Worker MPM MinSpareThreads", + "recipes": [ + + ], + "required": false + }, + "apache\/serversignature": { + "default": "On", + "type": "string", + "multiple_values": false, + "description": "Configure footer on server-generated documents", + "display_name": "Apache Server Signature", + "recipes": [ + + ], + "required": false + }, + "apache\/log_dir": { + "default": "\/etc\/apache2", + "type": "string", + "multiple_values": false, + "description": "Location for Apache logs", + "display_name": "Apache Log Directory", + "recipes": [ + + ], + "required": false + } + }, + "providing": { + "apache2::mod_python": [ + + ], + "apache2::mod_authn_file": [ + + ], + "apache2::mod_dir": [ + + ], + "apache2::mod_php5": [ + + ], + "apache2::mod_proxy_balancer": [ + + ], + "apache2::mod_dav": [ + + ], + "apache2::mod_authz_groupfile": [ + + ], + "apache2::mod_auth_basic": [ + + ], + "apache2::mod_setenvif": [ + + ], + "apache2::mod_authz_user": [ + + ], + "apache2::mod_deflate": [ + + ], + "apache2::mod_ssl": [ + + ], + "apache2::mod_negotiation": [ + + ], + "apache2::mod_dav_svn": [ + + ], + "apache2::mod_authz_host": [ + + ], + "apache2::mod_rewrite": [ + + ], + "apache2::mod_cgi": [ + + ], + "apache2::mod_fcgid": [ + + ], + "apache2::mod_auth_digest": [ + + ], + "apache2::mod_env": [ + + ], + "apache2::mod_headers": [ + + ], + "apache2::mod_autoindex": [ + + ], + "apache2::mod_authnz_ldap": [ + + ], + "apache2::mod_proxy_connect": [ + + ], + "apache2::mod_proxy": [ + + ], + "apache2::mod_alias": [ + + ], + "apache2::mod_status": [ + + ], + "apache2::mod_ldap": [ + + ], + "apache2::mod_authz_default": [ + + ], + "apache2::mod_log_config": [ + + ], + "apache2": [ + + ], + "apache2::mod_expires": [ + + ], + "apache2::god_monitor": [ + + ], + "apache2::mod_proxy_http": [ + + ], + "apache2::mod_auth_openid": [ + + ], + "apache2::mod_mime": [ + + ], + "apache2::mod_proxy_ajp": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "= DESCRIPTION:\n\nComplete Debian\/Ubuntu style Apache2 configuration.\n\n= REQUIREMENTS:\n\nDebian or Ubuntu preferred.\n\nRed Hat\/CentOS and Fedora can be used but will be converted to a Debian\/Ubuntu style Apache as it's far easier to manage with chef. \n\n= ATTRIBUTES:\n\nThe file attributes\/apache.rb contains the following attribute types:\n\n* platform specific locations and settings.\n* general settings\n* prefork attributes\n* worker attributes\n\nGeneral settings and prefork\/worker attributes are tunable.\n\n= USAGE:\n\nInclude the apache2 recipe to install Apache2 and get 'sane' default settings. Configuration is modularized through Apache vhost sites a la Debian style configuration.\n\nFor Red Hat, CentOS and Fedora you should first disable selinux as it's not supported (yet), then remove the stock httpd and all it's dependencies prior to attempting to use this recipe. Many packages in these distributions drop conflicting configs into conf.d, all of which haven't been accounted for yet. Starting from scratch will also make it far easier to debug.\n\n== Defines:\n\n* apache_module: sets up an Apache module.\n* apache_conf: sets up a config file for an apache module.\n* apache_site: sets up a vhost site. The conf file must be available.\n* web_app: copies the template for a web app and enables it as a site via apache_site.\n\n== Web Apps:\n\nVarious applications that can be set up with Apache as the front end, such as PHP, Django, Rails and others can use the web_app define to set up the template and the Apache site. The define is kind of dumb, so the template needs have the application implementation settings, since we don't know what your app is or what is needed from Apache.\n\nWe only prototype one parameter for the web_app define, \"template\". This is used to specify the name of the template to use in the current cookbook. When you use web_app, you can set up any parameters you want to use in your template. They will get passed to the template through the params hash. For example, the sample web_app.conf.erb template in this cookbook makes use of these.\n\n* docroot\n* server_name\n* server_aliases\n\nThese are available as @params[:docroot], @params[:server_name], @params[:server_aliases] within the template. \n\nIf 'cookbook' and 'template' are not specified, the current cookbook's templates\/default\/web_app.conf.erb will be used. If this template is not suitable for your application, copy it to your cookbook and customize as needed.\n\n== God Monitor:\n\nThere's a new recipe, apache2::god_monitor. You will need to make sure to include the 'god' recipe before using the apache2::god_monitor recipe in your cookbook.\n\n== OpenID Auth\n\nInstalls the mod_auth_openid module from source. Specify an array of OpenIDs that are allowed to authenticate with the attribute apache[:allowed_openids]. Use the following in a vhost to protect with OpenID authentication:\n\n AuthOpenIDEnabled On\n AuthOpenIDDBLocation \/var\/cache\/apache2\/mod_auth_openid.db\n AuthOpenIDUserProgram \/usr\/local\/bin\/mod_auth_openid.rb\n\nChange the DBLocation as appropriate for your platform. You'll need to change the file in the recipe to match. The UserProgram is optional if you don't want to limit access by certain OpenIDs.\n\n= LICENSE & AUTHOR:\n\nAuthor:: Joshua Timberman ()\nCopyright:: 2009, Opscode, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http:\/\/www.apache.org\/licenses\/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/apache2/metadata.rb b/apache2/metadata.rb new file mode 100644 index 0000000..ea9ab9f --- /dev/null +++ b/apache2/metadata.rb @@ -0,0 +1,197 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs and configures all aspects of apache2 using Debian style symlinks with helper definitions" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.10.0" +recipe "apache2", "Main Apache configuration" +recipe "apache2::mod_alias", "Apache module 'alias' with config file" +recipe "apache2::mod_auth_basic", "Apache module 'auth_basic'" +recipe "apache2::mod_auth_digest", "Apache module 'auth_digest'" +recipe "apache2::mod_auth_openid", "Apache module 'authopenid'" +recipe "apache2::mod_authn_file", "Apache module 'authn_file'" +recipe "apache2::mod_authnz_ldap", "Apache module 'authnz_ldap'" +recipe "apache2::mod_authz_default", "Apache module 'authz_default'" +recipe "apache2::mod_authz_groupfile", "Apache module 'authz_groupfile'" +recipe "apache2::mod_authz_host", "Apache module 'authz_host'" +recipe "apache2::mod_authz_user", "Apache module 'authz_user'" +recipe "apache2::mod_autoindex", "Apache module 'autoindex' with config file" +recipe "apache2::mod_cgi", "Apache module 'cgi'" +recipe "apache2::mod_dav", "Apache module 'dav'" +recipe "apache2::mod_dav_svn", "Apache module 'dav_svn'" +recipe "apache2::mod_deflate", "Apache module 'deflate' with config file" +recipe "apache2::mod_dir", "Apache module 'dir' with config file" +recipe "apache2::mod_env", "Apache module 'env'" +recipe "apache2::mod_expires", "Apache module 'expires'" +recipe "apache2::mod_fcgid", "Apache module 'fcgid', package on ubuntu/debian, rhel/centos, compile source on suse; with config file" +recipe "apache2::mod_headers", "Apache module 'headers'" +recipe "apache2::mod_ldap", "Apache module 'ldap'" +recipe "apache2::mod_log_config", "Apache module 'log_config'" +recipe "apache2::mod_mime", "Apache module 'mime' with config file" +recipe "apache2::mod_negotiation", "Apache module 'negotiation' with config file" +recipe "apache2::mod_php5", "Apache module 'php5'" +recipe "apache2::mod_proxy", "Apache module 'proxy' with config file" +recipe "apache2::mod_proxy_ajp", "Apache module 'proxy_ajp'" +recipe "apache2::mod_proxy_balancer", "Apache module 'proxy_balancer'" +recipe "apache2::mod_proxy_connect", "Apache module 'proxy_connect'" +recipe "apache2::mod_proxy_http", "Apache module 'proxy_http'" +recipe "apache2::mod_python", "Apache module 'python'" +recipe "apache2::mod_rewrite", "Apache module 'rewrite'" +recipe "apache2::mod_setenvif", "Apache module 'setenvif' with config file" +recipe "apache2::mod_ssl", "Apache module 'ssl' with config file, adds port 443 to listen_ports" +recipe "apache2::mod_status", "Apache module 'status' with config file" + +%w{redhat centos debian ubuntu}.each do |os| + supports os +end + +attribute "apache", + :display_name => "Apache Hash", + :description => "Hash of Apache attributes", + :type => "hash" + +attribute "apache/dir", + :display_name => "Apache Directory", + :description => "Location for Apache configuration", + :default => "/etc/apache2" + +attribute "apache/log_dir", + :display_name => "Apache Log Directory", + :description => "Location for Apache logs", + :default => "/etc/apache2" + +attribute "apache/user", + :display_name => "Apache User", + :description => "User Apache runs as", + :default => "www-data" + +attribute "apache/binary", + :display_name => "Apache Binary", + :description => "Apache server daemon program", + :default => "/usr/sbin/apache2" + +attribute "apache/icondir", + :display_name => "Apache Icondir", + :description => "Directory location for icons", + :default => "/usr/share/apache2/icons" + +attribute "apache/listen_ports", + :display_name => "Apache Listen Ports", + :description => "Ports that Apache should listen on", + :type => "array", + :default => [ "80", "443" ] + +attribute "apache/contact", + :display_name => "Apache Contact", + :description => "Email address of webmaster", + :default => "ops@example.com" + +attribute "apache/timeout", + :display_name => "Apache Timeout", + :description => "Connection timeout value", + :default => "300" + +attribute "apache/keepalive", + :display_name => "Apache Keepalive", + :description => "HTTP persistent connections", + :default => "On" + +attribute "apache/keepaliverequests", + :display_name => "Apache Keepalive Requests", + :description => "Number of requests allowed on a persistent connection", + :default => "100" + +attribute "apache/keepalivetimeout", + :display_name => "Apache Keepalive Timeout", + :description => "Time to wait for requests on persistent connection", + :default => "5" + +attribute "apache/servertokens", + :display_name => "Apache Server Tokens", + :description => "Server response header", + :default => "Prod" + +attribute "apache/serversignature", + :display_name => "Apache Server Signature", + :description => "Configure footer on server-generated documents", + :default => "On" + +attribute "apache/traceenable", + :display_name => "Apache Trace Enable", + :description => "Determine behavior of TRACE requests", + :default => "On" + +attribute "apache/allowed_openids", + :display_name => "Apache Allowed OpenIDs", + :description => "Array of OpenIDs allowed to authenticate", + :default => "" + +attribute "apache/prefork", + :display_name => "Apache Prefork", + :description => "Hash of Apache prefork tuning attributes.", + :type => "hash" + +attribute "apache/prefork/startservers", + :display_name => "Apache Prefork MPM StartServers", + :description => "Number of MPM servers to start", + :default => "16" + +attribute "apache/prefork/minspareservers", + :display_name => "Apache Prefork MPM MinSpareServers", + :description => "Minimum number of spare server processes", + :default => "16" + +attribute "apache/prefork/maxspareservers", + :display_name => "Apache Prefork MPM MaxSpareServers", + :description => "Maximum number of spare server processes", + :default => "32" + +attribute "apache/prefork/serverlimit", + :display_name => "Apache Prefork MPM ServerLimit", + :description => "Upper limit on configurable server processes", + :default => "400" + +attribute "apache/prefork/maxclients", + :display_name => "Apache Prefork MPM MaxClients", + :description => "Maximum number of simultaneous connections", + :default => "400" + +attribute "apache/prefork/maxrequestsperchild", + :display_name => "Apache Prefork MPM MaxRequestsPerChild", + :description => "Maximum number of request a child process will handle", + :default => "10000" + +attribute "apache/worker", + :display_name => "Apache Worker", + :description => "Hash of Apache prefork tuning attributes.", + :type => "hash" + +attribute "apache/worker/startservers", + :display_name => "Apache Worker MPM StartServers", + :description => "Initial number of server processes to start", + :default => "4" + +attribute "apache/worker/maxclients", + :display_name => "Apache Worker MPM MaxClients", + :description => "Maximum number of simultaneous connections", + :default => "1024" + +attribute "apache/worker/minsparethreads", + :display_name => "Apache Worker MPM MinSpareThreads", + :description => "Minimum number of spare worker threads", + :default => "64" + +attribute "apache/worker/maxsparethreads", + :display_name => "Apache Worker MPM MaxSpareThreads", + :description => "Maximum number of spare worker threads", + :default => "192" + +attribute "apache/worker/threadsperchild", + :display_name => "Apache Worker MPM ThreadsPerChild", + :description => "Constant number of worker threads in each server process", + :default => "64" + +attribute "apache/worker/maxrequestsperchild", + :display_name => "Apache Worker MPM MaxRequestsPerChild", + :description => "Maximum number of request a child process will handle", + :default => "0" diff --git a/apache2/recipes/default.rb b/apache2/recipes/default.rb new file mode 100644 index 0000000..2c42933 --- /dev/null +++ b/apache2/recipes/default.rb @@ -0,0 +1,191 @@ +# +# Cookbook Name:: apache2 +# Recipe:: default +# +# Copyright 2008-2009, Opscode, 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 "apache2" do + case node[:platform] + when "centos","redhat","fedora","suse" + package_name "httpd" + when "debian","ubuntu" + package_name "apache2" + end + action :install +end + +service "apache2" do + case node[:platform] + when "centos","redhat","fedora","suse" + service_name "httpd" + # If restarted/reloaded too quickly httpd has a habit of failing. + # This may happen with multiple recipes notifying apache to restart - like + # during the initial bootstrap. + restart_command "/sbin/service httpd restart && sleep 1" + reload_command "/sbin/service httpd reload && sleep 1" + when "debian","ubuntu" + service_name "apache2" + end + supports value_for_platform( + "debian" => { "4.0" => [ :restart, :reload ], "default" => [ :restart, :reload, :status ] }, + "ubuntu" => { "default" => [ :restart, :reload, :status ] }, + "centos" => { "default" => [ :restart, :reload, :status ] }, + "redhat" => { "default" => [ :restart, :reload, :status ] }, + "fedora" => { "default" => [ :restart, :reload, :status ] }, + "default" => { "default" => [:restart, :reload ] } + ) + action :enable +end + +if platform?("centos", "redhat", "fedora", "suse") + directory node[:apache][:log_dir] do + mode 0755 + action :create + end + + remote_file "/usr/local/bin/apache2_module_conf_generate.pl" do + source "apache2_module_conf_generate.pl" + mode 0755 + owner "root" + group "root" + end + + %w{sites-available sites-enabled mods-available mods-enabled}.each do |dir| + directory "#{node[:apache][:dir]}/#{dir}" do + mode 0755 + owner "root" + group "root" + action :create + end + end + + execute "generate-module-list" do + if node[:kernel][:machine] == "x86_64" + libdir = "lib64" + else + libdir = "lib" + end + command "/usr/local/bin/apache2_module_conf_generate.pl /usr/#{libdir}/httpd/modules /etc/httpd/mods-available" + + action :run + end + + %w{a2ensite a2dissite a2enmod a2dismod}.each do |modscript| + template "/usr/sbin/#{modscript}" do + source "#{modscript}.erb" + mode 0755 + owner "root" + group "root" + end + end + + # installed by default on centos/rhel, remove in favour of mods-enabled + file "#{node[:apache][:dir]}/conf.d/proxy_ajp.conf" do + action :delete + backup false + end + file "#{node[:apache][:dir]}/conf.d/README" do + action :delete + backup false + end + + # welcome page moved to the default-site.rb temlate + file "#{node[:apache][:dir]}/conf.d/welcome.conf" do + action :delete + backup false + end +end + +directory "#{node[:apache][:dir]}/ssl" do + action :create + mode 0755 + owner "root" + group "root" +end + +template "apache2.conf" do + case node[:platform] + when "centos","redhat","fedora" + path "#{node[:apache][:dir]}/conf/httpd.conf" + when "debian","ubuntu" + path "#{node[:apache][:dir]}/apache2.conf" + end + source "apache2.conf.erb" + owner "root" + group "root" + mode 0644 + notifies :restart, resources(:service => "apache2") +end + +template "security" do + path "#{node[:apache][:dir]}/conf.d/security" + source "security.erb" + owner "root" + group "root" + mode 0644 + backup false + notifies :restart, resources(:service => "apache2") +end + +template "charset" do + path "#{node[:apache][:dir]}/conf.d/charset" + source "charset.erb" + owner "root" + group "root" + mode 0644 + backup false + notifies :restart, resources(:service => "apache2") +end + +template "#{node[:apache][:dir]}/ports.conf" do + source "ports.conf.erb" + group "root" + owner "root" + variables :apache_listen_ports => node[:apache][:listen_ports] + mode 0644 + notifies :restart, resources(:service => "apache2") +end + +template "#{node[:apache][:dir]}/sites-available/default" do + source "default-site.erb" + owner "root" + group "root" + mode 0644 + notifies :restart, resources(:service => "apache2") +end + +include_recipe "apache2::mod_status" +include_recipe "apache2::mod_alias" +include_recipe "apache2::mod_auth_basic" +include_recipe "apache2::mod_authn_file" +include_recipe "apache2::mod_authz_default" +include_recipe "apache2::mod_authz_groupfile" +include_recipe "apache2::mod_authz_host" +include_recipe "apache2::mod_authz_user" +include_recipe "apache2::mod_autoindex" +include_recipe "apache2::mod_dir" +include_recipe "apache2::mod_env" +include_recipe "apache2::mod_mime" +include_recipe "apache2::mod_negotiation" +include_recipe "apache2::mod_setenvif" +include_recipe "apache2::mod_log_config" if platform?("centos", "redhat", "suse") + +# uncomment to get working example site on centos/redhat/fedora +#apache_site "default" + +service "apache2" do + action :start +end diff --git a/apache2/recipes/god_monitor.rb b/apache2/recipes/god_monitor.rb new file mode 100644 index 0000000..b3c49eb --- /dev/null +++ b/apache2/recipes/god_monitor.rb @@ -0,0 +1,33 @@ +# +# Cookbook Name:: apache2 +# Recipe:: god_monitor +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_service = service "apache2" do + action :nothing +end + +start_command = apache_service.start_command +stop_command = apache_service.stop_command +restart_command = apache_service.restart_command + +god_monitor "apache2" do + config "apache2.god.erb" + start (start_command)?start_command : "/etc/init.d/#{apache_service.service_name} start" + restart (restart_command)?restart_command : "/etc/init.d/#{apache_service.service_name} restart" + stop (stop_command)?stop_command : "/etc/init.d/#{apache_service.service_name} stop" +end diff --git a/apache2/recipes/mod_alias.rb b/apache2/recipes/mod_alias.rb new file mode 100644 index 0000000..a4618ed --- /dev/null +++ b/apache2/recipes/mod_alias.rb @@ -0,0 +1,22 @@ +# +# Cookbook Name:: apache2 +# Recipe:: alias +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "alias" do + conf true +end diff --git a/apache2/recipes/mod_auth_basic.rb b/apache2/recipes/mod_auth_basic.rb new file mode 100644 index 0000000..d30264f --- /dev/null +++ b/apache2/recipes/mod_auth_basic.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: apache2 +# Recipe:: auth_basic +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "auth_basic" diff --git a/apache2/recipes/mod_auth_digest.rb b/apache2/recipes/mod_auth_digest.rb new file mode 100644 index 0000000..5aef926 --- /dev/null +++ b/apache2/recipes/mod_auth_digest.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: apache2 +# Recipe:: auth_digest +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "auth_digest" diff --git a/apache2/recipes/mod_auth_openid.rb b/apache2/recipes/mod_auth_openid.rb new file mode 100644 index 0000000..83cc220 --- /dev/null +++ b/apache2/recipes/mod_auth_openid.rb @@ -0,0 +1,59 @@ +# +# Cookbook Name:: apache2 +# Recipe:: mod_auth_openid +# +# Copyright 2008-2009, Opscode, 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. +# + +%w{ apache2-prefork-dev libopkele-dev libopkele3 }.each do |pkg| + package pkg +end + +remote_file "/tmp/mod_auth_openid-0.4.tar.gz" do + source "http://butterfat.net/releases/mod_auth_openid/mod_auth_openid-0.4.tar.gz" + mode 0644 +end + +bash "install mod_auth_openid" do + cwd "/tmp" + code <<-EOH + tar zxvf mod_auth_openid-0.4.tar.gz + cd mod_auth_openid-0.4 && ./configure + perl -pi -e "s/-i -a -n 'authopenid'/-i -n 'authopenid'/g" Makefile + make && make install + EOH + not_if { File.exists?("/usr/lib/apache2/modules/mod_auth_openid.so") } +end + +file "/var/cache/apache2/mod_auth_openid.db" do + owner node[:apache][:user] + mode 0600 +end + +template "#{node[:apache][:dir]}/mods-available/authopenid.load" do + source "mods/authopenid.load.erb" + owner "root" + group "root" + mode 0644 +end + +apache_module "authopenid" + +template "/usr/local/bin/mod_auth_openid.rb" do + source "mod_auth_openid.rb.erb" + owner node[:apache][:user] + group node[:apache][:user] + mode 0750 +end diff --git a/apache2/recipes/mod_authn_file.rb b/apache2/recipes/mod_authn_file.rb new file mode 100644 index 0000000..872caa7 --- /dev/null +++ b/apache2/recipes/mod_authn_file.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: apache2 +# Recipe:: authn_file +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "authn_file" diff --git a/apache2/recipes/mod_authnz_ldap.rb b/apache2/recipes/mod_authnz_ldap.rb new file mode 100644 index 0000000..0310d24 --- /dev/null +++ b/apache2/recipes/mod_authnz_ldap.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: apache2 +# Recipe:: authnz_ldap +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "authnz_ldap" diff --git a/apache2/recipes/mod_authz_default.rb b/apache2/recipes/mod_authz_default.rb new file mode 100644 index 0000000..123536d --- /dev/null +++ b/apache2/recipes/mod_authz_default.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: apache2 +# Recipe:: authz_default +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "authz_default" diff --git a/apache2/recipes/mod_authz_groupfile.rb b/apache2/recipes/mod_authz_groupfile.rb new file mode 100644 index 0000000..b2833b2 --- /dev/null +++ b/apache2/recipes/mod_authz_groupfile.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: apache2 +# Recipe:: authz_groupfile +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "authz_groupfile" diff --git a/apache2/recipes/mod_authz_host.rb b/apache2/recipes/mod_authz_host.rb new file mode 100644 index 0000000..87c1a4b --- /dev/null +++ b/apache2/recipes/mod_authz_host.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: apache2 +# Recipe:: authz_host +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "authz_host" diff --git a/apache2/recipes/mod_authz_user.rb b/apache2/recipes/mod_authz_user.rb new file mode 100644 index 0000000..8dd46df --- /dev/null +++ b/apache2/recipes/mod_authz_user.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: apache2 +# Recipe:: authz_user +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "authz_user" diff --git a/apache2/recipes/mod_autoindex.rb b/apache2/recipes/mod_autoindex.rb new file mode 100644 index 0000000..622a66e --- /dev/null +++ b/apache2/recipes/mod_autoindex.rb @@ -0,0 +1,22 @@ +# +# Cookbook Name:: apache2 +# Recipe:: autoindex +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "autoindex" do + conf true +end diff --git a/apache2/recipes/mod_cgi.rb b/apache2/recipes/mod_cgi.rb new file mode 100644 index 0000000..6c15a05 --- /dev/null +++ b/apache2/recipes/mod_cgi.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: apache2 +# Recipe:: cgi +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "cgi" diff --git a/apache2/recipes/mod_dav.rb b/apache2/recipes/mod_dav.rb new file mode 100644 index 0000000..fef656a --- /dev/null +++ b/apache2/recipes/mod_dav.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: apache2 +# Recipe:: dav +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "dav" diff --git a/apache2/recipes/mod_dav_svn.rb b/apache2/recipes/mod_dav_svn.rb new file mode 100644 index 0000000..ce50d54 --- /dev/null +++ b/apache2/recipes/mod_dav_svn.rb @@ -0,0 +1,22 @@ +# +# Cookbook Name:: apache2 +# Recipe:: dav_svn +# +# Copyright 2008-2009, Opscode, 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 "libapache2-svn" + +apache_module "dav_svn" diff --git a/apache2/recipes/mod_deflate.rb b/apache2/recipes/mod_deflate.rb new file mode 100644 index 0000000..b568f30 --- /dev/null +++ b/apache2/recipes/mod_deflate.rb @@ -0,0 +1,22 @@ +# +# Cookbook Name:: apache2 +# Recipe:: deflate +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "deflate" do + conf true +end diff --git a/apache2/recipes/mod_dir.rb b/apache2/recipes/mod_dir.rb new file mode 100644 index 0000000..9930c3a --- /dev/null +++ b/apache2/recipes/mod_dir.rb @@ -0,0 +1,22 @@ +# +# Cookbook Name:: apache2 +# Recipe:: dir +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "dir" do + conf true +end diff --git a/apache2/recipes/mod_env.rb b/apache2/recipes/mod_env.rb new file mode 100644 index 0000000..d345503 --- /dev/null +++ b/apache2/recipes/mod_env.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: apache2 +# Recipe:: env +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "env" diff --git a/apache2/recipes/mod_expires.rb b/apache2/recipes/mod_expires.rb new file mode 100644 index 0000000..9e5042e --- /dev/null +++ b/apache2/recipes/mod_expires.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: apache2 +# Recipe:: expires +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "expires" diff --git a/apache2/recipes/mod_fcgid.rb b/apache2/recipes/mod_fcgid.rb new file mode 100644 index 0000000..ea7ec3e --- /dev/null +++ b/apache2/recipes/mod_fcgid.rb @@ -0,0 +1,46 @@ +# +# Cookbook Name:: apache2 +# Recipe:: fcgid +# +# Copyright 2008-2009, Opscode, 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. +# + +if platform?("debian", "ubuntu") + package "libapache2-mod-fcgid" +elsif platform?("centos", "redhat", "fedora") + package "mod_fcgid" do + notifies :run, resources(:execute => "generate-module-list"), :immediately + end + + file "#{node[:apache][:dir]}/conf.d/fcgid.conf" do + action :delete + backup false + end +elsif platform?("suse") + apache_lib_path = node[:architecture] == "i386" ? "/usr/lib/httpd" : "/usr/lib64/httpd" + package "httpd-devel" + bash "install-fcgid" do + code <<-EOH +(cd /tmp; wget http://superb-east.dl.sourceforge.net/sourceforge/mod-fcgid/mod_fcgid.2.2.tgz) +(cd /tmp; tar zxvf mod_fcgid.2.2.tgz) +(cd /tmp; perl -pi -e 's!/usr/local/apache2!#{apache_lib_path}!g' ./mod_fcgid.2.2/Makefile) +(cd /tmp/mod_fcgid.2.2; make install) +EOH + end +end + +apache_module "fcgid" do + conf true +end diff --git a/apache2/recipes/mod_headers.rb b/apache2/recipes/mod_headers.rb new file mode 100644 index 0000000..5e6b94d --- /dev/null +++ b/apache2/recipes/mod_headers.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: apache2 +# Recipe:: headers +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "headers" diff --git a/apache2/recipes/mod_ldap.rb b/apache2/recipes/mod_ldap.rb new file mode 100644 index 0000000..0877694 --- /dev/null +++ b/apache2/recipes/mod_ldap.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: apache2 +# Recipe:: ldap +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "ldap" diff --git a/apache2/recipes/mod_log_config.rb b/apache2/recipes/mod_log_config.rb new file mode 100644 index 0000000..fa8a484 --- /dev/null +++ b/apache2/recipes/mod_log_config.rb @@ -0,0 +1,24 @@ +# +# Cookbook Name:: apache2 +# Recipe:: log_config +# +# Copyright 2008-2009, Opscode, 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. +# + +if platform?("centos", "redhat", "fedora", "suse") + apache_module "log_config" +else + include_recipe "apache2" +end diff --git a/apache2/recipes/mod_mime.rb b/apache2/recipes/mod_mime.rb new file mode 100644 index 0000000..16aee1a --- /dev/null +++ b/apache2/recipes/mod_mime.rb @@ -0,0 +1,22 @@ +# +# Cookbook Name:: apache2 +# Recipe:: mime +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "mime" do + conf true +end diff --git a/apache2/recipes/mod_negotiation.rb b/apache2/recipes/mod_negotiation.rb new file mode 100644 index 0000000..348e11f --- /dev/null +++ b/apache2/recipes/mod_negotiation.rb @@ -0,0 +1,22 @@ +# +# Cookbook Name:: apache2 +# Recipe:: negotiation +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "negotiation" do + conf true +end diff --git a/apache2/recipes/mod_php5.rb b/apache2/recipes/mod_php5.rb new file mode 100644 index 0000000..b6ae2c0 --- /dev/null +++ b/apache2/recipes/mod_php5.rb @@ -0,0 +1,32 @@ +# +# Cookbook Name:: apache2 +# Recipe:: php5 +# +# Copyright 2008-2009, Opscode, 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. +# + +case node[:platform] +when "debian", "ubuntu" + package "libapache2-mod-php5" do + action :install + end +when "centos", "redhat", "fedora" + package "php" do + action :install + notifies :run, resources(:execute => "generate-module-list"), :immediately + end +end + +apache_module "php5" diff --git a/apache2/recipes/mod_proxy.rb b/apache2/recipes/mod_proxy.rb new file mode 100644 index 0000000..fff7627 --- /dev/null +++ b/apache2/recipes/mod_proxy.rb @@ -0,0 +1,22 @@ +# +# Cookbook Name:: apache2 +# Recipe:: proxy +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "proxy" do + conf true +end diff --git a/apache2/recipes/mod_proxy_ajp.rb b/apache2/recipes/mod_proxy_ajp.rb new file mode 100644 index 0000000..617a2c2 --- /dev/null +++ b/apache2/recipes/mod_proxy_ajp.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: apache2 +# Recipe:: proxy +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "proxy_ajp" diff --git a/apache2/recipes/mod_proxy_balancer.rb b/apache2/recipes/mod_proxy_balancer.rb new file mode 100644 index 0000000..dc62a71 --- /dev/null +++ b/apache2/recipes/mod_proxy_balancer.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: apache2 +# Recipe:: proxy +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "proxy_balancer" diff --git a/apache2/recipes/mod_proxy_connect.rb b/apache2/recipes/mod_proxy_connect.rb new file mode 100644 index 0000000..f41954f --- /dev/null +++ b/apache2/recipes/mod_proxy_connect.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: apache2 +# Recipe:: proxy +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "proxy_connect" diff --git a/apache2/recipes/mod_proxy_http.rb b/apache2/recipes/mod_proxy_http.rb new file mode 100644 index 0000000..ddff3ea --- /dev/null +++ b/apache2/recipes/mod_proxy_http.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: apache2 +# Recipe:: proxy_http +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "proxy_http" diff --git a/apache2/recipes/mod_python.rb b/apache2/recipes/mod_python.rb new file mode 100644 index 0000000..feaca03 --- /dev/null +++ b/apache2/recipes/mod_python.rb @@ -0,0 +1,22 @@ +# +# Cookbook Name:: apache2 +# Recipe:: python +# +# Copyright 2008-2009, Opscode, 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 "libapache2-mod-python" + +apache_module "python" diff --git a/apache2/recipes/mod_rewrite.rb b/apache2/recipes/mod_rewrite.rb new file mode 100644 index 0000000..df388a6 --- /dev/null +++ b/apache2/recipes/mod_rewrite.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: apache2 +# Recipe:: rewrite +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "rewrite" diff --git a/apache2/recipes/mod_setenvif.rb b/apache2/recipes/mod_setenvif.rb new file mode 100644 index 0000000..4048a5f --- /dev/null +++ b/apache2/recipes/mod_setenvif.rb @@ -0,0 +1,22 @@ +# +# Cookbook Name:: apache2 +# Recipe:: setenvif +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "setenvif" do + conf true +end diff --git a/apache2/recipes/mod_ssl.rb b/apache2/recipes/mod_ssl.rb new file mode 100644 index 0000000..e82b9d1 --- /dev/null +++ b/apache2/recipes/mod_ssl.rb @@ -0,0 +1,42 @@ +# +# Cookbook Name:: apache2 +# Recipe:: ssl +# +# Copyright 2008-2009, Opscode, 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. +# + +if platform?("centos", "redhat", "fedora") + package "mod_ssl" do + action :install + notifies :run, resources(:execute => "generate-module-list"), :immediately + end + + file "#{node[:apache][:dir]}/conf.d/ssl.conf" do + action :delete + backup false + end +end + +ports = node[:apache][:listen_ports].include?("443") ? node[:apache][:listen_ports] : [node[:apache][:listen_ports], "443"].flatten + +template "#{node[:apache][:dir]}/ports.conf" do + source "ports.conf.erb" + variables :apache_listen_ports => ports + notifies :restart, resources(:service => "apache2") +end + +apache_module "ssl" do + conf true +end diff --git a/apache2/recipes/mod_status.rb b/apache2/recipes/mod_status.rb new file mode 100644 index 0000000..3e71727 --- /dev/null +++ b/apache2/recipes/mod_status.rb @@ -0,0 +1,22 @@ +# +# Cookbook Name:: apache2 +# Recipe:: status +# +# Copyright 2008-2009, Opscode, 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. +# + +apache_module "status" do + conf true +end diff --git a/apache2/templates/default/a2dismod.erb b/apache2/templates/default/a2dismod.erb new file mode 100644 index 0000000..bcb73bf --- /dev/null +++ b/apache2/templates/default/a2dismod.erb @@ -0,0 +1,22 @@ +#!/bin/sh -e + +SYSCONFDIR='<%= @node[:apache][:dir] %>' + +if [ -z $1 ]; then + echo "Which module would you like to disable?" + echo -n "Your choices are: " + ls $SYSCONFDIR/mods-enabled/*.load | \ + sed -e "s,$SYSCONFDIR/mods-enabled/,,g" | sed -e 's/\.load$//g;' | xargs echo + echo -n "Module name? " + read MODNAME +else + MODNAME=$1 +fi + +if ! [ -e $SYSCONFDIR/mods-enabled/$MODNAME.load ]; then + echo "This module is already disabled, or does not exist!" + exit 1 +fi + +rm -f $SYSCONFDIR/mods-enabled/$MODNAME.* +echo "Module $MODNAME disabled; reload apache to fully disable." \ No newline at end of file diff --git a/apache2/templates/default/a2dissite.erb b/apache2/templates/default/a2dissite.erb new file mode 100644 index 0000000..7bcd80e --- /dev/null +++ b/apache2/templates/default/a2dissite.erb @@ -0,0 +1,29 @@ +#!/bin/sh -e + +SYSCONFDIR='<%= @node[:apache][:dir] %>' + +if [ -z $1 ]; then + echo "Which site would you like to disable?" + echo -n "Your choices are: " + ls $@node[:apache][:dir]/sites-enabled/* | \ + sed -e "s,$SYSCONFDIR/sites-enabled/,,g" | xargs echo + echo -n "Site name? " + read SITENAME +else + SITENAME=$1 +fi + +if [ $SITENAME = "default" ]; then + PRIORITY="000" +fi + +if ! [ -e $SYSCONFDIR/sites-enabled/$SITENAME -o \ + -e $SYSCONFDIR/sites-enabled/"$PRIORITY"-"$SITENAME" ]; then + echo "This site is already disabled, or does not exist!" + exit 1 +fi + +if ! rm $SYSCONFDIR/sites-enabled/$SITENAME 2>/dev/null; then + rm -f $SYSCONFDIR/sites-enabled/"$PRIORITY"-"$SITENAME" +fi +echo "Site $SITENAME disabled; reload apache to disable." \ No newline at end of file diff --git a/apache2/templates/default/a2enmod.erb b/apache2/templates/default/a2enmod.erb new file mode 100644 index 0000000..4579cbb --- /dev/null +++ b/apache2/templates/default/a2enmod.erb @@ -0,0 +1,37 @@ +#!/bin/sh -e + +SYSCONFDIR='<%= @node[:apache][:dir] %>' + +if [ -z $1 ]; then + echo "Which module would you like to enable?" + echo -n "Your choices are: " + ls $SYSCONFDIR/mods-available/*.load | \ + sed -e "s,$SYSCONFDIR/mods-available/,,g" | sed -e 's/\.load$//g;' | xargs echo + echo -n "Module name? " + read MODNAME +else + MODNAME=$1 +fi + +#figure out if we're on a prefork or threaded mpm +if [ -x /usr/sbin/apache2 ]; then + PREFORK=`/usr/sbin/apache2 -l | grep prefork || true` +fi + +if [ -e $SYSCONFDIR/mods-enabled/$MODNAME.load && -e $SYSCONFDIR/mods-enabled/$MODNAME.conf ]; then + echo "This module is already enabled!" + exit 0 +fi + +if ! [ -e $SYSCONFDIR/mods-available/$MODNAME.load ]; then + echo "This module does not exist!" + exit 1 +fi + +for i in conf load; do + if [ -e $SYSCONFDIR/mods-available/$MODNAME.$i -a ! -e $SYSCONFDIR/mods-enabled/$MODNAME.$i ]; then + ln -sf $SYSCONFDIR/mods-available/$MODNAME.$i $SYSCONFDIR/mods-enabled/$MODNAME.$i; + fi +done + +echo "Module $MODNAME installed; reload apache to enable." \ No newline at end of file diff --git a/apache2/templates/default/a2ensite.erb b/apache2/templates/default/a2ensite.erb new file mode 100644 index 0000000..68b3a15 --- /dev/null +++ b/apache2/templates/default/a2ensite.erb @@ -0,0 +1,38 @@ +#!/bin/sh -e + +SYSCONFDIR='<%= @node[:apache][:dir] %>' + +if [ -z $1 ]; then + echo "Which site would you like to enable?" + echo -n "Your choices are: " + ls $SYSCONFDIR/sites-available/* | \ + sed -e "s,$SYSCONFDIR/sites-available/,,g" | xargs echo + echo -n "Site name? " + read SITENAME +else + SITENAME=$1 +fi + +if [ $SITENAME = "default" ]; then + PRIORITY="000" +fi + +if [ -e $SYSCONFDIR/sites-enabled/$SITENAME -o \ + -e $SYSCONFDIR/sites-enabled/"$PRIORITY"-"$SITENAME" ]; then + echo "This site is already enabled!" + exit 0 +fi + +if ! [ -e $SYSCONFDIR/sites-available/$SITENAME ]; then + echo "This site does not exist!" + exit 1 +fi + +if [ $SITENAME = "default" ]; then + ln -sf $SYSCONFDIR/sites-available/$SITENAME \ + $SYSCONFDIR/sites-enabled/"$PRIORITY"-"$SITENAME" +else + ln -sf $SYSCONFDIR/sites-available/$SITENAME $SYSCONFDIR/sites-enabled/$SITENAME +fi + +echo "Site $SITENAME installed; reload apache to enable." \ No newline at end of file diff --git a/apache2/templates/default/apache2.conf.erb b/apache2/templates/default/apache2.conf.erb new file mode 100644 index 0000000..bbc72c7 --- /dev/null +++ b/apache2/templates/default/apache2.conf.erb @@ -0,0 +1,230 @@ +# +# Generated by Chef +# +# Based on the Ubuntu apache2.conf + +ServerRoot "<%= @node[:apache][:dir] %>" + +# +# The accept serialization lock file MUST BE STORED ON A LOCAL DISK. +# +<% if @node[:platform] == "debian" || @node[:platform] == "ubuntu" -%> +LockFile /var/lock/apache2/accept.lock +<% else %> +LockFile logs/accept.lock +<% end -%> + +# +# PidFile: The file in which the server should record its process +# identification number when it starts. +# +<% if @node[:platform] == "debian" || @node[:platform] == "ubuntu" -%> +PidFile /var/run/apache2.pid +<% elsif @node[:platform] == "centos" -%> +PidFile /var/run/httpd.pid +<% else -%> +PidFile logs/httpd.pid +<% end -%> + +# +# Timeout: The number of seconds before receives and sends time out. +# +Timeout <%= @node[:apache][:timeout] %> + +# +# KeepAlive: Whether or not to allow persistent connections (more than +# one request per connection). Set to "Off" to deactivate. +# +KeepAlive <%= @node[:apache][:keepalive] %> + +# +# MaxKeepAliveRequests: The maximum number of requests to allow +# during a persistent connection. Set to 0 to allow an unlimited amount. +# We recommend you leave this number high, for maximum performance. +# +MaxKeepAliveRequests <%= @node[:apache][:keepaliverequests] %> + +# +# KeepAliveTimeout: Number of seconds to wait for the next request from the +# same client on the same connection. +# +KeepAliveTimeout <%= @node[:apache][:keepalivetimeout] %> + +## +## Server-Pool Size Regulation (MPM specific) +## + +# prefork MPM +# StartServers: number of server processes to start +# MinSpareServers: minimum number of server processes which are kept spare +# MaxSpareServers: maximum number of server processes which are kept spare +# MaxClients: maximum number of server processes allowed to start +# MaxRequestsPerChild: maximum number of requests a server process serves + + StartServers <%= @node[:apache][:prefork][:startservers] %> + MinSpareServers <%= @node[:apache][:prefork][:minspareservers] %> + MaxSpareServers <%= @node[:apache][:prefork][:maxspareservers] %> + ServerLimit <%= @node[:apache][:prefork][:serverlimit] %> + MaxClients <%= @node[:apache][:prefork][:maxclients] %> + MaxRequestsPerChild <%= @node[:apache][:prefork][:maxrequestsperchild] %> + + +# worker MPM +# StartServers: initial number of server processes to start +# MaxClients: maximum number of simultaneous client connections +# MinSpareThreads: minimum number of worker threads which are kept spare +# MaxSpareThreads: maximum number of worker threads which are kept spare +# ThreadsPerChild: constant number of worker threads in each server process +# MaxRequestsPerChild: maximum number of requests a server process serves + + StartServers <%= @node[:apache][:worker][:startservers] %> + MaxClients <%= @node[:apache][:worker][:maxclients] %> + MinSpareThreads <%= @node[:apache][:worker][:minsparethreads] %> + MaxSpareThreads <%= @node[:apache][:worker][:maxsparethreads] %> + ThreadsPerChild <%= @node[:apache][:worker][:threadsperchild] %> + MaxRequestsPerChild <%= @node[:apache][:worker][:maxrequestsperchild] %> + + +User <%= @node[:apache][:user] %> +Group <%= @node[:apache][:user] %> + +# +# AccessFileName: The name of the file to look for in each directory +# for additional configuration directives. See also the AllowOverride +# directive. +# + +AccessFileName .htaccess + +# +# The following lines prevent .htaccess and .htpasswd files from being +# viewed by Web clients. +# + + Order allow,deny + Deny from all + + +# +# DefaultType is the default MIME type the server will use for a document +# if it cannot otherwise determine one, such as from filename extensions. +# If your server contains mostly text or HTML documents, "text/plain" is +# a good value. If most of your content is binary, such as applications +# or images, you may want to use "application/octet-stream" instead to +# keep browsers from trying to display binary files as though they are +# text. +# +DefaultType text/plain + + +# +# HostnameLookups: Log the names of clients or just their IP addresses +# e.g., www.apache.org (on) or 204.62.129.132 (off). +# The default is off because it'd be overall better for the net if people +# had to knowingly turn this feature on, since enabling it means that +# each client request will result in AT LEAST one lookup request to the +# nameserver. +# +HostnameLookups Off + +# ErrorLog: The location of the error log file. +# If you do not specify an ErrorLog directive within a +# container, error messages relating to that virtual host will be +# logged here. If you *do* define an error logfile for a +# container, that host's errors will be logged there and not here. +# +ErrorLog <%= @node[:apache][:log_dir] %>/error.log + +# +# LogLevel: Control the number of messages logged to the error_log. +# Possible values include: debug, info, notice, warn, error, crit, +# alert, emerg. +# +LogLevel warn + +# Include module configuration: +Include <%= @node[:apache][:dir] %>/mods-enabled/*.load +Include <%= @node[:apache][:dir] %>/mods-enabled/*.conf + +# Include ports listing +Include <%= @node[:apache][:dir] %>/ports.conf + +# +# The following directives define some format nicknames for use with +# a CustomLog directive (see below). +# +LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined +LogFormat "%h %l %u %t \"%r\" %>s %b" common +LogFormat "%{Referer}i -> %U" referer +LogFormat "%{User-agent}i" agent +# + +# Customizable error responses come in three flavors: +# 1) plain text 2) local redirects 3) external redirects +# +# Some examples: +#ErrorDocument 500 "The server made a boo boo." +#ErrorDocument 404 /missing.html +#ErrorDocument 404 "/cgi-bin/missing_handler.pl" +#ErrorDocument 402 http://www.example.com/subscription_info.html +# + +# +# Putting this all together, we can internationalize error responses. +# +# We use Alias to redirect any /error/HTTP_.html.var response to +# our collection of by-error message multi-language collections. We use +# includes to substitute the appropriate text. +# +# You can modify the messages' appearance without changing any of the +# default HTTP_.html.var files by adding the line: +# +# Alias /error/include/ "/your/include/path/" +# +# which allows you to create your own set of files by starting with the +# /usr/share/apache2/error/include/ files and copying them to /your/include/path/, +# even on a per-VirtualHost basis. The default include files will display +# your Apache version number and your ServerAdmin email address regardless +# of the setting of ServerSignature. +# +# The internationalized error documents require mod_alias, mod_include +# and mod_negotiation. To activate them, uncomment the following 30 lines. + +# Alias /error/ "/usr/share/apache2/error/" +# +# +# AllowOverride None +# Options IncludesNoExec +# AddOutputFilter Includes html +# AddHandler type-map var +# Order allow,deny +# Allow from all +# LanguagePriority en cs de es fr it nl sv pt-br ro +# ForceLanguagePriority Prefer Fallback +# +# +# ErrorDocument 400 /error/HTTP_BAD_REQUEST.html.var +# ErrorDocument 401 /error/HTTP_UNAUTHORIZED.html.var +# ErrorDocument 403 /error/HTTP_FORBIDDEN.html.var +# ErrorDocument 404 /error/HTTP_NOT_FOUND.html.var +# ErrorDocument 405 /error/HTTP_METHOD_NOT_ALLOWED.html.var +# ErrorDocument 408 /error/HTTP_REQUEST_TIME_OUT.html.var +# ErrorDocument 410 /error/HTTP_GONE.html.var +# ErrorDocument 411 /error/HTTP_LENGTH_REQUIRED.html.var +# ErrorDocument 412 /error/HTTP_PRECONDITION_FAILED.html.var +# ErrorDocument 413 /error/HTTP_REQUEST_ENTITY_TOO_LARGE.html.var +# ErrorDocument 414 /error/HTTP_REQUEST_URI_TOO_LARGE.html.var +# ErrorDocument 415 /error/HTTP_UNSUPPORTED_MEDIA_TYPE.html.var +# ErrorDocument 500 /error/HTTP_INTERNAL_SERVER_ERROR.html.var +# ErrorDocument 501 /error/HTTP_NOT_IMPLEMENTED.html.var +# ErrorDocument 502 /error/HTTP_BAD_GATEWAY.html.var +# ErrorDocument 503 /error/HTTP_SERVICE_UNAVAILABLE.html.var +# ErrorDocument 506 /error/HTTP_VARIANT_ALSO_VARIES.html.var + + + +# Include generic snippets of statements +Include <%= @node[:apache][:dir] %>/conf.d/ + +# Include the virtual host configurations: +Include <%= @node[:apache][:dir] %>/sites-enabled/ diff --git a/apache2/templates/default/apache2.god.erb b/apache2/templates/default/apache2.god.erb new file mode 100644 index 0000000..b7315e4 --- /dev/null +++ b/apache2/templates/default/apache2.god.erb @@ -0,0 +1,19 @@ +God.watch do |w| + w.name = "apache2" + w.interval = 30.seconds # default + w.start = "<%= @params[:start] %>" + w.stop = "/etc/init.d/httpd stop" + w.restart = "<%= @params[:restart] %>" + w.start_grace = 10.seconds + w.restart_grace = 10.seconds + w.pid_file = "/var/run/httpd.pid" + w.behavior(:clean_pid_file) + + w.start_if do |start| + start.condition(:process_running) do |c| + c.interval = 5.seconds + c.running = false + c.notify = 'admin' + end + end +end diff --git a/apache2/templates/default/charset.erb b/apache2/templates/default/charset.erb new file mode 100644 index 0000000..40d7198 --- /dev/null +++ b/apache2/templates/default/charset.erb @@ -0,0 +1,6 @@ +# Read the documentation before enabling AddDefaultCharset. +# In general, it is only a good idea if you know that all your files +# have this encoding. It will override any encoding given in the files +# in meta http-equiv or xml encoding tags. + +#AddDefaultCharset UTF-8 diff --git a/apache2/templates/default/default-site.erb b/apache2/templates/default/default-site.erb new file mode 100644 index 0000000..d461bed --- /dev/null +++ b/apache2/templates/default/default-site.erb @@ -0,0 +1,57 @@ + + ServerAdmin <%= @node[:apache][:contact] %> + + DocumentRoot /var/www/ + + Options FollowSymLinks + AllowOverride None + + + Options Indexes FollowSymLinks MultiViews + AllowOverride None + Order allow,deny + allow from all + # This directive allows us to have apache2's default start page + # in /apache2-default/, but still have / go to the right place + #RedirectMatch ^/$ /apache2-default/ + + + ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ + + AllowOverride None + Options ExecCGI -MultiViews +SymLinksIfOwnerMatch + Order allow,deny + Allow from all + + + ErrorLog <%= @node[:apache][:log_dir] %>/error.log + + # Possible values include: debug, info, notice, warn, error, crit, + # alert, emerg. + LogLevel warn + + CustomLog <%= @node[:apache][:log_dir] %>/access.log combined + ServerSignature On + + Alias /doc/ "/usr/share/doc/" + + Options Indexes MultiViews FollowSymLinks + AllowOverride None + Order deny,allow + Deny from all + Allow from 127.0.0.0/255.0.0.0 ::1/128 + + + <% if @node[:platform] == "centos" || @node[:platform] == "redhat" || @node[:platform] == "fedora" -%> + # + # This configuration file enables the default "Welcome" + # page if there is no default index page present for + # the root URL. To disable the Welcome page, comment + # out all the lines below. + # + + Options -Indexes + ErrorDocument 403 /error/noindex.html + + <% end -%> + diff --git a/apache2/templates/default/mod_auth_openid.rb.erb b/apache2/templates/default/mod_auth_openid.rb.erb new file mode 100644 index 0000000..52dd8b0 --- /dev/null +++ b/apache2/templates/default/mod_auth_openid.rb.erb @@ -0,0 +1,12 @@ +#!/usr/bin/env ruby + +allowed_openids = Array.new +<% @node[:apache][:allowed_openids].each do |id| -%> +allowed_openids << "<%= id %>" +<% end -%> + +if allowed_openids.grep(ARGV[0]) + exit 0 +else + exit 1 +end diff --git a/apache2/templates/default/mods/README b/apache2/templates/default/mods/README new file mode 100644 index 0000000..df9f0bc --- /dev/null +++ b/apache2/templates/default/mods/README @@ -0,0 +1,2 @@ +These configs are taken from a Debian apache2.2-common 2.2.11-3 install. They +work on CentOS 5.3 with a few conditions using erb. diff --git a/apache2/templates/default/mods/alias.conf.erb b/apache2/templates/default/mods/alias.conf.erb new file mode 100644 index 0000000..d70670f --- /dev/null +++ b/apache2/templates/default/mods/alias.conf.erb @@ -0,0 +1,24 @@ + +# +# Aliases: Add here as many aliases as you need (with no limit). The format is +# Alias fakename realname +# +# Note that if you include a trailing / on fakename then the server will +# require it to be present in the URL. So "/icons" isn't aliased in this +# example, only "/icons/". If the fakename is slash-terminated, then the +# realname must also be slash terminated, and if the fakename omits the +# trailing slash, the realname must also omit it. +# +# We include the /icons/ alias for FancyIndexed directory listings. If +# you do not use FancyIndexing, you may comment this out. +# +Alias /icons/ "<%= @node[:apache][:icondir] %>" + +"> + Options Indexes MultiViews + AllowOverride None + Order allow,deny + Allow from all + + + diff --git a/apache2/templates/default/mods/authopenid.load.erb b/apache2/templates/default/mods/authopenid.load.erb new file mode 100644 index 0000000..f21882b --- /dev/null +++ b/apache2/templates/default/mods/authopenid.load.erb @@ -0,0 +1 @@ +LoadModule authopenid_module /usr/lib/apache2/modules/mod_auth_openid.so diff --git a/apache2/templates/default/mods/autoindex.conf.erb b/apache2/templates/default/mods/autoindex.conf.erb new file mode 100644 index 0000000..3839093 --- /dev/null +++ b/apache2/templates/default/mods/autoindex.conf.erb @@ -0,0 +1,101 @@ + +# +# Directives controlling the display of server-generated directory listings. +# + +# +# IndexOptions: Controls the appearance of server-generated directory +# listings. +# Remove/replace the "Charset=UTF-8" if you don't use UTF-8 for your filenames. +# +IndexOptions FancyIndexing VersionSort HTMLTable NameWidth=* DescriptionWidth=* Charset=UTF-8 + +# +# AddIcon* directives tell the server which icon to show for different +# files or filename extensions. These are only displayed for +# FancyIndexed directories. +# +AddIconByEncoding (CMP,/icons/compressed.gif) x-compress x-gzip x-bzip2 + +AddIconByType (TXT,/icons/text.gif) text/* +AddIconByType (IMG,/icons/image2.gif) image/* +AddIconByType (SND,/icons/sound2.gif) audio/* +AddIconByType (VID,/icons/movie.gif) video/* + +AddIcon /icons/binary.gif .bin .exe +AddIcon /icons/binhex.gif .hqx +AddIcon /icons/tar.gif .tar +AddIcon /icons/world2.gif .wrl .wrl.gz .vrml .vrm .iv +AddIcon /icons/compressed.gif .Z .z .tgz .gz .zip +AddIcon /icons/a.gif .ps .ai .eps +AddIcon /icons/layout.gif .html .shtml .htm .pdf +AddIcon /icons/text.gif .txt +AddIcon /icons/c.gif .c +AddIcon /icons/p.gif .pl .py +AddIcon /icons/f.gif .for +AddIcon /icons/dvi.gif .dvi +AddIcon /icons/uuencoded.gif .uu +AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl +AddIcon /icons/tex.gif .tex +# It's a suffix rule, so simply matching "core" matches "score" as well ! +AddIcon /icons/bomb.gif /core +AddIcon (SND,/icons/sound2.gif) .ogg +AddIcon (VID,/icons/movie.gif) .ogm + +AddIcon /icons/back.gif .. +AddIcon /icons/hand.right.gif README +AddIcon /icons/folder.gif ^^DIRECTORY^^ +AddIcon /icons/blank.gif ^^BLANKICON^^ + +# Default icons for OpenDocument format +AddIcon /icons/odf6odt-20x22.png .odt +AddIcon /icons/odf6ods-20x22.png .ods +AddIcon /icons/odf6odp-20x22.png .odp +AddIcon /icons/odf6odg-20x22.png .odg +AddIcon /icons/odf6odc-20x22.png .odc +AddIcon /icons/odf6odf-20x22.png .odf +AddIcon /icons/odf6odb-20x22.png .odb +AddIcon /icons/odf6odi-20x22.png .odi +AddIcon /icons/odf6odm-20x22.png .odm + +AddIcon /icons/odf6ott-20x22.png .ott +AddIcon /icons/odf6ots-20x22.png .ots +AddIcon /icons/odf6otp-20x22.png .otp +AddIcon /icons/odf6otg-20x22.png .otg +AddIcon /icons/odf6otc-20x22.png .otc +AddIcon /icons/odf6otf-20x22.png .otf +AddIcon /icons/odf6oti-20x22.png .oti +AddIcon /icons/odf6oth-20x22.png .oth + +# +# DefaultIcon is which icon to show for files which do not have an icon +# explicitly set. +# +DefaultIcon /icons/unknown.gif + +# +# AddDescription allows you to place a short description after a file in +# server-generated indexes. These are only displayed for FancyIndexed +# directories. +# Format: AddDescription "description" filename +# +#AddDescription "GZIP compressed document" .gz +#AddDescription "tar archive" .tar +#AddDescription "GZIP compressed tar archive" .tgz + +# +# ReadmeName is the name of the README file the server will look for by +# default, and append to directory listings. +# +# HeaderName is the name of a file which should be prepended to +# directory indexes. +ReadmeName README.html +HeaderName HEADER.html + +# +# IndexIgnore is a set of filenames which directory indexing should ignore +# and not include in the listing. Shell-style wildcarding is permitted. +# +IndexIgnore .??* *~ *# RCS CVS *,v *,t + + diff --git a/apache2/templates/default/mods/deflate.conf.erb b/apache2/templates/default/mods/deflate.conf.erb new file mode 100644 index 0000000..2e41975 --- /dev/null +++ b/apache2/templates/default/mods/deflate.conf.erb @@ -0,0 +1,16 @@ + + AddOutputFilterByType DEFLATE text/html + AddOutputFilterByType DEFLATE text/css + AddOutputFilterByType DEFLATE text/plain + AddOutputFilterByType DEFLATE text/xml + AddOutputFilterByType DEFLATE application/xhtml+xml + AddOutputFilterByType DEFLATE application/xml + AddOutputFilterByType DEFLATE image/svg+xml + AddOutputFilterByType DEFLATE application/rss+xml + AddOutputFilterByType DEFLATE application/atom_xml + AddOutputFilterByType DEFLATE application/javascript + AddOutputFilterByType DEFLATE application/x-javascript + AddOutputFilterByType DEFLATE application/x-httpd-php + AddOutputFilterByType DEFLATE application/x-httpd-fastphp + AddOutputFilterByType DEFLATE application/x-httpd-eruby + diff --git a/apache2/templates/default/mods/dir.conf.erb b/apache2/templates/default/mods/dir.conf.erb new file mode 100644 index 0000000..e16fcb3 --- /dev/null +++ b/apache2/templates/default/mods/dir.conf.erb @@ -0,0 +1,5 @@ + + + DirectoryIndex index.html index.cgi index.pl index.php index.xhtml index.htm + + diff --git a/apache2/templates/default/mods/fcgid.conf.erb b/apache2/templates/default/mods/fcgid.conf.erb new file mode 100644 index 0000000..2141141 --- /dev/null +++ b/apache2/templates/default/mods/fcgid.conf.erb @@ -0,0 +1,10 @@ + + AddHandler fcgid-script .fcgi + IPCConnectTimeout 20 + + +<% if @node[:platform] == "centos" || @node[:platform] == "redhat" || @node[:platform] == "fedora" -%> +# Sane place to put sockets and shared memory file +SocketPath run/mod_fcgid +SharememPath run/mod_fcgid/fcgid_shm +<% end -%> diff --git a/apache2/templates/default/mods/mime.conf.erb b/apache2/templates/default/mods/mime.conf.erb new file mode 100644 index 0000000..b6954a3 --- /dev/null +++ b/apache2/templates/default/mods/mime.conf.erb @@ -0,0 +1,191 @@ + + +# +# TypesConfig points to the file containing the list of mappings from +# filename extension to MIME-type. +# +TypesConfig /etc/mime.types + +# +# AddType allows you to add to or override the MIME configuration +# file mime.types for specific file types. +# +#AddType application/x-gzip .tgz +# +# AddEncoding allows you to have certain browsers uncompress +# information on the fly. Note: Not all browsers support this. +# Despite the name similarity, the following Add* directives have +# nothing to do with the FancyIndexing customization directives above. +# +#AddEncoding x-compress .Z +#AddEncoding x-gzip .gz .tgz +#AddEncoding x-bzip2 .bz2 +# +# If the AddEncoding directives above are commented-out, then you +# probably should define those extensions to indicate media types: +# +AddType application/x-compress .Z +AddType application/x-gzip .gz .tgz +AddType application/x-bzip2 .bz2 + +# +# DefaultLanguage and AddLanguage allows you to specify the language of +# a document. You can then use content negotiation to give a browser a +# file in a language the user can understand. +# +# Specify a default language. This means that all data +# going out without a specific language tag (see below) will +# be marked with this one. You probably do NOT want to set +# this unless you are sure it is correct for all cases. +# +# * It is generally better to not mark a page as +# * being a certain language than marking it with the wrong +# * language! +# +# DefaultLanguage nl +# +# Note 1: The suffix does not have to be the same as the language +# keyword --- those with documents in Polish (whose net-standard +# language code is pl) may wish to use "AddLanguage pl .po" to +# avoid the ambiguity with the common suffix for perl scripts. +# +# Note 2: The example entries below illustrate that in some cases +# the two character 'Language' abbreviation is not identical to +# the two character 'Country' code for its country, +# E.g. 'Danmark/dk' versus 'Danish/da'. +# +# Note 3: In the case of 'ltz' we violate the RFC by using a three char +# specifier. There is 'work in progress' to fix this and get +# the reference data for rfc1766 cleaned up. +# +# Catalan (ca) - Croatian (hr) - Czech (cs) - Danish (da) - Dutch (nl) +# English (en) - Esperanto (eo) - Estonian (et) - French (fr) - German (de) +# Greek-Modern (el) - Hebrew (he) - Italian (it) - Japanese (ja) +# Korean (ko) - Luxembourgeois* (ltz) - Norwegian Nynorsk (nn) +# Norwegian (no) - Polish (pl) - Portugese (pt) +# Brazilian Portuguese (pt-BR) - Russian (ru) - Swedish (sv) +# Simplified Chinese (zh-CN) - Spanish (es) - Traditional Chinese (zh-TW) +# +AddLanguage ca .ca +AddLanguage cs .cz .cs +AddLanguage da .dk +AddLanguage de .de +AddLanguage el .el +AddLanguage en .en +AddLanguage eo .eo +# See README.Debian for Spanish +AddLanguage es .es +AddLanguage et .et +AddLanguage fr .fr +AddLanguage he .he +AddLanguage hr .hr +AddLanguage it .it +AddLanguage ja .ja +AddLanguage ko .ko +AddLanguage ltz .ltz +AddLanguage nl .nl +AddLanguage nn .nn +AddLanguage no .no +AddLanguage pl .po +AddLanguage pt .pt +AddLanguage pt-BR .pt-br +AddLanguage ru .ru +AddLanguage sv .sv +# See README.Debian for Turkish +AddLanguage tr .tr +AddLanguage zh-CN .zh-cn +AddLanguage zh-TW .zh-tw + +# +# Commonly used filename extensions to character sets. You probably +# want to avoid clashes with the language extensions, unless you +# are good at carefully testing your setup after each change. +# See http://www.iana.org/assignments/character-sets for the +# official list of charset names and their respective RFCs. +# +AddCharset us-ascii .ascii .us-ascii +AddCharset ISO-8859-1 .iso8859-1 .latin1 +AddCharset ISO-8859-2 .iso8859-2 .latin2 .cen +AddCharset ISO-8859-3 .iso8859-3 .latin3 +AddCharset ISO-8859-4 .iso8859-4 .latin4 +AddCharset ISO-8859-5 .iso8859-5 .cyr .iso-ru +AddCharset ISO-8859-6 .iso8859-6 .arb .arabic +AddCharset ISO-8859-7 .iso8859-7 .grk .greek +AddCharset ISO-8859-8 .iso8859-8 .heb .hebrew +AddCharset ISO-8859-9 .iso8859-9 .latin5 .trk +AddCharset ISO-8859-10 .iso8859-10 .latin6 +AddCharset ISO-8859-13 .iso8859-13 +AddCharset ISO-8859-14 .iso8859-14 .latin8 +AddCharset ISO-8859-15 .iso8859-15 .latin9 +AddCharset ISO-8859-16 .iso8859-16 .latin10 +AddCharset ISO-2022-JP .iso2022-jp .jis +AddCharset ISO-2022-KR .iso2022-kr .kis +AddCharset ISO-2022-CN .iso2022-cn .cis +AddCharset Big5 .Big5 .big5 .b5 +AddCharset cn-Big5 .cn-big5 +# For russian, more than one charset is used (depends on client, mostly): +AddCharset WINDOWS-1251 .cp-1251 .win-1251 +AddCharset CP866 .cp866 +AddCharset KOI8 .koi8 +AddCharset KOI8-E .koi8-e +AddCharset KOI8-r .koi8-r .koi8-ru +AddCharset KOI8-U .koi8-u +AddCharset KOI8-ru .koi8-uk .ua +AddCharset ISO-10646-UCS-2 .ucs2 +AddCharset ISO-10646-UCS-4 .ucs4 +AddCharset UTF-7 .utf7 +AddCharset UTF-8 .utf8 +AddCharset UTF-16 .utf16 +AddCharset UTF-16BE .utf16be +AddCharset UTF-16LE .utf16le +AddCharset UTF-32 .utf32 +AddCharset UTF-32BE .utf32be +AddCharset UTF-32LE .utf32le +AddCharset euc-cn .euc-cn +AddCharset euc-gb .euc-gb +AddCharset euc-jp .euc-jp +AddCharset euc-kr .euc-kr +#Not sure how euc-tw got in - IANA doesn't list it??? +AddCharset EUC-TW .euc-tw +AddCharset gb2312 .gb2312 .gb +AddCharset iso-10646-ucs-2 .ucs-2 .iso-10646-ucs-2 +AddCharset iso-10646-ucs-4 .ucs-4 .iso-10646-ucs-4 +AddCharset shift_jis .shift_jis .sjis + +# +# AddHandler allows you to map certain file extensions to "handlers": +# actions unrelated to filetype. These can be either built into the server +# or added with the Action directive (see below) +# +# To use CGI scripts outside of ScriptAliased directories: +# (You will also need to add "ExecCGI" to the "Options" directive.) +# +#AddHandler cgi-script .cgi + +# +# For files that include their own HTTP headers: +# +#AddHandler send-as-is asis + +# +# For server-parsed imagemap files: +# +#AddHandler imap-file map + +# +# For type maps (negotiated resources): +# (This is enabled by default to allow the Apache "It Worked" page +# to be distributed in multiple languages.) +# +AddHandler type-map var + +# +# Filters allow you to process content before it is sent to the client. +# +# To parse .shtml files for server-side includes (SSI): +# (You will also need to add "Includes" to the "Options" directive.) +# +AddType text/html .shtml +AddOutputFilter INCLUDES .shtml + + diff --git a/apache2/templates/default/mods/negotiation.conf.erb b/apache2/templates/default/mods/negotiation.conf.erb new file mode 100644 index 0000000..0e3455b --- /dev/null +++ b/apache2/templates/default/mods/negotiation.conf.erb @@ -0,0 +1,18 @@ + +# +# LanguagePriority allows you to give precedence to some languages +# in case of a tie during content negotiation. +# +# Just list the languages in decreasing order of preference. We have +# more or less alphabetized them here. You probably want to change this. +# +LanguagePriority en ca cs da de el eo es et fr he hr it ja ko ltz nl nn no pl pt pt-BR ru sv tr zh-CN zh-TW + +# +# ForceLanguagePriority allows you to serve a result page rather than +# MULTIPLE CHOICES (Prefer) [in case of a tie] or NOT ACCEPTABLE (Fallback) +# [in case no accepted languages matched the available variants] +# +ForceLanguagePriority Prefer Fallback + + diff --git a/apache2/templates/default/mods/proxy.conf.erb b/apache2/templates/default/mods/proxy.conf.erb new file mode 100644 index 0000000..46407a1 --- /dev/null +++ b/apache2/templates/default/mods/proxy.conf.erb @@ -0,0 +1,19 @@ + + #turning ProxyRequests on and allowing proxying from all may allow + #spammers to use your proxy to send email. + + ProxyRequests Off + + + AddDefaultCharset off + Order deny,allow + Deny from all + #Allow from .example.com + + + # Enable/disable the handling of HTTP/1.1 "Via:" headers. + # ("Full" adds the server version; "Block" removes all outgoing Via: headers) + # Set to one of: Off | On | Full | Block + + ProxyVia On + diff --git a/apache2/templates/default/mods/setenvif.conf.erb b/apache2/templates/default/mods/setenvif.conf.erb new file mode 100644 index 0000000..6b7d6e2 --- /dev/null +++ b/apache2/templates/default/mods/setenvif.conf.erb @@ -0,0 +1,28 @@ + + +# +# The following directives modify normal HTTP response behavior to +# handle known problems with browser implementations. +# +BrowserMatch "Mozilla/2" nokeepalive +BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0 +BrowserMatch "RealPlayer 4\.0" force-response-1.0 +BrowserMatch "Java/1\.0" force-response-1.0 +BrowserMatch "JDK/1\.0" force-response-1.0 + +# +# The following directive disables redirects on non-GET requests for +# a directory that does not include the trailing slash. This fixes a +# problem with Microsoft WebFolders which does not appropriately handle +# redirects for folders with DAV methods. +# Same deal with Apple's DAV filesystem and Gnome VFS support for DAV. +# +BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully +BrowserMatch "MS FrontPage" redirect-carefully +BrowserMatch "^WebDrive" redirect-carefully +BrowserMatch "^WebDAVFS/1.[012]" redirect-carefully +BrowserMatch "^gnome-vfs/1.0" redirect-carefully +BrowserMatch "^XML Spy" redirect-carefully +BrowserMatch "^Dreamweaver-WebDAV-SCM1" redirect-carefully + + diff --git a/apache2/templates/default/mods/ssl.conf.erb b/apache2/templates/default/mods/ssl.conf.erb new file mode 100644 index 0000000..14f72a6 --- /dev/null +++ b/apache2/templates/default/mods/ssl.conf.erb @@ -0,0 +1,72 @@ + +# +# Pseudo Random Number Generator (PRNG): +# Configure one or more sources to seed the PRNG of the SSL library. +# The seed data should be of good random quality. +# WARNING! On some platforms /dev/random blocks if not enough entropy +# is available. This means you then cannot use the /dev/random device +# because it would lead to very long connection times (as long as +# it requires to make more entropy available). But usually those +# platforms additionally provide a /dev/urandom device which doesn't +# block. So, if available, use this one instead. Read the mod_ssl User +# Manual for more details. +# +SSLRandomSeed startup builtin +SSLRandomSeed startup file:/dev/urandom 512 +SSLRandomSeed connect builtin +SSLRandomSeed connect file:/dev/urandom 512 + +## +## SSL Global Context +## +## All SSL configuration in this context applies both to +## the main server and all SSL-enabled virtual hosts. +## + +# +# Some MIME-types for downloading Certificates and CRLs +# +AddType application/x-x509-ca-cert .crt +AddType application/x-pkcs7-crl .crl + +# Pass Phrase Dialog: +# Configure the pass phrase gathering process. +# The filtering dialog program (`builtin' is a internal +# terminal dialog) has to provide the pass phrase on stdout. +SSLPassPhraseDialog builtin + +# Inter-Process Session Cache: +# Configure the SSL Session Cache: First the mechanism +# to use and second the expiring timeout (in seconds). +#SSLSessionCache dbm:/var/run/apache2/ssl_scache +<% if @node[:platform] == "centos" || @node[:platform] == "redhat" || @node[:platform] == "fedora" -%> +SSLSessionCache shmcb:/var/cache/mod_ssl/scache(512000) +<% else -%> +SSLSessionCache shmcb:/var/run/apache2/ssl_scache +<% end -%> +SSLSessionCacheTimeout 300 + +# Semaphore: +# Configure the path to the mutual exclusion semaphore the +# SSL engine uses internally for inter-process synchronization. +<% if @node[:platform] == "centos" || @node[:platform] == "redhat" || @node[:platform] == "fedora" -%> +SSLMutex default +<% else -%> +SSLMutex file:/var/run/apache2/ssl_mutex +<% end -%> + +# SSL Cipher Suite: +# List the ciphers that the client is permitted to negotiate. +# See the mod_ssl documentation for a complete list. +# enable only secure ciphers: +SSLCipherSuite HIGH:MEDIUM:!ADH +# Use this instead if you want to allow cipher upgrades via SGC facility. +# In this case you also have to use something like +# SSLRequire %{SSL_CIPHER_USEKEYSIZE} >= 128 +# see http://httpd.apache.org/docs/2.2/ssl/ssl_howto.html.en#upgradeenc +#SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL + +# enable only secure protocols: SSLv3 and TLSv1, but not SSLv2 +SSLProtocol all -SSLv2 + + diff --git a/apache2/templates/default/mods/status.conf.erb b/apache2/templates/default/mods/status.conf.erb new file mode 100644 index 0000000..679d111 --- /dev/null +++ b/apache2/templates/default/mods/status.conf.erb @@ -0,0 +1,16 @@ + +# +# Allow server status reports generated by mod_status, +# with the URL of http://servername/server-status +# Uncomment and change the ".example.com" to allow +# access from other hosts. +# + + SetHandler server-status + Order deny,allow + Deny from all + Allow from localhost ip6-localhost +# Allow from .example.com + + + diff --git a/apache2/templates/default/port_apache.erb b/apache2/templates/default/port_apache.erb new file mode 100644 index 0000000..f6078dd --- /dev/null +++ b/apache2/templates/default/port_apache.erb @@ -0,0 +1,2 @@ +# Port <%= @port %> +-A FWR -p tcp -m tcp --dport <%= @port %> -j ACCEPT \ No newline at end of file diff --git a/apache2/templates/default/ports.conf.erb b/apache2/templates/default/ports.conf.erb new file mode 100644 index 0000000..cc3631e --- /dev/null +++ b/apache2/templates/default/ports.conf.erb @@ -0,0 +1,6 @@ +#This file generated via template by Chef. +<% @apache_listen_ports.each do |port| -%> +Listen <%= port %> +NameVirtualHost *:<%= port %> + +<% end -%> diff --git a/apache2/templates/default/security.erb b/apache2/templates/default/security.erb new file mode 100644 index 0000000..dbb1a47 --- /dev/null +++ b/apache2/templates/default/security.erb @@ -0,0 +1,50 @@ +# +# Disable access to the entire file system except for the directories that +# are explicitly allowed later. +# +# This currently breaks the configurations that come with some web application +# Debian packages. It will be made the default for the release after lenny. +# +# +# AllowOverride None +# Order Deny,Allow +# Deny from all +# + + +# Changing the following options will not really affect the security of the +# server, but might make attacks slightly more difficult in some cases. + +# +# ServerTokens +# This directive configures what you return as the Server HTTP response +# Header. The default is 'Full' which sends information about the OS-Type +# and compiled in modules. +# Set to one of: Full | OS | Minimal | Minor | Major | Prod +# where Full conveys the most information, and Prod the least. +# +#ServerTokens Minimal +ServerTokens <%= @node[:apache][:servertokens] %> + +# +# Optionally add a line containing the server version and virtual host +# name to server-generated pages (internal error documents, FTP directory +# listings, mod_status and mod_info output etc., but not CGI generated +# documents or custom error documents). +# Set to "EMail" to also include a mailto: link to the ServerAdmin. +# Set to one of: On | Off | EMail +# +#ServerSignature Off +ServerSignature <%= @node[:apache][:serversignature] %> + +# +# Allow TRACE method +# +# Set to "extended" to also reflect the request body (only for testing and +# diagnostic purposes). +# +# Set to one of: On | Off | extended +# +#TraceEnable Off +TraceEnable <%= @node[:apache][:traceenable] %> + diff --git a/apache2/templates/default/web_app.conf.erb b/apache2/templates/default/web_app.conf.erb new file mode 100644 index 0000000..d6a12c4 --- /dev/null +++ b/apache2/templates/default/web_app.conf.erb @@ -0,0 +1,43 @@ + + ServerName <%= @params[:server_name] %> + ServerAlias <% @params[:server_aliases].each do |a| %><%= "#{a}" %> <% end %> + DocumentRoot <%= @params[:docroot] %> + RewriteEngine On + + > + Options FollowSymLinks + AllowOverride None + Order allow,deny + Allow from all + + + + Options FollowSymLinks + AllowOverride None + + + + SetHandler server-status + + Order Deny,Allow + Deny from all + Allow from 127.0.0.1 + + + LogLevel info + ErrorLog <%= @node[:apache][:log_dir] %>/<%= @params[:name] %>-error.log + CustomLog <%= @node[:apache][:log_dir] %>/<%= @params[:name] %>-access.log combined + + RewriteEngine On + RewriteLog <%= @node[:apache][:log_dir] %>/<%= @application_name %>-rewrite.log + RewriteLogLevel 0 + + # Canonical host, <%= @params[:server_name] %> + RewriteCond %{HTTP_HOST} !^<%= @params[:server_name] %> [NC] + RewriteCond %{HTTP_HOST} !^$ + RewriteRule ^/(.*)$ http://<%= @params[:server_name] %>/$1 [L,R=301] + + RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f + RewriteCond %{SCRIPT_FILENAME} !maintenance.html + RewriteRule ^.*$ /system/maintenance.html [L] + \ No newline at end of file diff --git a/apparmor/metadata.json b/apparmor/metadata.json new file mode 100644 index 0000000..01bfb09 --- /dev/null +++ b/apparmor/metadata.json @@ -0,0 +1,40 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Disables apparmor service on Ubuntu", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "apparmor": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ] + }, + "version": "0.7.0", + "name": "apparmor", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "apparmor": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/apparmor/metadata.rb b/apparmor/metadata.rb new file mode 100644 index 0000000..d225763 --- /dev/null +++ b/apparmor/metadata.rb @@ -0,0 +1,6 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Disables apparmor service on Ubuntu" +version "0.8" +supports "ubuntu" diff --git a/apparmor/recipes/default.rb b/apparmor/recipes/default.rb new file mode 100644 index 0000000..bbdb43b --- /dev/null +++ b/apparmor/recipes/default.rb @@ -0,0 +1,26 @@ +# +# Author:: Joshua Timberman () +# Cookbook Name:: apparmor +# Recipe:: default +# +# Copyright 2009, Opscode, 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. +# + +case node[:platform] +when "ubuntu" + service "apparmor" do + action [ :stop, :disable ] + end +end diff --git a/apt/files/default/apt-cacher b/apt/files/default/apt-cacher new file mode 100644 index 0000000..dab9488 --- /dev/null +++ b/apt/files/default/apt-cacher @@ -0,0 +1,9 @@ +# apt-cacher startup configuration file + +# IMPORTANT: check the apt-cacher.conf file before using apt-cacher as daemon. + +# set to 1 to start the daemon at boot time +AUTOSTART=1 + +# extra settings to override the ones in apt-cacher.conf +# EXTRAOPT=" daemon_port=3142 limit=30 " diff --git a/apt/files/default/apt-cacher.conf b/apt/files/default/apt-cacher.conf new file mode 100644 index 0000000..32ca3c3 --- /dev/null +++ b/apt/files/default/apt-cacher.conf @@ -0,0 +1,144 @@ +# This file has been modified by ./apt-proxy-to-apt-cacher +# Some lines may have been appended at the bottom of this file +# This file has been modified by /usr/share/apt-cacher/apt-proxy-to-apt-cacher +# Some lines may have been appended at the bottom of this file +################################################################# +# This is the config file for apt-cacher. On most Debian systems +# you can safely leave the defaults alone. +################################################################# + +# cache_dir is used to set the location of the local cache. This can +# become quite large, so make sure it is somewhere with plenty of space. +cache_dir=/var/cache/apt-cacher + +# The email address of the administrator is displayed in the info page +# and traffic reports. +admin_email=root@localhost + +# For the daemon startup settings please edit the file /etc/default/apt-cacher. + +# Daemon port setting, only useful in stand-alone mode. You need to run the +# daemon as root to use privileged ports (<1024). +daemon_port = 3142 + +# optional settings, user and group to run the daemon as. Make sure they have +# sufficient permissions on the cache and log directories. Comment the settings +# to run apt-cacher as the native user. +group=www-data +user=www-data + +# optional setting, binds the listening daemon to one specified IP. Use IP +# ranges for more advanced configuration, see below. +# daemon_addr=localhost + +# If your apt-cacher machine is directly exposed to the Internet and you are +# worried about unauthorised machines fetching packages through it, you can +# specify a list of IPv4 addresses which are allowed to use it and another +# list of IPv4 addresses which aren't. +# Localhost (127.0.0.1) is always allowed. Other addresses must be matched +# by allowed_hosts and not by denied_hosts to be permitted to use the cache. +# Setting allowed_hosts to "*" means "allow all". +# Otherwise the format is a comma-separated list containing addresses, +# optionally with masks (like 10.0.0.0/22), or ranges of addresses (two +# addresses separated by a hyphen, no masks, like '192.168.0.3-192.168.0.56'). +allowed_hosts=* +denied_hosts= + +# And similiarly for IPv6 with allowed_hosts_6 and denied_hosts_6. +# Note that IPv4-mapped IPv6 addresses (::ffff:w.x.y.z) are truncated to +# w.x.y.z and are handled as IPv4. +allowed_hosts_6=fec0::/16 +denied_hosts_6= + +# This thing can be done by Apache but is much simplier here - limit access to +# Debian mirrors based on server names in the URLs +#allowed_locations=ftp.uni-kl.de,ftp.nerim.net,debian.tu-bs.de + +# Apt-cacher can generate usage reports every 24 hours if you set this +# directive to 1. You can view the reports in a web browser by pointing +# to your cache machine with '/apt-cacher/report' on the end, like this: +# http://yourcache.example.com/apt-cacher/report +# Generating reports is very fast even with many thousands of logfile +# lines, so you can safely turn this on without creating much +# additional system load. +generate_reports=1 + +# Apt-cacher can clean up its cache directory every 24 hours if you set +# this directive to 1. Cleaning the cache can take some time to run +# (generally in the order of a few minutes) and removes all package +# files that are not mentioned in any existing 'Packages' lists. This +# has the effect of deleting packages that have been superseded by an +# updated 'Packages' list. +clean_cache=1 + +# The directory to use for apt-cacher access and error logs. +# The access log records every request in the format: +# date-time|client ip address|HIT/MISS/EXPIRED|object size|object name +# The error log is slightly more free-form, and is also used for debug +# messages if debug mode is turned on. +# Note that the old 'logfile' and 'errorfile' directives are +# deprecated: if you set them explicitly they will be honoured, but it's +# better to just get rid of them from old config files. +logdir=/var/log/apt-cacher + +# apt-cacher can use different methods to decide whether package lists need to +# be updated, +# A) looking at the age of the cached files +# B) getting HTTP header from server and comparing that with cached data. This +# method is more reliable and avoids desynchronisation of data and index files +# but needs to transfer few bytes from the server every time somebody requests +# the files ("apt-get update") +# Set the following value to the maximum age (in hours) for method A or to 0 +# for method B +expire_hours=0 + +# Apt-cacher can pass all its requests to an external http proxy like +# Squid, which could be very useful if you are using an ISP that blocks +# port 80 and requires all web traffic to go through its proxy. The +# format is 'hostname:port', eg: 'proxy.example.com:8080'. +http_proxy=proxy.example.com:8080 + +# Use of an external proxy can be turned on or off with this flag. +# Value should be either 0 (off) or 1 (on). +use_proxy=0 + +# External http proxy sometimes need authentication to get full access. The +# format is 'username:password'. +http_proxy_auth=proxyuser:proxypass + +# Use of external proxy authentication can be turned on or off with this flag. +# Value should be either 0 (off) or 1 (on). +use_proxy_auth=0 + +# Rate limiting sets the maximum bandwidth in bytes per second to use +# for fetching packages. Syntax is fully defined in 'man wget'. +# Use 'k' or 'm' to use kilobits or megabits / second: eg, 'limit=25k'. +# Use 0 or a negative value for no rate limiting. +limit=0 + +# Debug mode makes apt-cacher spew a lot of extra debug junk to the +# error log (whose location is defined with the 'logdir' directive). +# Leave this off unless you need it, or your error log will get very +# big. Acceptable values are 0 or 1. +debug=0 + +# Adapt the line in the usage info web page to match your server configuration +# example_sources_line=deb http://my.cacher.server:3142/ftp.au.debian.org/debian unstable main contrib non-free + +# Print a 410 (Gone) HTTP message with the specified text when accessed via +# CGI. Useful to tell users to adapt their sources.list files when the +# apt-cacher server is beeing relocated (via apt-get's error messages while +# running "update") +#cgi_advise_to_use = Please use http://cacheserver:3142/ as apt-cacher access URL +#cgi_advise_to_use = Server relocated. To change sources.list, run perl -pe "s,/apt-cacher\??,:3142," -i /etc/apt/sources.list + +# Server mapping - this allows to hide real server names behind virtual paths +# that appear in the access URL. This method is known from apt-proxy. This is +# also the only method to use FTP access to the target hosts. The syntax is simple, the part of the beginning to replace, followed by a list of mirror urls, all space separated. Multiple profile are separated by semicolons +# path_map = debian ftp.uni-kl.de/pub/linux/debian ftp2.de.debian.org/debian ; ubuntu archive.ubuntu.com/ubuntu ; security security.debian.org/debian-security ftp2.de.debian.org/debian-security +# Note that you need to specify all target servers in the allowed_locations +# options if you make use of it. Also note that the paths should not overlap +# each other. FTP access method not supported yet, maybe in the future. + +# extra setting from apt-proxy configuration +path_map = ubuntu us.archive.ubuntu.com/ubuntu ; ubuntu-security security.ubuntu.com/ubuntu ; debian debian.osuosl.org/debian/ ; security security.debian.org/debian-security diff --git a/apt/files/default/apt-proxy-v2.conf b/apt/files/default/apt-proxy-v2.conf new file mode 100644 index 0000000..6541f25 --- /dev/null +++ b/apt/files/default/apt-proxy-v2.conf @@ -0,0 +1,50 @@ +[DEFAULT] +;; All times are in seconds, but you can add a suffix +;; for minutes(m), hours(h) or days(d) + +;; commented out address so apt-proxy will listen on all IPs +;; address = 127.0.0.1 +port = 9999 +cache_dir = /var/cache/apt-proxy + +;; Control files (Packages/Sources/Contents) refresh rate +min_refresh_delay = 1s +complete_clientless_downloads = 1 + +;; Debugging settings. +debug = all:4 db:0 + +time = 30 +passive_ftp = on + +;;-------------------------------------------------------------- +;; Cache housekeeping + +cleanup_freq = 1d +max_age = 120d +max_versions = 3 + +;;--------------------------------------------------------------- +;; Backend servers +;; +;; Place each server in its own [section] + +[ubuntu] +; Ubuntu archive +backends = + http://us.archive.ubuntu.com/ubuntu + +[ubuntu-security] +; Ubuntu security updates +backends = http://security.ubuntu.com/ubuntu + +[debian] +;; Backend servers, in order of preference +backends = + http://debian.osuosl.org/debian/ + +[security] +;; Debian security archive +backends = + http://security.debian.org/debian-security + http://ftp2.de.debian.org/debian-security diff --git a/apt/metadata.json b/apt/metadata.json new file mode 100644 index 0000000..c37fe61 --- /dev/null +++ b/apt/metadata.json @@ -0,0 +1,51 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Configures apt and apt services", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "apt::proxy": "Set up an APT proxy", + "apt": "", + "apt::cacher": "Set up an APT cache" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "debian": [ + + ] + }, + "version": "0.8.0", + "name": "apt", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "apt::proxy": [ + + ], + "apt": [ + + ], + "apt::cacher": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/apt/metadata.rb b/apt/metadata.rb new file mode 100644 index 0000000..cb6e712 --- /dev/null +++ b/apt/metadata.rb @@ -0,0 +1,11 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Configures apt and apt services" +version "0.8" +recipe "apt::cacher", "Set up an APT cache" +recipe "apt::proxy", "Set up an APT proxy" + +%w{ ubuntu debian }.each do |os| + supports os +end diff --git a/apt/recipes/cacher.rb b/apt/recipes/cacher.rb new file mode 100644 index 0000000..2377408 --- /dev/null +++ b/apt/recipes/cacher.rb @@ -0,0 +1,42 @@ +# +# Cookbook Name:: apt +# Recipe:: cacher +# +# Copyright 2008-2009, Opscode, 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 "apt-cacher" do + action :install +end + +service "apt-cacher" do + supports :restart => true, :status => false + action [ :enable, :start ] +end + +remote_file "/etc/apt-cacher/apt-cacher.conf" do + source "apt-cacher.conf" + owner "root" + group "root" + mode 0644 + notifies :restart, resources(:service => "apt-cacher") +end + +remote_file "/etc/default/apt-cacher" do + source "apt-cacher" + owner "root" + group "root" + mode 0644 + notifies :restart, resources(:service => "apt-cacher") +end diff --git a/apt/recipes/default.rb b/apt/recipes/default.rb new file mode 100644 index 0000000..d1117a7 --- /dev/null +++ b/apt/recipes/default.rb @@ -0,0 +1,33 @@ +# +# Cookbook Name:: apt +# Recipe:: default +# +# Copyright 2008-2009, Opscode, 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. +# + +e = execute "apt-get update" do + action :nothing +end + +e.run_action(:run) + +%w{/var/cache/local /var/cache/local/preseeding}.each do |dirname| + directory dirname do + owner "root" + group "root" + mode 0755 + action :create + end +end diff --git a/apt/recipes/proxy.rb b/apt/recipes/proxy.rb new file mode 100644 index 0000000..3eede34 --- /dev/null +++ b/apt/recipes/proxy.rb @@ -0,0 +1,34 @@ +# +# Cookbook Name:: apt +# Recipe:: proxy +# +# Copyright 2008-2009, Opscode, 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 "apt-proxy" do + action :install +end + +service "apt-proxy" do + supports :restart => true, :status => false + action [ :enable, :start ] +end + +remote_file "/etc/apt-proxy/apt-proxy-v2.conf" do + source "apt-proxy-v2.conf" + owner "root" + group "root" + mode 0644 + notifies :restart, resources(:service => "apt-proxy") +end diff --git a/aws/libraries/ec2.rb b/aws/libraries/ec2.rb new file mode 100644 index 0000000..b7c2a46 --- /dev/null +++ b/aws/libraries/ec2.rb @@ -0,0 +1,56 @@ +# TODO: once sync_libraries properly handles sub-directories, move this file to aws/libraries/opscode/aws/ec2.rb + +begin + require 'right_aws' +rescue LoadError + Chef::Log.warn("Missing gem 'right_aws'") +end + +require 'open-uri' + +module Opscode + module Aws + module Ec2 + def find_snapshot_id(volume_id="") + snapshot_id = nil + ec2.describe_snapshots.sort { |a,b| b[:aws_started_at] <=> a[:aws_started_at] }.each do |snapshot| + if snapshot[:aws_volume_id] == volume_id + snapshot_id = snapshot[:aws_id] + end + end + raise "Cannot find snapshot id!" unless snapshot_id + Chef::Log.debug("Snapshot ID is #{snapshot_id}") + snapshot_id + end + + def ec2 + @@ec2 ||= RightAws::Ec2.new(new_resource.aws_access_key, new_resource.aws_secret_access_key, { :logger => Chef::Log }) + end + + def instance_id + @@instance_id ||= query_instance_id + end + + def instance_availability_zone + @@instance_availability_zone ||= query_instance_availability_zone + end + + private + + def query_instance_id + instance_id = open('http://169.254.169.254/latest/meta-data/instance-id'){|f| f.gets} + raise "Cannot find instance id!" unless instance_id + Chef::Log.debug("Instance ID is #{instance_id}") + instance_id + end + + def query_instance_availability_zone + availability_zone = open('http://169.254.169.254/latest/meta-data/placement/availability-zone/'){|f| f.gets} + raise "Cannot find availability zone!" unless availability_zone + Chef::Log.debug("Instance's availability zone is #{availability_zone}") + availability_zone + end + + end + end +end diff --git a/aws/providers/ebs_volume.rb b/aws/providers/ebs_volume.rb new file mode 100644 index 0000000..75b7059 --- /dev/null +++ b/aws/providers/ebs_volume.rb @@ -0,0 +1,222 @@ +include Opscode::Aws::Ec2 + +action :create do + raise "Cannot create a volume with a specific id (EC2 chooses volume ids)" if new_resource.volume_id + if new_resource.snapshot_id =~ /vol/ + new_resource.snapshot_id(find_snapshot_id(new_resource.snapshot_id)) + end + + nvid = volume_id_in_node_data + if nvid + # volume id is registered in the node data, so check that the volume in fact exists in EC2 + vol = volume_by_id(nvid) + exists = vol && vol[:aws_status] != "deleting" + # TODO: determine whether this should be an error or just cause a new volume to be created. Currently erring on the side of failing loudly + raise "Volume with id #{nvid} is registered with the node but does not exist in EC2. To clear this error, remove the ['aws']['ebs_volume']['#{new_resource.name}']['volume_id'] entry from this node's data." unless exists + else + # Determine if there is a volume that meets the resource's specifications and is attached to the current + # instance in case a previous [:create, :attach] run created and attached a volume but for some reason was + # not registered in the node data (e.g. an exception is thrown after the attach_volume request was accepted + # by EC2, causing the node data to not be stored on the server) + if new_resource.device && (attached_volume = currently_attached_volume(instance_id, new_resource.device)) + Chef::Log.debug("There is already a volume attached at device #{new_resource.device}") + compatible = volume_compatible_with_resource_definition?(attached_volume) + raise "Volume #{attached_volume[:aws_id]} attached at #{attached_volume[:aws_device]} but does not conform to this resource's specifications" unless compatible + Chef::Log.debug("The volume matches the resource's definition, so the volume is assumed to be already created") + node.set[:aws][:ebs_volume][new_resource.name][:volume_id] = attached_volume[:aws_id] + else + # If not, create volume and register its id in the node data + nvid = create_volume(new_resource.snapshot_id, new_resource.size, new_resource.availability_zone, new_resource.timeout) + node.set[:aws][:ebs_volume][new_resource.name][:volume_id] = nvid + new_resource.updated = true + end + node.save + end +end + +action :attach do + vol = determine_volume + + if vol[:aws_status] == "in-use" + if vol[:aws_instance_id] != instance_id + raise "Volume with id #{vol[:aws_id]} exists but is attached to instance #{vol[:aws_instance_id]}" + else + Chef::Log.debug("Volume is already attached") + end + else + # attach the volume and register its id in the node data + attach_volume(vol[:aws_id], instance_id, new_resource.device, new_resource.timeout) + node.set[:aws][:ebs_volume][new_resource.name][:volume_id] = vol[:aws_id] + node.save + new_resource.updated = true + end +end + +action :detach do + vol = determine_volume + return if vol[:aws_instance_id] != instance_id + detach_volume(vol[:aws_id], new_resource.timeout) + new_resource.updated = true +end + +action :snapshot do + vol = determine_volume + snapshot = ec2.create_snapshot(vol[:aws_id]) + new_resource.updated = true + Chef::Log.info("Created snapshot of #{vol[:aws_id]} as #{snapshot[:aws_id]}") +end + +action :prune do + vol = determine_volume + old_snapshots = Array.new + Chef::Log.info "Checking for old snapshots" + ec2.describe_snapshots.sort { |a,b| b[:aws_started_at] <=> a[:aws_started_at] }.each do |snapshot| + if snapshot[:aws_volume_id] == vol[:aws_id] + Chef::Log.info "Found old snapshot #{snapshot[:aws_id]} (#{snapshot[:aws_volume_id]}) #{snapshot[:aws_started_at]}" + old_snapshots << snapshot + end + end + if old_snapshots.length >= new_resource.snapshots_to_keep + old_snapshots[new_resource.snapshots_to_keep - 1, old_snapshots.length].each do |die| + Chef::Log.info "Deleting old snapshot #{die[:aws_id]}" + ec2.delete_snapshot(die[:aws_id]) + new_resource.updated = true + end + end +end + +private + +def volume_id_in_node_data + begin + node[:aws][:ebs_volume][new_resource.name][:volume_id] + rescue NoMethodError => e + nil + end +end + +# Pulls the volume id from the volume_id attribute or the node data and verifies that the volume actually exists +def determine_volume + vol_id = new_resource.volume_id || volume_id_in_node_data || currently_attached_volume(instance_id, new_resource.device) + raise "volume_id attribute not set and no volume id is set in the node data for this resource (which is populated by action :create)" unless vol_id + + # check that volume exists + vol = volume_by_id(vol_id) + raise "No volume with id #{vol_id} exists" unless vol + + vol +end + +# Retrieves information for a volume +def volume_by_id(volume_id) + ec2.describe_volumes.find{|v| v[:aws_id] == volume_id} +end + +# Returns the volume that's attached to the instance at the given device or nil if none matches +def currently_attached_volume(instance_id, device) + ec2.describe_volumes.find{|v| v[:aws_instance_id] == instance_id && v[:aws_device] == device} +end + +# Returns true if the given volume meets the resource's attributes +def volume_compatible_with_resource_definition?(volume) + if new_resource.snapshot_id =~ /vol/ + new_resource.snapshot_id(find_snapshot_id(new_resource.snapshot_id)) + end + (new_resource.size.nil? || new_resource.size == volume[:aws_size]) && + (new_resource.availability_zone.nil? || new_resource.availability_zone == volume[:zone]) && + (new_resource.snapshot_id == volume[:snapshot_id]) +end + +# Creates a volume according to specifications and blocks until done (or times out) +def create_volume(snapshot_id, size, availability_zone, timeout) + availability_zone ||= instance_availability_zone + nv = ec2.create_volume(snapshot_id, size, availability_zone) + Chef::Log.debug("Created new volume #{nv[:aws_id]}#{snapshot_id ? " based on #{snapshot_id}" : ""}") + + # block until created + begin + Timeout::timeout(timeout) do + while true + vol = volume_by_id(nv[:aws_id]) + if vol && vol[:aws_status] != "deleting" + if ["in-use", "available"].include?(vol[:aws_status]) + Chef::Log.info("Volume #{nv[:aws_id]} is available") + break + else + Chef::Log.debug("Volume is #{vol[:aws_status]}") + end + sleep 3 + else + raise "Volume #{nv[:aws_id]} no longer exists" + end + end + end + rescue Timeout::Error + raise "Timed out waiting for volume creation after #{timeout} seconds" + end + + nv[:aws_id] +end + +# Attaches the volume and blocks until done (or times out) +def attach_volume(volume_id, instance_id, device, timeout) + Chef::Log.debug("Attaching #{volume_id} as #{device}") + ec2.attach_volume(volume_id, instance_id, device) + + # block until attached + begin + Timeout::timeout(timeout) do + while true + vol = volume_by_id(volume_id) + if vol && vol[:aws_status] != "deleting" + if vol[:aws_attachment_status] == "attached" + if vol[:aws_instance_id] == instance_id + Chef::Log.info("Volume #{volume_id} is attached to #{instance_id}") + break + else + raise "Volume is attached to instance #{vol[:aws_instance_id]} instead of #{instance_id}" + end + else + Chef::Log.debug("Volume is #{vol[:aws_status]}") + end + sleep 3 + else + raise "Volume #{volume_id} no longer exists" + end + end + end + rescue Timeout::Error + raise "Timed out waiting for volume attachment after #{timeout} seconds" + end +end + +# Detaches the volume and blocks until done (or times out) +def detach_volume(volume_id, timeout) + Chef::Log.debug("Detaching #{volume_id}") + vol = volume_by_id(volume_id) + orig_instance_id = vol[:aws_instance_id] + ec2.detach_volume(volume_id) + + # block until detached + begin + Timeout::timeout(timeout) do + while true + vol = volume_by_id(volume_id) + if vol && vol[:aws_status] != "deleting" + if vol[:aws_instance_id] != orig_instance_id + Chef::Log.info("Volume detached from #{orig_instance_id}") + break + else + Chef::Log.debug("Volume: #{vol.inspect}") + end + else + Chef::Log.debug("Volume #{volume_id} no longer exists") + break + end + sleep 3 + end + end + rescue Timeout::Error + raise "Timed out waiting for volume detachment after #{timeout} seconds" + end +end diff --git a/aws/providers/elastic_ip.rb b/aws/providers/elastic_ip.rb new file mode 100644 index 0000000..8429c7b --- /dev/null +++ b/aws/providers/elastic_ip.rb @@ -0,0 +1,83 @@ +include Opscode::Aws::Ec2 + +action :associate do + addr = address(new_resource.ip) + + if addr.nil? + raise "Elastic IP #{new_resource.ip} does not exist" + elsif addr[:instance_id] == instance_id + Chef::Log.debug("Elastic IP #{new_resource.ip} is already attached to the instance") + else + attach(new_resource.ip, new_resource.timeout) + new_resource.updated = true + Chef::Log.info("Attaching Elastic IP #{new_resource.ip} to the instance") + end +end + +action :disassociate do + addr = address(new_resource.ip) + + if addr.nil? + Chef::Log.debug("Elastic IP #{new_resource.ip} does not exist, so there is nothing to detach") + elsif addr[:instance_id] != instance_id + Chef::Log.debug("Elastic IP #{new_resource.ip} is already detached from the instance") + else + Chef::Log.info("Detaching Elastic IP #{new_resource.ip} from the instance") + detach(new_resource.ip, new_resource.timeout) + new_resource.updated = true + end +end + +private + +def address(ip) + ec2.describe_addresses.find{|a| a[:public_ip] == ip} +end + +def attach(ip, timeout) + ec2.associate_address(instance_id, ip) + + # block until attached + begin + Timeout::timeout(timeout) do + while true + addr = address(ip) + if addr.nil? + raise "Elastic IP has been deleted while waiting for attachment" + elsif addr[:instance_id] == instance_id + Chef::Log.debug("Elastic IP is attached to this instance") + break + else + Chef::Log.debug("Elastic IP is currently attached to #{addr[:instance_id]}") + end + sleep 3 + end + end + rescue Timeout::Error + raise "Timed out waiting for attachment after #{timeout} seconds" + end +end + +def detach(ip, timeout) + ec2.disassociate_address(ip) + + # block until detached + begin + Timeout::timeout(timeout) do + while true + addr = address(ip) + if addr.nil? + Chef::Log.debug("Elastic IP has been deleted while waiting for detachment") + elsif addr[:instance_id] != instance_id + Chef::Log.debug("Elastic IP is detached from this instance") + break + else + Chef::Log.debug("Elastic IP is still attached") + end + sleep 3 + end + end + rescue Timeout::Error + raise "Timed out waiting for detachment after #{timeout} seconds" + end +end diff --git a/aws/recipes/default.rb b/aws/recipes/default.rb new file mode 100644 index 0000000..0eef6bf --- /dev/null +++ b/aws/recipes/default.rb @@ -0,0 +1,27 @@ +# +# Cookbook Name:: aws +# Recipe:: default +# +# Copyright 2008-2009, Opscode, 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. +# + +r = gem_package "right_aws" do + action :nothing +end + +r.run_action(:install) + +Gem.clear_paths +require 'right_aws' diff --git a/aws/resources/ebs_volume.rb b/aws/resources/ebs_volume.rb new file mode 100644 index 0000000..5665eb9 --- /dev/null +++ b/aws/resources/ebs_volume.rb @@ -0,0 +1,11 @@ +actions :create, :attach, :detach, :snapshot, :prune + +attribute :aws_access_key, :kind_of => String +attribute :aws_secret_access_key, :kind_of => String +attribute :size, :kind_of => Integer +attribute :snapshot_id, :kind_of => String +attribute :availability_zone, :kind_of => String +attribute :device, :kind_of => String +attribute :volume_id, :kind_of => String +attribute :timeout, :default => 3*60 # 3 mins, nil or 0 for no timeout +attribute :snapshots_to_keep, :default => 2 diff --git a/aws/resources/elastic_ip.rb b/aws/resources/elastic_ip.rb new file mode 100644 index 0000000..9666d66 --- /dev/null +++ b/aws/resources/elastic_ip.rb @@ -0,0 +1,6 @@ +actions :associate, :disassociate + +attribute :aws_access_key, :kind_of => String +attribute :aws_secret_access_key, :kind_of => String +attribute :ip, :kind_of => String +attribute :timeout, :default => 3*60 # 3 mins, nil or 0 for no timeout diff --git a/bluepill/attributes/bluepill.rb b/bluepill/attributes/bluepill.rb new file mode 100755 index 0000000..913cbec --- /dev/null +++ b/bluepill/attributes/bluepill.rb @@ -0,0 +1,4 @@ +default.bluepill[:config_dir] = "/etc/bluepill" +default.bluepill[:log_dir] = "/var/log/bluepill" +default.bluepill[:pid_dir] = "/var/run/bluepill" +bluepill[:version] = "0.0.30" \ No newline at end of file diff --git a/bluepill/definitions/bluepill_monitor.rb b/bluepill/definitions/bluepill_monitor.rb new file mode 100755 index 0000000..2b831bc --- /dev/null +++ b/bluepill/definitions/bluepill_monitor.rb @@ -0,0 +1,21 @@ +define :bluepill_monitor, :enable => true, :rack_config_path => false do + include_recipe "bluepill" + config_path = "#{node[:bluepill][:config_dir]}/#{params[:name]}.conf.rb" + + execute "load-bluepill-#{params[:name]}" do + command "bluepill load #{node[:bluepill][:config_dir]}/#{params[:name]}.conf.rb" + action :nothing + end + + execute "restart-bluepill-#{params[:name]}" do + command "bluepill restart #{params[:name]}" + action :nothing + end + + template config_path do + source params[:source] || "bluepill_#{params[:name]}.conf.erb" + cookbook params[:cookbook] + variables params + notifies :run, resources("execute[load-bluepill-#{params[:name]}]") + end +end \ No newline at end of file diff --git a/bluepill/metadata.json b/bluepill/metadata.json new file mode 100755 index 0000000..26c5896 --- /dev/null +++ b/bluepill/metadata.json @@ -0,0 +1,47 @@ +{ + "replacing": { + + }, + "long_description": "= DESCRIPTION:\n\nInstalls god gem, sets up modular configuration directory and provides a define to monitor processes.\n\n= REQUIREMENTS:\n\n== Platform and Application Environment:\n\nTested on Ubuntu 8.10. May work on other platforms, esp Ubuntu\/Debian. Sample configuration file uses mongrel_runit for managing mongrels via runit. \n\n== Cookbooks:\n\nOpscode cookbooks, http:\/\/github.com\/opscode\/cookbooks\/tree\/master:\n\n* ruby\n* runit\n\nOpscode does not yet have a mongrel_runit cookbook.\n\n= ATTRIBUTES: \n\nNo attributes are used.\n\n= USAGE:\n\nThis recipe is designed to be used through the god_monitor define. Create a god configuration file in your application's cookbook and then call god_monitor:\n\n god_monitor \"myproj\" do\n config \"myproj.god.erb\"\n end\n\nA sample mongrel.god.erb is provided, though it assumes mongrel_runit is used. This can be used as a baseline for customization.\n\n= LICENSE and AUTHOR:\n \nAuthor:: Joshua Timberman ()\nCopyright:: 2009, Opscode, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http:\/\/www.apache.org\/licenses\/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n", + "attributes": { + + }, + "maintainer": "Opscode, Inc.", + "recommendations": { + + }, + "license": "Apache 2.0", + "recipes": { + "god::apps": "", + "god": "" + }, + "maintainer_email": "cookbooks@opscode.com", + "suggestions": { + + }, + "dependencies": { + "runit": [ + + ], + "ruby": [ + + ] + }, + "conflicting": { + + }, + "platforms": { + + }, + "description": "Installs and configures god and provides a define for monitoring", + "version": "0.7.0", + "name": "god", + "providing": { + "god::apps": [ + + ], + "god": [ + + ] + } +} \ No newline at end of file diff --git a/bluepill/metadata.rb b/bluepill/metadata.rb new file mode 100755 index 0000000..eeec383 --- /dev/null +++ b/bluepill/metadata.rb @@ -0,0 +1,5 @@ +maintainer "Joshua Sierles" +maintainer_email "joshua@37signals.com" +license "Apache 2.0" +description "Installs bluepill and provides definitions and templates for monitoring" +version "0.7" \ No newline at end of file diff --git a/bluepill/recipes/default.rb b/bluepill/recipes/default.rb new file mode 100755 index 0000000..fd84922 --- /dev/null +++ b/bluepill/recipes/default.rb @@ -0,0 +1,27 @@ +gem_package "bluepill" do + version node[:bluepill][:version] +end + +directory node[:bluepill][:config_dir] do + owner "root" + group "root" +end + +directory node[:bluepill][:log_dir] do + owner "root" + group "root" +end + +directory node[:bluepill][:pid_dir] do + owner "root" + group "root" +end + +template "/etc/init.d/bluepill" do + source "init.sh.erb" + mode 0755 +end + +service "bluepill" do + action [:enable, :start] +end diff --git a/bluepill/templates/default/init.sh.erb b/bluepill/templates/default/init.sh.erb new file mode 100755 index 0000000..6e1c7c6 --- /dev/null +++ b/bluepill/templates/default/init.sh.erb @@ -0,0 +1,35 @@ +#!/bin/sh + +### BEGIN INIT INFO +# Provides: bluepill +# Required-Start: +# Required-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 1 +# Short-Description: Bluepill initializer +### END INIT INFO + +. /lib/lsb/init-functions + +case "$1" in + start) + log_daemon_msg "Starting bluepill services" + for i in <%= @node[:bluepill][:config_dir] %>/*conf.rb; do + <%= @node[:ruby][:bin_dir] %>/bluepill load $i + done + log_end_msg 0 + ;; + stop) + echo "Stop is not implemented, since bluepill processes are run independently." + ;; + restart) + for i in <%= @node[:bluepill][:config_dir] %>/*conf.rb; do + <%= @node[:ruby][:bin_dir] %>/bluepill load $i + done + ;; + *) + log_action_msg "Usage: /etc/init.d/bluepill start" + exit +esac + +exit 0 \ No newline at end of file diff --git a/boost/README.rdoc b/boost/README.rdoc new file mode 100644 index 0000000..1edfb9b --- /dev/null +++ b/boost/README.rdoc @@ -0,0 +1,33 @@ += DESCRIPTION: + +Installs boost, mainly to support Thrift. + += REQUIREMENTS: + +Platform: Ubuntu 9.04. Not tested on any others at this time. + += USAGE: + +Include this recipe to install boost development packages. + + include_recipe "boost" + +Merely installs the libboost-dev package which should grab a bunch of dependencies and get the right thing. + += LICENSE and AUTHOR: + + +Author:: Joshua Timberman () +Copyright:: 2009, Opscode, 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/boost/metadata.json b/boost/metadata.json new file mode 100644 index 0000000..c875a8d --- /dev/null +++ b/boost/metadata.json @@ -0,0 +1,40 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs libboost", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "boost": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ] + }, + "version": "0.1.0", + "name": "boost", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "boost": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "= DESCRIPTION:\n\nInstalls boost, mainly to support Thrift.\n\n= REQUIREMENTS:\n\nPlatform: Ubuntu 9.04. Not tested on any others at this time.\n\n= USAGE:\n\nInclude this recipe to install boost development packages.\n\n include_recipe \"boost\"\n\nMerely installs the libboost-dev package which should grab a bunch of dependencies and get the right thing.\n\n= LICENSE and AUTHOR:\n\n\nAuthor:: Joshua Timberman ()\nCopyright:: 2009, Opscode, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http:\/\/www.apache.org\/licenses\/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/boost/metadata.rb b/boost/metadata.rb new file mode 100644 index 0000000..43bd644 --- /dev/null +++ b/boost/metadata.rb @@ -0,0 +1,8 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs libboost" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.1" + +supports "ubuntu" diff --git a/boost/recipes/default.rb b/boost/recipes/default.rb new file mode 100644 index 0000000..5cf2f81 --- /dev/null +++ b/boost/recipes/default.rb @@ -0,0 +1,19 @@ +# +# Cookbook Name:: boost +# Recipe:: default +# +# Copyright 2009, Opscode, 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 "libboost-dev" diff --git a/bootstrap/README.rdoc b/bootstrap/README.rdoc new file mode 100644 index 0000000..00548b2 --- /dev/null +++ b/bootstrap/README.rdoc @@ -0,0 +1,165 @@ += DESCRIPTION: + +This cookbook bootstraps a Chef client or server when Chef is installed via RubyGems. If installing Chef from OS distribution packages, please see the 'chef' cookbook. + += REQUIREMENTS: + +This cookbook requires Chef installed from RubyGems. Chef v0.7.10, for attribute syntax. + +== Platform: + +Server bootstrap is tested on Ubuntu 9.10, 9.04, 8.10 and 8.04, Debian 5.0. + +Client bootstrap is tested on the above, plus CentOS 5.3, Fedora 10, OpenBSD 4.6, FreeBSD 7.1 and Gentoo. OpenSolaris 11 is also tested, but there's a bug in Ohai that requires some manual intervention (OHAI-122). + +== Cookbooks: + +Opscode cookbooks, http://github.com/opscode/cookbooks: + +Both clients and servers: + +* runit + +Servers only: + +* couchdb +* stompserver + +The couchdb and stompserver recipes may be somewhat naive depending on the platform. You should view them online at the github repository to see if your platform is supported. If not, you'll need to manually install them, and remove the "include_recipe" statements from the bootstrap::server recipe. + += ATTRIBUTES: + +Attributes are under 'bootstrap[:chef]' - eg: 'bootstrap[:chef][:client_version]'. You may wish to change some of these locations to customize for your environment. For the bootstrap process this is done with a JSON data file passed to chef-solo. + +== url_type + +Set up the URLs the client should connect to with this. Default is 'http', which tells the client to connect to 'http://server:4000'. If you set up your chef-server to use an SSL front-end, set this to 'https' and the URLs will be 'https://server/'. + +== init_style + +Specifies the init style to use. Default 'runit'. Other possible values 'init', 'bsd', any other string will be treated as unknown. + +If your platform doesn't have a 'runit' package or if the cookbook doesn't detect it, but you stil want to use runit, set init_style to 'none' and install runit separately. + +== path + +This is the base location where chef will store its associated data. Default '/srv/chef' for RubyGems installed systems. The location preference varies by platform. The default is a filesystem hiearchy standard suggestion[1]. Some other locations you may consider, by platform: + +Debian and Red Hat based Linux distros (Ubuntu, CentOS, Fedora, etc): + +* /var/lib/chef + +Any BSD and Gentoo: + +* /var/chef + +== run_path + +Location for pidfiles on systems using init scripts. Default '/var/run/chef'. + +If init_style is 'init', this is used, and should match what the init script itself uses for the PID files. + +== cache_path + +Location where the client will cache cookbooks and other data. Default is 'cache' underneath the bootstrap[:chef][:path] location. Some Linux distributions might prefer /var/cache/chef instead. + +== serve_path + +Used by the Chef server as the base location to "serve" cookbooks, roles and other assets. Default is /srv/chef. + +== server_version, client_version + +Set the version of the Gems to install. This can be used to upgrade Chef automatically[0]. The chef gems are not managed by the Opscode Chef cookbook, however. + +== client_interval + +Number of seconds to run chef-client periodically. Default '1800' (30 minutes). + +== client_splay + +Splay interval to randomly add to interval. Default '20'. + +== log_dir + +Directory where logs are stored if logs are not sent to STDOUT. Systems using runit should send logs to STDOUT as runit manages log output. Default '/var/log/chef'. + +== client_log, indexer_log, server_log + +Location of the client, indexer and server logs, respectively. Default 'STDOUT' on systems with runit, '/var/log/chef/{client,indexer,server}.log' on other systems. + +== server_fqdn + +Fully qualified domain name of the server. Default is the current node's fqdn as detected by Ohai. For clients, set this to the hostname of your environment's Chef Server. + +== server_token + +The validation_token used to automatically authorize chef-clients. Default is a random string generated every time chef-solo runs. Use chef-client -t 'validation_token' to automatically validate the client. + +[0] http://blog.opscode.com/2009/08/cool-chef-tricks-upgrade-chef-with-chef.html +[1] http://www.pathname.com/fhs/ + += USAGE: + +Opscode stores this cookbook and some others (see the requirements above) on S3. Use chef-solo: + + sudo chef-solo -j chef.json -c solo.rb -r http://s3.amazonaws.com/chef-solo/bootstrap-latest.tar.gz + +You set the attributes through the chef.json file, and tell Solo where to put them with solo.rb. + +== Clients: + +Common attributes you may wish to adjust for the client: + +{ + "bootstrap": { + "chef": { + "url_type": "http", + "init_style": "runit", + "path": "/srv/chef", + "server_fqdn": "localhost.localdomain", + } + }, + "recipes": "bootstrap::client" +} + +== Servers: + +Common attributes you may wish to adjust for the server: + +{ + "bootstrap": { + "chef": { + "url_type": "http", + "init_style": "runit", + "path": "/srv/chef", + "serve_path": "/srv/chef", + "server_fqdn": "localhost.localdomain", + } + }, + "recipes": "bootstrap::server" +} + +Note that the server recipe includes the client recipe as well, since we recommend managing the chef-server with Chef. + +For more information on usage and next steps, please see the Chef wiki. + + http://wiki.opscode.com/display/chef/Home + += LICENSE and AUTHOR: + +Author:: Joshua Timberman +Author:: Joshua Sierles + +Copyright 2008-2009, Opscode, Inc +Copyright 2009, 37signals + +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 diff --git a/bootstrap/attributes/bootstrap.rb b/bootstrap/attributes/bootstrap.rb new file mode 100644 index 0000000..00024ac --- /dev/null +++ b/bootstrap/attributes/bootstrap.rb @@ -0,0 +1,50 @@ +# +# Cookbook Name:: bootstrap +# Attributes:: bootstrap +# +# Copyright 2008-2009, Opscode, 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. +# + +validation_token = "" +chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a +20.times { |i| validation_token << chars[rand(chars.size-1)] } + +set_unless[:bootstrap][:chef][:umask] = 0022 +set_unless[:bootstrap][:chef][:url_type] = "http" +set_unless[:bootstrap][:chef][:init_style] = "runit" +set_unless[:bootstrap][:chef][:path] = "/srv/chef" +set_unless[:bootstrap][:chef][:run_path] = "/var/run/chef" +set_unless[:bootstrap][:chef][:cache_path] = "/#{bootstrap[:chef][:path]}/cache" +set_unless[:bootstrap][:chef][:serve_path] = "/srv/chef" + +set_unless[:bootstrap][:chef][:server_version] = "0.7.16" +set_unless[:bootstrap][:chef][:client_version] = "0.7.16" +set_unless[:bootstrap][:chef][:client_interval] = "1800" +set_unless[:bootstrap][:chef][:client_splay] = "20" +set_unless[:bootstrap][:chef][:log_dir] = "/var/log/chef" + +case bootstrap[:chef][:init_style] +when "runit" + set_unless[:bootstrap][:chef][:client_log] = "STDOUT" + set_unless[:bootstrap][:chef][:server_log] = "STDOUT" + set_unless[:bootstrap][:chef][:indexer_log] = "STDOUT" +else + set_unless[:bootstrap][:chef][:client_log] = "#{bootstrap[:chef][:log_dir]}/client.log" + set_unless[:bootstrap][:chef][:server_log] = "#{bootstrap[:chef][:log_dir]}/server.log" + set_unless[:bootstrap][:chef][:indexer_log] = "#{bootstrap[:chef][:log_dir]}/indexer.log" +end + +set_unless[:bootstrap][:chef][:server_fqdn] = domain ? "chef.#{domain}" : "chef" +set_unless[:bootstrap][:chef][:server_token] = validation_token diff --git a/bootstrap/metadata.json b/bootstrap/metadata.json new file mode 100644 index 0000000..e31efa7 --- /dev/null +++ b/bootstrap/metadata.json @@ -0,0 +1,77 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Configures RubyGems-installed Chef", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "bootstrap::client": "", + "bootstrap": "", + "bootstrap::server": "" + }, + "suggestions": { + + }, + "platforms": { + "freebsd": [ + + ], + "ubuntu": [ + + ], + "openbsd": [ + + ], + "fedora": [ + + ], + "centos": [ + + ], + "redhat": [ + + ], + "debian": [ + + ] + }, + "version": "0.1.0", + "name": "bootstrap", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "bootstrap": [ + + ], + "bootstrap::client": [ + + ], + "bootstrap::server": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "= DESCRIPTION:\n\nThis cookbook bootstraps a Chef client or server when Chef is installed via RubyGems. If installing Chef from OS distribution packages, please see the 'chef' cookbook. \n\n= REQUIREMENTS:\n\nThis cookbook requires Chef installed from RubyGems. Chef v0.7.10, for attribute syntax.\n\n== Platform:\n\nServer bootstrap is tested on Ubuntu 9.10, 9.04, 8.10 and 8.04, Debian 5.0.\n\nClient bootstrap is tested on the above, plus CentOS 5.3, Fedora 10, OpenBSD 4.6, FreeBSD 7.1 and Gentoo. OpenSolaris 11 is also tested, but there's a bug in Ohai that requires some manual intervention (OHAI-122).\n\n== Cookbooks:\n\nOpscode cookbooks, http:\/\/github.com\/opscode\/cookbooks:\n\nBoth clients and servers:\n\n* runit\n\nServers only:\n\n* couchdb\n* stompserver\n\nThe couchdb and stompserver recipes may be somewhat naive depending on the platform. You should view them online at the github repository to see if your platform is supported. If not, you'll need to manually install them, and remove the \"include_recipe\" statements from the bootstrap::server recipe.\n\n= ATTRIBUTES:\n\nAttributes are under 'bootstrap[:chef]' - eg: 'bootstrap[:chef][:client_version]'. You may wish to change some of these locations to customize for your environment. For the bootstrap process this is done with a JSON data file passed to chef-solo.\n\n== url_type\n\nSet up the URLs the client should connect to with this. Default is 'http', which tells the client to connect to 'http:\/\/server:4000'. If you set up your chef-server to use an SSL front-end, set this to 'https' and the URLs will be 'https:\/\/server\/'. \n\n== init_style\n\nSpecifies the init style to use. Default 'runit'. Other possible values 'init', 'bsd', any other string will be treated as unknown.\n\nIf your platform doesn't have a 'runit' package or if the cookbook doesn't detect it, but you stil want to use runit, set init_style to 'none' and install runit separately.\n\n== path\n\nThis is the base location where chef will store its associated data. Default '\/srv\/chef' for RubyGems installed systems. The location preference varies by platform. The default is a filesystem hiearchy standard suggestion[1]. Some other locations you may consider, by platform:\n\nDebian and Red Hat based Linux distros (Ubuntu, CentOS, Fedora, etc):\n\n* \/var\/lib\/chef\n\nAny BSD and Gentoo:\n\n* \/var\/chef\n\n== run_path\n\nLocation for pidfiles on systems using init scripts. Default '\/var\/run\/chef'.\n\nIf init_style is 'init', this is used, and should match what the init script itself uses for the PID files.\n\n== cache_path\n\nLocation where the client will cache cookbooks and other data. Default is 'cache' underneath the bootstrap[:chef][:path] location. Some Linux distributions might prefer \/var\/cache\/chef instead.\n\n== serve_path\n\nUsed by the Chef server as the base location to \"serve\" cookbooks, roles and other assets. Default is \/srv\/chef.\n\n== server_version, client_version\n\nSet the version of the Gems to install. This can be used to upgrade Chef automatically[0]. The chef gems are not managed by the Opscode Chef cookbook, however.\n\n== client_interval\n\nNumber of seconds to run chef-client periodically. Default '1800' (30 minutes).\n\n== client_splay\n\nSplay interval to randomly add to interval. Default '20'.\n\n== log_dir\n\nDirectory where logs are stored if logs are not sent to STDOUT. Systems using runit should send logs to STDOUT as runit manages log output. Default '\/var\/log\/chef'.\n\n== client_log, indexer_log, server_log\n\nLocation of the client, indexer and server logs, respectively. Default 'STDOUT' on systems with runit, '\/var\/log\/chef\/{client,indexer,server}.log' on other systems.\n\n== server_fqdn\n\nFully qualified domain name of the server. Default is the current node's fqdn as detected by Ohai. For clients, set this to the hostname of your environment's Chef Server.\n\n== server_token\n\nThe validation_token used to automatically authorize chef-clients. Default is a random string generated every time chef-solo runs. Use chef-client -t 'validation_token' to automatically validate the client.\n\n[0] http:\/\/blog.opscode.com\/2009\/08\/cool-chef-tricks-upgrade-chef-with-chef.html\n[1] http:\/\/www.pathname.com\/fhs\/\n\n= USAGE:\n\nOpscode stores this cookbook and some others (see the requirements above) on S3. Use chef-solo:\n\n sudo chef-solo -j chef.json -c solo.rb -r http:\/\/s3.amazonaws.com\/chef-solo\/bootstrap-latest.tar.gz\n\nYou set the attributes through the chef.json file, and tell Solo where to put them with solo.rb.\n\n== Clients:\n\nCommon attributes you may wish to adjust for the client:\n\n{\n \"bootstrap\": {\n \"chef\": {\n \"url_type\": \"http\",\n \"init_style\": \"runit\",\n \"path\": \"\/srv\/chef\",\n \"server_fqdn\": \"localhost.localdomain\",\n }\n },\n \"recipes\": \"bootstrap::client\"\n}\n\n== Servers:\n\nCommon attributes you may wish to adjust for the server:\n\n{\n \"bootstrap\": {\n \"chef\": {\n \"url_type\": \"http\",\n \"init_style\": \"runit\",\n \"path\": \"\/srv\/chef\",\n \"serve_path\": \"\/srv\/chef\",\n \"server_fqdn\": \"localhost.localdomain\",\n }\n },\n \"recipes\": \"bootstrap::server\"\n}\n\nNote that the server recipe includes the client recipe as well, since we recommend managing the chef-server with Chef.\n\nFor more information on usage and next steps, please see the Chef wiki.\n\n http:\/\/wiki.opscode.com\/display\/chef\/Home\n\n= LICENSE and AUTHOR:\n\nAuthor:: Joshua Timberman \nAuthor:: Joshua Sierles \n\nCopyright 2008-2009, Opscode, Inc\nCopyright 2009, 37signals\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http:\/\/www.apache.org\/licenses\/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\n", + "replacing": { + + }, + "dependencies": { + "stompserver": [ + + ], + "runit": [ + + ], + "couchdb": [ + + ], + "apache2": [ + + ] + } +} \ No newline at end of file diff --git a/bootstrap/metadata.rb b/bootstrap/metadata.rb new file mode 100644 index 0000000..f24a020 --- /dev/null +++ b/bootstrap/metadata.rb @@ -0,0 +1,14 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Configures RubyGems-installed Chef" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.2" + +%w{ ubuntu debian redhat centos fedora freebsd openbsd }.each do |os| + supports os +end + +%w{ runit couchdb stompserver apache2 }.each do |cb| + depends cb +end diff --git a/bootstrap/recipes/client.rb b/bootstrap/recipes/client.rb new file mode 100644 index 0000000..4caf821 --- /dev/null +++ b/bootstrap/recipes/client.rb @@ -0,0 +1,87 @@ +# +# Cookbook Name:: bootstrap +# Recipe:: default +# +# Copyright 2009, Opscode, 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. +# + +root_group = value_for_platform( + "openbsd" => { "default" => "wheel" }, + "freebsd" => { "default" => "wheel" }, + "default" => "root" +) + +gem_package "chef" do + version node[:bootstrap][:chef][:client_version] +end + +case node[:bootstrap][:chef][:init_style] +when "runit" + client_log = node[:bootstrap][:chef][:client_log] + show_time = "false" + include_recipe "runit" + runit_service "chef-client" +when "init" + client_log = "\"#{node[:bootstrap][:chef][:client_log]}\"" + show_time = "true" + + directory node[:bootstrap][:chef][:run_path] do + action :create + owner "root" + group root_group + mode "755" + end + + service "chef-client" do + action :nothing + end + + Chef::Log.info("You specified service style 'init'.") + Chef::Log.info("'init' scripts available in #{node[:languages][:ruby][:gems_dir]}/gems/chef-#{node[:bootstrap][:chef][:client_version]}/distro") +when "bsd" + client_log = node[:bootstrap][:chef][:client_log] + show_time = "false" + Chef::Log.info("You specified service style 'bsd'. You will need to set up your rc.local file.") + Chef::Log.info("Hint: chef-client -i #{node[:bootstrap][:chef][:client_interval]} -s #{node[:bootstrap][:chef][:client_splay]}") +else + client_log = node[:bootstrap][:chef][:client_log] + show_time = "false" + Chef::Log.info("Could not determine service init style, manual intervention required to start up the client service.") +end + +chef_dirs = [ + node[:bootstrap][:chef][:log_dir], + node[:bootstrap][:chef][:path], + "/etc/chef" +] + +chef_dirs.each do |dir| + directory dir do + owner "root" + group root_group + mode "755" + end +end + +template "/etc/chef/client.rb" do + source "client.rb.erb" + owner "root" + group root_group + mode "644" + variables( + :client_log => client_log, + :show_time => show_time + ) +end diff --git a/bootstrap/recipes/default.rb b/bootstrap/recipes/default.rb new file mode 100644 index 0000000..3f4ba70 --- /dev/null +++ b/bootstrap/recipes/default.rb @@ -0,0 +1,18 @@ +# +# Cookbook Name:: bootstrap +# Recipe:: client +# +# Copyright 2009, Opscode, 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/bootstrap/recipes/server.rb b/bootstrap/recipes/server.rb new file mode 100644 index 0000000..19ff7b1 --- /dev/null +++ b/bootstrap/recipes/server.rb @@ -0,0 +1,120 @@ +# +# Author:: Joshua Timberman +# Author:: Joshua Sierles +# +# Cookbook Name:: bootstrap +# Recipe:: server +# +# Copyright 2009, Opscode, Inc. +# Copyright 2009, 37signals +# +# 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. +# + +root_group = value_for_platform( + "openbsd" => { "default" => "wheel" }, + "freebsd" => { "default" => "wheel" }, + "default" => "root" +) + +include_recipe "bootstrap::client" +include_recipe "stompserver" + +case node[:platform] +when "ubuntu" + if node[:platform_version].to_f >= 8.10 + include_recipe "couchdb" + end +when "debian" + if node[:platform_version].to_f >= 5.0 || node[:platform_version] =~ /.*sid/ + include_recipe "couchdb" + end +when "centos","redhat","fedora" + include_recipe "couchdb" +else + Chef::Log.info("Unknown platform for CouchDB. Manual installation of CouchDB required.") +end + +%w{ chef-server chef-server-slice }.each do |gem| + gem_package gem do + version node[:bootstrap][:chef][:server_version] + end +end + +if node[:bootstrap][:chef][:server_log] == "STDOUT" + server_log = node[:bootstrap][:chef][:server_log] + show_time = "false" +else + server_log = "\"#{node[:bootstrap][:chef][:server_log]}\"" + indexer_log = "\"#{node[:bootstrap][:chef][:indexer_log]}\"" + show_time = "true" +end + +template "/etc/chef/server.rb" do + source "server.rb.erb" + owner "root" + group root_group + mode "600" + variables( + :server_log => server_log, + :show_time => show_time + ) +end + +%w{ openid cache search_index openid/cstore openid/store }.each do |dir| + directory "#{node[:bootstrap][:chef][:path]}/#{dir}" do + owner "root" + group root_group + mode "755" + end +end + +directory "/etc/chef/certificates" do + owner "root" + group root_group + mode "700" +end + +directory node[:bootstrap][:chef][:run_path] do + owner "root" + group root_group + mode "755" +end + +case node[:bootstrap][:chef][:init_style] +when "runit" + include_recipe "runit" + runit_service "chef-indexer" + runit_service "chef-server" + service "chef-server" do + restart_command "sv int chef-server" + end +when "init" + show_time = "true" + + service "chef-indexer" do + action :nothing + end + + service "chef-server" do + action :nothing + end + + Chef::Log.info("You specified service style 'init'.") + Chef::Log.info("'init' scripts available in #{node[:languages][:ruby][:gems_dir]}/gems/chef-#{node[:bootstrap][:chef][:client_version]}/distro") +when "bsd" + Chef::Log.info("You specified service style 'bsd'. You will need to set up your rc.local file for chef-indexer and chef-server.") + Chef::Log.info("Server startup command: chef-server -c2 -d") +else + Chef::Log.info("Could not determine service init style, manual intervention required to set up indexer and server services.") +end diff --git a/bootstrap/templates/default/client.rb.erb b/bootstrap/templates/default/client.rb.erb new file mode 100644 index 0000000..a719708 --- /dev/null +++ b/bootstrap/templates/default/client.rb.erb @@ -0,0 +1,30 @@ +# +# Chef Client Config File +# +# Dynamically generated by Chef - local modifications will be replaced +# + +log_level :info +log_location <%= @client_log %> +ssl_verify_mode :verify_none +<% if @node[:bootstrap][:chef][:url_type] == "https" -%> +registration_url "https://<%= @node[:bootstrap][:chef][:server_fqdn] %>" +openid_url "https://<%= @node[:bootstrap][:chef][:server_fqdn] %>:444" +template_url "https://<%= @node[:bootstrap][:chef][:server_fqdn] %>" +remotefile_url "https://<%= @node[:bootstrap][:chef][:server_fqdn] %>" +search_url "https://<%= @node[:bootstrap][:chef][:server_fqdn] %>" +role_url "https://<%= @node[:bootstrap][:chef][:server_fqdn] %>" +<% else -%> +registration_url "http://<%= @node[:bootstrap][:chef][:server_fqdn] %>:4000" +openid_url "http://<%= @node[:bootstrap][:chef][:server_fqdn] %>:4001" +template_url "http://<%= @node[:bootstrap][:chef][:server_fqdn] %>:4000" +remotefile_url "http://<%= @node[:bootstrap][:chef][:server_fqdn] %>:4000" +search_url "http://<%= @node[:bootstrap][:chef][:server_fqdn] %>:4000" +role_url "http://<%= @node[:bootstrap][:chef][:server_fqdn] %>:4000" +<% end -%> + +file_cache_path "<%= @node[:bootstrap][:chef][:cache_path] %>" + +pid_file "<%= @node[:bootstrap][:chef][:run_path] %>/client.pid" + +Chef::Log::Formatter.show_time = <%= @show_time %> diff --git a/bootstrap/templates/default/server.rb.erb b/bootstrap/templates/default/server.rb.erb new file mode 100644 index 0000000..941e3d8 --- /dev/null +++ b/bootstrap/templates/default/server.rb.erb @@ -0,0 +1,34 @@ +# +# Chef Server Config File +# +# Dynamically generated by Chef - local modifications will be replaced + +log_level :info +log_location <%= @server_log %> +ssl_verify_mode :verify_none +registration_url "http://<%= @node[:bootstrap][:chef][:server_fqdn] %>:4000" +openid_url "http://<%= @node[:bootstrap][:chef][:server_fqdn] %>:4001" +template_url "http://<%= @node[:bootstrap][:chef][:server_fqdn] %>:4000" +remotefile_url "http://<%= @node[:bootstrap][:chef][:server_fqdn] %>:4000" +search_url "http://<%= @node[:bootstrap][:chef][:server_fqdn] %>:4000" +role_url "http://<%= @node[:bootstrap][:chef][:server_fqdn] %>:4000" + +validation_token "<%= @node[:bootstrap][:chef][:server_token] %>" + +cookbook_path [ "<%= @node[:bootstrap][:chef][:serve_path] %>/site-cookbooks", "<%= @node[:bootstrap][:chef][:serve_path] %>/cookbooks" ] + +file_cache_path "<%= @node[:bootstrap][:chef][:cache_path] %>" +node_path "<%= @node[:bootstrap][:chef][:serve_path] %>/nodes" +openid_store_path "<%= @node[:bootstrap][:chef][:path] %>/openid/store" +openid_cstore_path "<%= @node[:bootstrap][:chef][:path] %>/openid/cstore" +search_index_path "<%= @node[:bootstrap][:chef][:path] %>/search_index" +role_path "<%= @node[:bootstrap][:chef][:serve_path] %>/roles" + +umask <%= @node[:bootstrap][:chef][:umask] %> + +# See http://wiki.opscode.com/display/chef/Securing+Chef+Server +# For more information on these settings. +#authorized_openid_providers [ "https://<%= @node[:bootstrap][:chef][:server_fqdn]%>", "https://chef", "myopenid.com" ] +#authorized_openid_identifiers [ "" ] + +Chef::Log::Formatter.show_time = <%= @show_time %> diff --git a/bootstrap/templates/default/sv-chef-client-log-run.erb b/bootstrap/templates/default/sv-chef-client-log-run.erb new file mode 100644 index 0000000..a79a518 --- /dev/null +++ b/bootstrap/templates/default/sv-chef-client-log-run.erb @@ -0,0 +1,2 @@ +#!/bin/sh +exec svlogd -tt ./main diff --git a/bootstrap/templates/default/sv-chef-client-run.erb b/bootstrap/templates/default/sv-chef-client-run.erb new file mode 100644 index 0000000..7c0dec7 --- /dev/null +++ b/bootstrap/templates/default/sv-chef-client-run.erb @@ -0,0 +1,4 @@ +#!/bin/sh +PATH=/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin<% if @node[:languages][:ruby][:gems_dir] %>:<%= @node[:languages][:ruby][:gems_dir] %>/bin<% end -%> +exec 2>&1 +exec /usr/bin/env chef-client -i <%= @node[:bootstrap][:chef][:client_interval] %> -s <%= @node[:bootstrap][:chef][:client_splay] %> <% if @node[:bootstrap][:chef][:client_log] != "STDOUT" then -%>-L <%= @node[:bootstrap][:chef][:client_log] %><% end -%> diff --git a/bootstrap/templates/default/sv-chef-indexer-log-run.erb b/bootstrap/templates/default/sv-chef-indexer-log-run.erb new file mode 100644 index 0000000..a79a518 --- /dev/null +++ b/bootstrap/templates/default/sv-chef-indexer-log-run.erb @@ -0,0 +1,2 @@ +#!/bin/sh +exec svlogd -tt ./main diff --git a/bootstrap/templates/default/sv-chef-indexer-run.erb b/bootstrap/templates/default/sv-chef-indexer-run.erb new file mode 100644 index 0000000..634f651 --- /dev/null +++ b/bootstrap/templates/default/sv-chef-indexer-run.erb @@ -0,0 +1,4 @@ +#!/bin/sh +PATH=/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin<% if @node[:languages][:ruby][:gems_dir] %>:<%= @node[:languages][:ruby][:gems_dir] %>/bin<% end -%> +exec 2>&1 +exec /usr/bin/env chef-indexer diff --git a/bootstrap/templates/default/sv-chef-server-log-run.erb b/bootstrap/templates/default/sv-chef-server-log-run.erb new file mode 100644 index 0000000..a79a518 --- /dev/null +++ b/bootstrap/templates/default/sv-chef-server-log-run.erb @@ -0,0 +1,2 @@ +#!/bin/sh +exec svlogd -tt ./main diff --git a/bootstrap/templates/default/sv-chef-server-run.erb b/bootstrap/templates/default/sv-chef-server-run.erb new file mode 100644 index 0000000..7d20fe0 --- /dev/null +++ b/bootstrap/templates/default/sv-chef-server-run.erb @@ -0,0 +1,4 @@ +#!/bin/sh +PATH=/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin<% if @node[:languages][:ruby][:gems_dir] %>:<%= @node[:languages][:ruby][:gems_dir] %>/bin<% end -%> +exec 2>&1 +exec /usr/bin/env chef-server -N -c2 -P <%= @node[:bootstrap][:chef][:run_path] %>/server.%s.pid diff --git a/build-essential/metadata.json b/build-essential/metadata.json new file mode 100644 index 0000000..38e9f0b --- /dev/null +++ b/build-essential/metadata.json @@ -0,0 +1,46 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs C compiler \/ build tools", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "build-essential": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "centos": [ + + ], + "debian": [ + + ] + }, + "version": "0.7.0", + "name": "build-essential", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "build-essential": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/build-essential/metadata.rb b/build-essential/metadata.rb new file mode 100644 index 0000000..5e1613e --- /dev/null +++ b/build-essential/metadata.rb @@ -0,0 +1,9 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs C compiler / build tools" +version "0.7" + +%w{ centos ubuntu debian }.each do |os| + supports os +end diff --git a/build-essential/recipes/default.rb b/build-essential/recipes/default.rb new file mode 100644 index 0000000..b4dcce0 --- /dev/null +++ b/build-essential/recipes/default.rb @@ -0,0 +1,43 @@ +# +# Cookbook Name:: build-essential +# Recipe:: default +# +# Copyright 2008-2009, Opscode, 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. +# + +case node[:platform] +when "ubuntu","debian" + %w{build-essential binutils-doc}.each do |pkg| + package pkg do + action :install + end + end +when "centos" + package "gcc" do + action :install + end +end + +package "autoconf" do + action :install +end + +package "flex" do + action :install +end + +package "bison" do + action :install +end diff --git a/build/attributes/build.rb b/build/attributes/build.rb new file mode 100755 index 0000000..13fa538 --- /dev/null +++ b/build/attributes/build.rb @@ -0,0 +1,2 @@ +build Mash.new unless attribute?("build") +build[:ruby_enterprise_edition] = {:packages => ["libssl-dev", "libreadline5-dev", "bison"]} diff --git a/build/metadata.json b/build/metadata.json new file mode 100755 index 0000000..bf8bdb1 --- /dev/null +++ b/build/metadata.json @@ -0,0 +1,38 @@ +{ + "replacing": { + + }, + "long_description": "", + "attributes": { + + }, + "maintainer": "37signals", + "recommendations": { + + }, + "license": "Apache v2.0", + "recipes": { + "build": "" + }, + "maintainer_email": "sysadmins@37signals.com", + "suggestions": { + + }, + "dependencies": { + + }, + "conflicting": { + + }, + "platforms": { + + }, + "description": "Configures build dependencies", + "version": "0.1.0", + "name": "build", + "providing": { + "build": [ + + ] + } +} \ No newline at end of file diff --git a/build/metadata.rb b/build/metadata.rb new file mode 100755 index 0000000..00bb229 --- /dev/null +++ b/build/metadata.rb @@ -0,0 +1,4 @@ +maintainer "37signals" +maintainer_email "sysadmins@37signals.com" +description "Configures build dependencies" +version "0.1" \ No newline at end of file diff --git a/build/recipes/default.rb b/build/recipes/default.rb new file mode 100755 index 0000000..e4a30b6 --- /dev/null +++ b/build/recipes/default.rb @@ -0,0 +1,41 @@ +case node[:platform] +when "ubuntu","debian" + %w{build-essential binutils-doc}.each do |pkg| + package pkg do + action :install + end + end +when "centos" + package "gcc" do + action :install + end +end + +package "autoconf" do + action :install +end + +package "flex" do + action :install +end + +package "bison" do + action :install +end + +gem_package "git_remote_branch" + +directory "/usr/local/build" do + action :create + owner "root" + group "admin" + mode 0775 +end + +if node[:build] + node[:build].each do |name, config| + config[:packages].each do |pack| + package pack + end + end +end \ No newline at end of file diff --git a/capistrano/definitions/cap_setup.rb b/capistrano/definitions/cap_setup.rb new file mode 100644 index 0000000..997062a --- /dev/null +++ b/capistrano/definitions/cap_setup.rb @@ -0,0 +1,46 @@ +# +# Cookbook Name:: capistrano +# Definition:: cap_setup +# +# Copyright 2009, Opscode, 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. +# + +define :cap_setup, :path => nil, :owner => "root", :group => "root", :appowner => "nobody" do + include_recipe "capistrano" + + directory params[:path] do + owner params[:owner] + group params[:group] + mode 0755 + end + + # after chef-174 fixed, change mode to 2775 + %w{ releases shared }.each do |dir| + directory "#{params[:path]}/#{dir}" do + owner params[:owner] + group params[:group] + mode 0775 + end + end + + %w{ log system }.each do |dir| + directory "#{params[:path]}/shared/#{dir}" do + owner params[:appowner] + group params[:group] + mode 0775 + end + end + +end diff --git a/capistrano/metadata.json b/capistrano/metadata.json new file mode 100644 index 0000000..3976c89 --- /dev/null +++ b/capistrano/metadata.json @@ -0,0 +1,59 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs Capistrano gem and provides a define to set up deployment for an application", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "capistrano": "", + "capistrano": "Installs Capistrano gem" + }, + "suggestions": { + + }, + "platforms": { + "freebsd": [ + + ], + "ubuntu": [ + + ], + "openbsd": [ + + ], + "fedora": [ + + ], + "centos": [ + + ], + "redhat": [ + + ], + "debian": [ + + ] + }, + "version": "0.7.0", + "name": "capistrano", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "capistrano": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/capistrano/metadata.rb b/capistrano/metadata.rb new file mode 100644 index 0000000..040a65f --- /dev/null +++ b/capistrano/metadata.rb @@ -0,0 +1,9 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs Capistrano gem and provides a define to set up deployment for an application" +version "0.7" +recipe "capistrano", "Installs Capistrano gem" +%w{ ubuntu debian redhat centos fedora freebsd openbsd }.each do |os| + supports os +end diff --git a/capistrano/recipes/default.rb b/capistrano/recipes/default.rb new file mode 100644 index 0000000..39e27ba --- /dev/null +++ b/capistrano/recipes/default.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: capistrano +# Recipe:: default +# +# Copyright 2009, Opscode, 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. +# + +gem_package "capistrano" diff --git a/chef/README.rdoc b/chef/README.rdoc new file mode 100644 index 0000000..0a21e31 --- /dev/null +++ b/chef/README.rdoc @@ -0,0 +1,221 @@ += IMPORTANT CHANGES: + +First be aware of important changes in this version from previous versions. + +== General: + +The attributes have been consolidated into one file, chef.rb, rather than split amongst chef.rb, client.rb, indexer.rb and server.rb. + +== Client: + +This cookbook no longer manages the chef package version, it manages /etc/chef/client.rb, reloads the configuration using the new ruby_block resource if the template changes. + +The client service is not managed at all. It is assumed to be set up via init script or runit from package installation or bootstrap. + +== Server: + +*This cookbook no longer configures a Chef Server under Passenger by default.* + +The stompserver and couchdb cookbooks are not included by default. See below under Cookbooks requirements. + +The default server recipe (chef::server) sets up two Merb Mongrel workers for the webui/api (port 4000) and openid (port 4001). + +The default server recipe (chef::server), creates but does not manage the chef-indexer and chef-server services, and configures both from /etc/chef/server.rb. Some package installation methods (e.g., Debian) have a separate config file for chef-indexer. + +The chef::server_proxy recipe sets up an Apache proxy vhost to provide SSL in front of the chef-server running as a Merb application. + += DESCRIPTION: + +Use this cookbook to configure a chef client to connect to your preferred chef-server, or config a chef-server. + += REQUIREMENTS: + +Chef v0.7.10, for attribute 'default' syntax. + +== Platform: + +Server is tested on Ubuntu 9.10, 9.04, 8.10 and 8.04, Debian 5.0. + +Client is tested on the above, plus CentOS 5.3, Fedora 10, OpenBSD 4.6, FreeBSD 7.1 and Gentoo. + +== Cookbooks: + +Client: + +runit is suggested for RubyGem installations. Clients do not require any other cookbooks. + +Server: + +couchdb and stompserver are suggested for RubyGem installations. On systems where Chef and dependencies were installed from platform packages, CouchDB and Stompserver should be installed and configured sufficiently. Localised configuration requires additional changes to the server recipe and may require changes when using the Opscode recipes. + +Server using server_proxy: + +* apache2 (opscode/cookbooks) + += ATTRIBUTES: + +*A note about paths:* We try to stick with generally accepted FHS guidelines for path locations, but you might need to adjust these for your platform. See the filesystem hierarchy documentation for your operating system if you're not sure. + +=== url_type + +Set up the URLs the client should connect to with this. Default is 'http', which tells the client to connect to 'http://server:4000'. If you set up your chef-server to use an SSL front-end for example with chef::server_proxy, set this to 'https' and the URLs will be 'https://server/'. + +=== init_style + +Specifies the init style to use. Default 'runit'. Other possible values 'init', 'bsd', any other string will be treated as unknown. + +If your platform doesn't have a 'runit' package or if the cookbook doesn't detect it, but you stil want to use runit, set init_style to 'none' and install runit separately. + +=== path + +This is the base location where chef will store its associated data. Default '/srv/chef' for RubyGems installed systems. The location preference varies by platform. The default is a filesystem hiearchy standard suggestion[1]. Some other locations you may consider, by platform: + +Debian and Red Hat based Linux distros (Ubuntu, CentOS, Fedora, etc): + +* /var/lib/chef + +Any BSD and Gentoo: + +* /var/chef + +=== run_path + +Location for pidfiles on systems using init scripts. Default '/var/run/chef'. + +If init_style is 'init', this is used, and should match what the init script itself uses for the PID files. + +=== cache_path + +Location where the client will cache cookbooks and other data. Default is 'cache' underneath the bootstrap[:chef][:path] location. Linux distributions might prefer /var/cache/chef instead. + +=== serve_path + +Used by the Chef server as the base location to "serve" cookbooks, roles and other assets. Default is /srv/chef. + +=== server_version, client_version + +Set the version Chef. This is now unused in the chef cookbook for any specific configuration but you can optionally override the opscode recipe with one that manages the specific version of Chef installed. Default is the latest Chef release. Informational messages may be printed using the veresion, though. + +=== client_interval + +Number of seconds to run chef-client periodically. Default '1800' (30 minutes). + +=== client_splay + +Splay interval to randomly add to interval. Default '20'. + +=== log_dir + +Directory where logs are stored if logs are not sent to STDOUT. Systems using runit should send logs to STDOUT as runit manages log output. Default STDOUT when init_style is 'runit', otherwise the default is '/var/log/chef'. + +=== client_log, indexer_log, server_log + +Location of the client, indexer and server logs, respectively. Default 'STDOUT' on systems with runit, '/var/log/chef/{client,indexer,server}.log' on other systems. + +=== server_fqdn + +Fully qualified domain name of the server. Default is 'chef.domain' where domain is detected by Ohai. You should configure a DNS entry for your Chef Server. + +On servers, this specifies the URLs the server expects, plus it is used in the server_ssl_req as the canonical name (CN) and in server_proxy for the vhost name. + +On clients, this specifies the URLs the client uses to connect to the server. + +=== server_token + +The validation_token used to automatically authorize chef-clients. Default is a random string generated every time chef-solo runs, and can be stored as a node attribute on the server. Use chef-client -t 'validation_token' to automatically validate the client. + +=== server_ssl_req + +Used by the server_proxy recipe, this attribute can be used to set up a self-signed SSL certificate automatically using openssl. Fields: + +* C: country (two letter code) +* ST: state/province +* L: locality or city +* O: organization +* OU: organizational unit +* CN: canonical name, usually the fully qualified domain name of the server (FQDN) +* emailAddress: contact email address + += USAGE: + +This cookbook is primarily designed to configure a Chef client or server with the /etc/chef/ configuration files. Server services should be restarted when the config file changes. The running client configuration will get reloaded from the template if it changes. + +The primary usage would be to set up a JSON file used with chef-client -j to set the run_list and attributes. The settings could alternately be put in a role, as well. When the JSON is used, node will have the run_list and attributes saved in the Chef Server it connected to. + +Example JSON to set up a client: + + { + "chef": { + "url_type": "https", + "init_style": "init", + "server_fqdn": "chef.example.com" + }, + "recipes": "chef::client" + } + +This will tell the client to use the https style URLs (see chef::client below), that we'll have init scripts set up, and to connect to the server "chef.example.com" + +=== Passenger Not Used: + +As mentioned above, Passenger is no longer used as the default. Use the server_proxy recipe to create an SSL front-end. + +== Server Default (chef::server) + +By default, the server is setup to run as a standard Merb application with the Mongrel adapter, using the package installation or the bootstrap cookbook. The chef::server recipe is used to maintain the configuration. + +When using chef::server only, clients can use the default value for url_type (http). + +== Server Proxy (chef::server_proxy) + +If you would like to set up an SSL front end for your server, use the chef::server_proxy recipe. + +When using this recipe, clients should have the url_type attribute set to "https". + +You will need to edit the server_ssl_request attribute so the certificate is generated correctly. + +The recipe itself will set up the Apache proxy: + +* Add port 444 to the listen_ports (Apache's ports.conf), required for OpenID. +* Enable Apache modules proxy proxy_http proxy_balancer ssl rewrite headers +* Create the SSL certificate based on the server_ssl_req attribute. +* Set up and enable virtual hosts on ports 443 and 444 in the site config "chef_server.conf". + +The proxy will send requests from port 443 to the Mongrel running on port 4000 (webui/api) and requests on port 444 to the Mongrel on port 4001 (openid). Be sure to adjust any firewall rules or security group settings appropriately for these ports (4000, 4001, 443, 444). + +=== SSL Certificates + +The server_proxy recipe will generate a self-signed PEM certificate on the first run. If you use opscode's chef-repo, use rake to generate your own site-specific certificate if you wish. You can also use a purchased certificate to replace the one generated through this cookbook, but it must be named by the fully qualified domain name as used in the server_fqdn attribute. + +== Client Default (chef::client) + +If your Chef Server's fully qualified domain name is not "chef.domain" where domain is the node attribute detected by ohai, then you'll need to specify the server_fqdn attribute for your clients. + +You may want to adjust the path attributes as described above. + +Make sure you specify the correct url_type for your Chef Server. This will create the URLs in the client config file as so: + +http:: http://chef.domain:4000/ + +https:: https://chef.domain/ + +(the openid_url will be :4001 and :444 respectively.) + += LICENSE and AUTHOR: + +Author:: Joshua Timberman +Author:: Joshua Sierles + +Copyright 2008-2009, Opscode, Inc +Copyright 2009, 37signals + +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/chef/attributes/chef.rb b/chef/attributes/chef.rb new file mode 100644 index 0000000..7f24af8 --- /dev/null +++ b/chef/attributes/chef.rb @@ -0,0 +1,61 @@ +# +# Author:: Joshua Timberman +# Cookbook Name:: chef +# Attributes:: chef +# +# Copyright 2008-2009, Opscode, 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. + +validation_token = "" +chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a +20.times { |i| validation_token << chars[rand(chars.size-1)] } + +set_unless[:chef][:umask] = 0022 +set_unless[:chef][:url_type] = "http" +set_unless[:chef][:init_style] = "runit" + +case platform +when "openbsd","freebsd" + set_unless[:chef][:path] = "/var/chef" + set_unless[:chef][:run_path] = "/var/run" + set_unless[:chef][:cache_path] = "/var/chef/cache" + set_unless[:chef][:serve_path] = "/var/chef" +else + set_unless[:chef][:path] = "/srv/chef" + set_unless[:chef][:run_path] = "/var/run/chef" + set_unless[:chef][:cache_path] = "#{chef[:path]}/cache" + set_unless[:chef][:serve_path] = "/srv/chef" +end + +set_unless[:chef][:server_version] = "0.7.16" +set_unless[:chef][:client_version] = "0.7.16" +set_unless[:chef][:client_interval] = "1800" +set_unless[:chef][:client_splay] = "20" +set_unless[:chef][:log_dir] = "/var/log/chef" + +case chef[:init_style] +when "runit" + set_unless[:chef][:client_log] = "STDOUT" + set_unless[:chef][:indexer_log] = "STDOUT" + set_unless[:chef][:server_log] = "STDOUT" +else + set_unless[:chef][:client_log] = "#{chef[:log_dir]}/client.log" + set_unless[:chef][:indexer_log] = "#{chef[:log_dir]}/indexer.log" + set_unless[:chef][:server_log] = "#{chef[:log_dir]}/server.log" +end + +set_unless[:chef][:server_fqdn] = domain ? "chef.#{domain}" : "chef" +set_unless[:chef][:server_token] = validation_token +set_unless[:chef][:server_ssl_req] = "/C=US/ST=Several/L=Locality/O=Example/OU=Operations/" + + "CN=#{chef[:server_fqdn]}/emailAddress=ops@#{domain}" diff --git a/chef/attributes/server_proxy.rb b/chef/attributes/server_proxy.rb new file mode 100644 index 0000000..b1657a0 --- /dev/null +++ b/chef/attributes/server_proxy.rb @@ -0,0 +1,23 @@ +# +# Author:: David Abdemoulaie +# Cookbook Name:: chef +# Attributes:: server_proxy +# +# Copyright 2009, David Abdemoulaie +# +# 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. + +set_unless[:chef][:doc_root] = "/usr/share/chef-server-slice/public" + +set_unless[:chef][:server_proxy][:css_expire_hours] = "120" +set_unless[:chef][:server_proxy][:js_expire_hours] = "24" \ No newline at end of file diff --git a/chef/metadata.json b/chef/metadata.json new file mode 100644 index 0000000..ff57f34 --- /dev/null +++ b/chef/metadata.json @@ -0,0 +1,276 @@ +{ + "dependencies": { + "passenger_apache2": [ + + ], + "stompserver": [ + + ], + "packages": [ + + ], + "runit": [ + + ], + "couchdb": [ + + ], + "apache2": [ + + ] + }, + "maintainer_email": "cookbooks@opscode.com", + "conflicting": { + + }, + "description": "Installs and configures chef client and server", + "recipes": { + "chef::server": "Configures a chef-server as a passenger application", + "chef::server_proxy": "", + "chef::client": "Sets up a client to talk to a chef-server", + "chef": "" + }, + "providing": { + "chef::server": [ + + ], + "chef::server_proxy": [ + + ], + "chef": [ + + ], + "chef::client": [ + + ] + }, + "platforms": { + "ubuntu": [ + + ], + "rhel": [ + + ], + "centos": [ + + ], + "debian": [ + + ] + }, + "version": "0.13.0", + "name": "chef", + "replacing": { + + }, + "groupings": { + + }, + "long_description": "= IMPORTANT CHANGES:\n\nFirst be aware of important changes in this version from previous versions.\n\n== General:\n\nThe attributes have been consolidated into one file, chef.rb, rather than split amongst chef.rb, client.rb, indexer.rb and server.rb.\n\n== Client:\n\nThis cookbook no longer manages the chef package version, it manages /etc/chef/client.rb, reloads the configuration using the new ruby_block resource if the template changes.\n\nThe client service is not managed at all. It is assumed to be set up via init script or runit from package installation or bootstrap.\n\n== Server:\n\n*This cookbook no longer configures a Chef Server under Passenger by default.* \n\nThe stompserver and couchdb cookbooks are not included by default. See below under Cookbooks requirements.\n\nThe default server recipe (chef::server) sets up two Merb Mongrel workers for the webui/api (port 4000) and openid (port 4001).\n\nThe default server recipe (chef::server), creates but does not manage the chef-indexer and chef-server services, and configures both from /etc/chef/server.rb. Some package installation methods (e.g., Debian) have a separate config file for chef-indexer.\n\nThe chef::server_proxy recipe sets up an Apache proxy vhost to provide SSL in front of the chef-server running as a Merb application.\n\n= DESCRIPTION:\n\nUse this cookbook to configure a chef client to connect to your preferred chef-server, or config a chef-server.\n\n= REQUIREMENTS:\n\nChef v0.7.10, for attribute 'default' syntax.\n\n== Platform:\n\nServer is tested on Ubuntu 9.10, 9.04, 8.10 and 8.04, Debian 5.0.\n\nClient is tested on the above, plus CentOS 5.3, Fedora 10, OpenBSD 4.6, FreeBSD 7.1 and Gentoo.\n\n== Cookbooks:\n\nClient: \n\nrunit is suggested for RubyGem installations. Clients do not require any other cookbooks.\n\nServer:\n\ncouchdb and stompserver are suggested for RubyGem installations. On systems where Chef and dependencies were installed from platform packages, CouchDB and Stompserver should be installed and configured sufficiently. Localised configuration requires additional changes to the server recipe and may require changes when using the Opscode recipes.\n\nServer using server_proxy:\n\n* apache2 (opscode/cookbooks)\n\n= ATTRIBUTES:\n\n*A note about paths:* We try to stick with generally accepted FHS guidelines for path locations, but you might need to adjust these for your platform. See the filesystem hierarchy documentation for your operating system if you're not sure.\n\n=== url_type\n\nSet up the URLs the client should connect to with this. Default is 'http', which tells the client to connect to 'http://server:4000'. If you set up your chef-server to use an SSL front-end for example with chef::server_proxy, set this to 'https' and the URLs will be 'https://server/'. \n\n=== init_style\n\nSpecifies the init style to use. Default 'runit'. Other possible values 'init', 'bsd', any other string will be treated as unknown.\n\nIf your platform doesn't have a 'runit' package or if the cookbook doesn't detect it, but you stil want to use runit, set init_style to 'none' and install runit separately.\n\n=== path\n\nThis is the base location where chef will store its associated data. Default '/srv/chef' for RubyGems installed systems. The location preference varies by platform. The default is a filesystem hiearchy standard suggestion[1]. Some other locations you may consider, by platform:\n\nDebian and Red Hat based Linux distros (Ubuntu, CentOS, Fedora, etc):\n\n* /var/lib/chef\n\nAny BSD and Gentoo:\n\n* /var/chef\n\n=== run_path\n\nLocation for pidfiles on systems using init scripts. Default '/var/run/chef'.\n\nIf init_style is 'init', this is used, and should match what the init script itself uses for the PID files.\n\n=== cache_path\n\nLocation where the client will cache cookbooks and other data. Default is 'cache' underneath the bootstrap[:chef][:path] location. Linux distributions might prefer /var/cache/chef instead.\n\n=== serve_path\n\nUsed by the Chef server as the base location to \"serve\" cookbooks, roles and other assets. Default is /srv/chef.\n\n=== server_version, client_version\n\nSet the version Chef. This is now unused in the chef cookbook for any specific configuration but you can optionally override the opscode recipe with one that manages the specific version of Chef installed. Default is the latest Chef release. Informational messages may be printed using the veresion, though.\n\n=== client_interval\n\nNumber of seconds to run chef-client periodically. Default '1800' (30 minutes).\n\n=== client_splay\n\nSplay interval to randomly add to interval. Default '20'.\n\n=== log_dir\n\nDirectory where logs are stored if logs are not sent to STDOUT. Systems using runit should send logs to STDOUT as runit manages log output. Default STDOUT when init_style is 'runit', otherwise the default is '/var/log/chef'.\n\n=== client_log, indexer_log, server_log\n\nLocation of the client, indexer and server logs, respectively. Default 'STDOUT' on systems with runit, '/var/log/chef/{client,indexer,server}.log' on other systems.\n\n=== server_fqdn\n\nFully qualified domain name of the server. Default is 'chef.domain' where domain is detected by Ohai. You should configure a DNS entry for your Chef Server.\n\nOn servers, this specifies the URLs the server expects, plus it is used in the server_ssl_req as the canonical name (CN) and in server_proxy for the vhost name.\n\nOn clients, this specifies the URLs the client uses to connect to the server.\n\n=== server_token\n\nThe validation_token used to automatically authorize chef-clients. Default is a random string generated every time chef-solo runs, and can be stored as a node attribute on the server. Use chef-client -t 'validation_token' to automatically validate the client.\n\n=== server_ssl_req\n\nUsed by the server_proxy recipe, this attribute can be used to set up a self-signed SSL certificate automatically using openssl. Fields:\n\n* C: country (two letter code)\n* ST: state/province\n* L: locality or city\n* O: organization\n* OU: organizational unit\n* CN: canonical name, usually the fully qualified domain name of the server (FQDN)\n* emailAddress: contact email address\n\n= USAGE:\n\nThis cookbook is primarily designed to configure a Chef client or server with the /etc/chef/ configuration files. Server services should be restarted when the config file changes. The running client configuration will get reloaded from the template if it changes.\n\nThe primary usage would be to set up a JSON file used with chef-client -j to set the run_list and attributes. The settings could alternately be put in a role, as well. When the JSON is used, node will have the run_list and attributes saved in the Chef Server it connected to.\n\nExample JSON to set up a client:\n\n {\n \"chef\": {\n \"url_type\": \"https\",\n \"init_style\": \"init\",\n \"server_fqdn\": \"chef.example.com\"\n },\n \"recipes\": \"chef::client\"\n }\n\nThis will tell the client to use the https style URLs (see chef::client below), that we'll have init scripts set up, and to connect to the server \"chef.example.com\"\n\n=== Passenger Not Used:\n\nAs mentioned above, Passenger is no longer used as the default. Use the server_proxy recipe to create an SSL front-end.\n\n== Server Default (chef::server)\n\nBy default, the server is setup to run as a standard Merb application with the Mongrel adapter, using the package installation or the bootstrap cookbook. The chef::server recipe is used to maintain the configuration.\n\nWhen using chef::server only, clients can use the default value for url_type (http).\n\n== Server Proxy (chef::server_proxy)\n\nIf you would like to set up an SSL front end for your server, use the chef::server_proxy recipe.\n\nWhen using this recipe, clients should have the url_type attribute set to \"https\".\n\nYou will need to edit the server_ssl_request attribute so the certificate is generated correctly.\n\nThe recipe itself will set up the Apache proxy:\n\n* Add port 444 to the listen_ports (Apache's ports.conf), required for OpenID.\n* Enable Apache modules proxy proxy_http proxy_balancer ssl rewrite headers\n* Create the SSL certificate based on the server_ssl_req attribute.\n* Set up and enable virtual hosts on ports 443 and 444 in the site config \"chef_server.conf\".\n\nThe proxy will send requests from port 443 to the Mongrel running on port 4000 (webui/api) and requests on port 444 to the Mongrel on port 4001 (openid). Be sure to adjust any firewall rules or security group settings appropriately for these ports (4000, 4001, 443, 444).\n\n=== SSL Certificates\n\nThe server_proxy recipe will generate a self-signed PEM certificate on the first run. If you use opscode's chef-repo, use rake to generate your own site-specific certificate if you wish. You can also use a purchased certificate to replace the one generated through this cookbook, but it must be named by the fully qualified domain name as used in the server_fqdn attribute.\n\n== Client Default (chef::client)\n\nIf your Chef Server's fully qualified domain name is not \"chef.domain\" where domain is the node attribute detected by ohai, then you'll need to specify the server_fqdn attribute for your clients. \n\nYou may want to adjust the path attributes as described above.\n\nMake sure you specify the correct url_type for your Chef Server. This will create the URLs in the client config file as so:\n\nhttp:: http://chef.domain:4000/\n\nhttps:: https://chef.domain/\n\n(the openid_url will be :4001 and :444 respectively.)\n\n= LICENSE and AUTHOR:\n\nAuthor:: Joshua Timberman \nAuthor:: Joshua Sierles \n\nCopyright 2008-2009, Opscode, Inc\nCopyright 2009, 37signals\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n", + "attributes": { + "chef/server_ssl_req": { + "default": "/C=US/ST=Several/L=Locality/O=Example/OU=Operations/CN=chef_server_fqdn/emailAddress=ops@domain", + "calculated": false, + "type": "string", + "choice": [ + + ], + "description": "Data to pass for creating the SSL certificate", + "display_name": "Chef Server SSL Request", + "required": "optional", + "recipes": [ + + ] + }, + "chef/server_path": { + "default": "gem_dir/gems/chef-server-chef_server_version", + "calculated": false, + "type": "string", + "choice": [ + + ], + "description": "Location of the Chef Server assets", + "display_name": "Chef Server Path", + "required": "optional", + "recipes": [ + + ] + }, + "chef/run_path": { + "default": "/var/run/chef", + "calculated": false, + "type": "string", + "choice": [ + + ], + "description": "Filesystem location for Chef 'run' files", + "display_name": "Chef Run Path", + "required": "optional", + "recipes": [ + + ] + }, + "chef/client_log": { + "default": "STDOUT", + "calculated": false, + "type": "string", + "choice": [ + + ], + "description": "Location of the chef client log", + "display_name": "Chef Client Log", + "required": "optional", + "recipes": [ + + ] + }, + "chef/path": { + "default": "/srv/chef", + "calculated": false, + "type": "string", + "choice": [ + + ], + "description": "Filesystem location for Chef files", + "display_name": "Chef Path", + "required": "optional", + "recipes": [ + + ] + }, + "chef/server_log": { + "default": "/var/log/chef/server.log", + "calculated": false, + "type": "string", + "choice": [ + + ], + "description": "Location of the Chef server log", + "display_name": "Chef Server Log", + "required": "optional", + "recipes": [ + + ] + }, + "chef/client_splay": { + "default": "20", + "calculated": false, + "type": "string", + "choice": [ + + ], + "description": "Random number of seconds to add to interval", + "display_name": "Chef Client Splay ", + "required": "optional", + "recipes": [ + + ] + }, + "chef/client_version": { + "default": "0.7.10", + "calculated": false, + "type": "string", + "choice": [ + + ], + "description": "Set the version of the client gem to install", + "display_name": "Chef Client Version", + "required": "optional", + "recipes": [ + + ] + }, + "chef/server_fqdn": { + "default": "hostname.domain", + "calculated": false, + "type": "string", + "choice": [ + + ], + "description": "FQDN of the Chef server for Apache vhost and SSL certificate and clients", + "display_name": "Chef Server Fully Qualified Domain Name", + "required": "optional", + "recipes": [ + + ] + }, + "chef/server_version": { + "default": "0.7.10", + "calculated": false, + "type": "string", + "choice": [ + + ], + "description": "Set the version of the server and server-slice gems to install", + "display_name": "Chef Server Version", + "required": "optional", + "recipes": [ + + ] + }, + "chef/indexer_log": { + "default": "/var/log/chef/indexer.log", + "calculated": false, + "type": "string", + "choice": [ + + ], + "description": "Location of the chef-indexer log", + "display_name": "Chef Indexer Log ", + "required": "optional", + "recipes": [ + + ] + }, + "chef/client_interval": { + "default": "1800", + "calculated": false, + "type": "string", + "choice": [ + + ], + "description": "Poll chef client process to run on this interval in seconds", + "display_name": "Chef Client Interval ", + "required": "optional", + "recipes": [ + + ] + }, + "chef/server_token": { + "default": "randomly generated", + "calculated": false, + "type": "string", + "choice": [ + + ], + "description": "Value of the validation_token", + "display_name": "Chef Server Validation Token", + "required": "optional", + "recipes": [ + + ] + }, + "chef/server_hostname": { + "default": "hostname", + "calculated": false, + "type": "string", + "choice": [ + + ], + "description": "Hostname for the chef server, for building FQDN", + "display_name": "Chef Server Hostname", + "required": "optional", + "recipes": [ + + ] + } + }, + "recommendations": { + + }, + "license": "Apache 2.0", + "maintainer": "Opscode, Inc.", + "suggestions": { + + } +} \ No newline at end of file diff --git a/chef/metadata.rb b/chef/metadata.rb new file mode 100644 index 0000000..b465d13 --- /dev/null +++ b/chef/metadata.rb @@ -0,0 +1,87 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs and configures chef client and server" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.13" +recipe "chef::client", "Sets up a client to talk to a chef-server" +recipe "chef::server", "Configures a chef-server as a passenger application" + +%w{ runit packages couchdb stompserver apache2 passenger_apache2 }.each do |cb| + depends cb +end + +%w{ centos rhel ubuntu debian }.each do |os| + supports os +end + +attribute "chef/path", + :display_name => "Chef Path", + :description => "Filesystem location for Chef files", + :default => "/srv/chef" + +attribute "chef/run_path", + :display_name => "Chef Run Path", + :description => "Filesystem location for Chef 'run' files", + :default => "/var/run/chef" + +attribute "chef/client_version", + :display_name => "Chef Client Version", + :description => "Set the version of the client gem to install", + :default => "0.7.10" + +attribute "chef/client_interval", + :display_name => "Chef Client Interval ", + :description => "Poll chef client process to run on this interval in seconds", + :default => "1800" + +attribute "chef/client_splay", + :display_name => "Chef Client Splay ", + :description => "Random number of seconds to add to interval", + :default => "20" + +attribute "chef/client_log", + :display_name => "Chef Client Log", + :description => "Location of the chef client log", + :default => "STDOUT" + +attribute "chef/indexer_log", + :display_name => "Chef Indexer Log ", + :description => "Location of the chef-indexer log", + :default => "/var/log/chef/indexer.log" + +attribute "chef/server_version", + :display_name => "Chef Server Version", + :description => "Set the version of the server and server-slice gems to install", + :default => "0.7.10" + +attribute "chef/server_log", + :display_name => "Chef Server Log", + :description => "Location of the Chef server log", + :default => "/var/log/chef/server.log" + +attribute "chef/server_path", + :display_name => "Chef Server Path", + :description => "Location of the Chef Server assets", + :default => "gem_dir/gems/chef-server-chef_server_version" + +attribute "chef/server_hostname", + :display_name => "Chef Server Hostname", + :description => "Hostname for the chef server, for building FQDN", + :default => "hostname" + +attribute "chef/server_fqdn", + :display_name => "Chef Server Fully Qualified Domain Name", + :description => "FQDN of the Chef server for Apache vhost and SSL certificate and clients", + :default => "hostname.domain" + +attribute "chef/server_ssl_req", + :display_name => "Chef Server SSL Request", + :description => "Data to pass for creating the SSL certificate", + :default => "/C=US/ST=Several/L=Locality/O=Example/OU=Operations/CN=chef_server_fqdn/emailAddress=ops@domain" + +attribute "chef/server_token", + :display_name => "Chef Server Validation Token", + :description => "Value of the validation_token", + :default => "randomly generated" + diff --git a/chef/recipes/client.rb b/chef/recipes/client.rb new file mode 100644 index 0000000..999b855 --- /dev/null +++ b/chef/recipes/client.rb @@ -0,0 +1,64 @@ +# +# Author:: Joshua Timberman +# Author:: Joshua Sierles +# Cookbook Name:: chef +# Recipe:: client +# +# Copyright 2008-2009, Opscode, Inc +# Copyright 2009, 37signals +# +# 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. + +root_group = value_for_platform( + "openbsd" => { "default" => "wheel" }, + "freebsd" => { "default" => "wheel" }, + "default" => "root" +) + +if node[:chef][:client_log] == "STDOUT" + client_log = node[:chef][:client_log] + show_time = "false" +else + client_log = "\"#{node[:chef][:client_log]}\"" + show_time = "true" +end + +ruby_block "reload_client_config" do + block do + Chef::Config.from_file("/etc/chef/client.rb") + end + action :nothing +end + +template "/etc/chef/client.rb" do + source "client.rb.erb" + owner "root" + group root_group + mode "644" + variables( + :client_log => client_log, + :show_time => show_time + ) + notifies :create, resources(:ruby_block => "reload_client_config") +end + +execute "Register client node with Chef Server" do + command "/usr/bin/env chef-client -t \`cat /etc/chef/validation_token\`" + only_if { File.exists?("/etc/chef/validation_token") } + not_if { File.exists?("#{node[:chef][:path]}/cache/registration") } +end + +execute "Remove the validation token" do + command "rm /etc/chef/validation_token" + only_if { File.exists?("/etc/chef/validation_token") } +end diff --git a/chef/recipes/default.rb b/chef/recipes/default.rb new file mode 100644 index 0000000..e69de29 diff --git a/chef/recipes/server.rb b/chef/recipes/server.rb new file mode 100644 index 0000000..78e4ac0 --- /dev/null +++ b/chef/recipes/server.rb @@ -0,0 +1,75 @@ +# +# Author:: Joshua Timberman +# Author:: Joshua Sierles +# Cookbook Name:: chef +# Recipe:: server +# +# Copyright 2008-2009, Opscode, Inc +# Copyright 2009, 37signals +# +# 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. + +root_group = value_for_platform( + "openbsd" => { "default" => "wheel" }, + "freebsd" => { "default" => "wheel" }, + "default" => "root" +) + +include_recipe "chef::client" + +service "chef-indexer" do + action :nothing +end + +service "chef-server" do + action :nothing + if node[:chef][:init_style] == "runit" + restart_command "sv int chef-server" + end +end + +if node[:chef][:server_log] == "STDOUT" + server_log = node[:chef][:server_log] + show_time = "false" +else + server_log = "\"#{node[:chef][:server_log]}\"" + show_time = "true" +end + +template "/etc/chef/server.rb" do + source "server.rb.erb" + owner "root" + group root_group + mode "644" + variables( + :server_log => server_log, + :show_time => show_time + ) + notifies :restart, resources( + :service => "chef-indexer", + :service => "chef-server" + ), :delayed +end + +http_request "compact chef couchDB" do + action :post + url "#{Chef::Config[:couchdb_url]}/_compact" + only_if do + begin + open("#{Chef::Config[:couchdb_url]}/chef") + JSON::parse(open("#{Chef::Config[:couchdb_url]}/chef").read)["disk_size"] > 100_000_000 + rescue OpenURI::HTTPError + nil + end + end +end diff --git a/chef/recipes/server_proxy.rb b/chef/recipes/server_proxy.rb new file mode 100644 index 0000000..95aa687 --- /dev/null +++ b/chef/recipes/server_proxy.rb @@ -0,0 +1,61 @@ +# +# Author:: Joshua Timberman +# Cookbook Name:: chef +# Recipe:: server_proxy +# +# Copyright 2009, Opscode, 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. + +root_group = value_for_platform( + "openbsd" => { "default" => "wheel" }, + "freebsd" => { "default" => "wheel" }, + "default" => "root" +) + +node[:apache][:listen_ports] << "444" unless node[:apache][:listen_ports].include?("444") + +include_recipe "chef::server" +include_recipe "apache2" +include_recipe "apache2::mod_ssl" +include_recipe "apache2::mod_proxy" +include_recipe "apache2::mod_proxy_http" +include_recipe "apache2::mod_proxy_balancer" +include_recipe "apache2::mod_rewrite" +include_recipe "apache2::mod_headers" +include_recipe "apache2::mod_expires" +include_recipe "apache2::mod_deflate" + +directory "/etc/chef/certificates" do + owner "root" + group root_group + mode "700" +end + +bash "Create SSL Certificates" do + cwd "/etc/chef/certificates" + code <<-EOH + umask 077 + openssl genrsa 2048 > #{node[:chef][:server_fqdn]}.key + openssl req -subj "#{node[:chef][:server_ssl_req]}" -new -x509 -nodes -sha1 -days 3650 -key #{node[:chef][:server_fqdn]}.key > #{node[:chef][:server_fqdn]}.crt + cat #{node[:chef][:server_fqdn]}.key #{node[:chef][:server_fqdn]}.crt > #{node[:chef][:server_fqdn]}.pem + EOH + not_if { File.exists?("/etc/chef/certificates/#{node[:chef][:server_fqdn]}.pem") } +end + +web_app "chef_server" do + template "chef_server.conf.erb" + server_name node[:chef][:server_fqdn] + server_aliases [ node[:hostname], node[:fqdn], node[:chef][:server_fqdn] ] + log_dir node[:apache][:log_dir] +end diff --git a/chef/templates/default/chef_server.conf.erb b/chef/templates/default/chef_server.conf.erb new file mode 100644 index 0000000..8eaf49b --- /dev/null +++ b/chef/templates/default/chef_server.conf.erb @@ -0,0 +1,65 @@ + + ServerName <%= @params[:server_name] %> + ServerAlias <% @params[:server_aliases].each do |a| %><%= "#{a}" %> <% end %> + + DocumentRoot <%= @node[:chef][:doc_root] %> + + ExpiresActive On + ExpiresByType text/css "access plus <%= @node[:chef][:server_proxy][:css_expire_hours] %> hours" + ExpiresByType text/javascript "access plus <%= @node[:chef][:server_proxy][:js_expire_hours] %> hours" + ExpiresByType application/x-javascript "access plus <%= @node[:chef][:server_proxy][:js_expire_hours] %> hours" + ExpiresByType application/javascript "access plus <%= @node[:chef][:server_proxy][:js_expire_hours] %> hours" + + + BalancerMember http://127.0.0.1:4000 + Order deny,allow + Allow from all + + + LogLevel info + ErrorLog <%= @params[:log_dir] %>/<%= @params[:name] %>-error.log + CustomLog <%= @params[:log_dir] %>/<%= @params[:name] %>-access.log combined + + SSLEngine On + SSLCertificateFile /etc/chef/certificates/<%= @params[:server_name] %>.pem + SSLCertificateKeyFile /etc/chef/certificates/<%= @params[:server_name] %>.pem + + RequestHeader set X_FORWARDED_PROTO 'https' + + RewriteEngine On + RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f + RewriteRule ^/(.*)$ balancer://chef_server%{REQUEST_URI} [P,QSA,L] + + + + ServerName <%= @params[:server_name] %> + ServerAlias <% @params[:server_aliases].each do |a| %><%= "#{a}" %> <% end %> + + DocumentRoot <%= @node[:chef][:doc_root] %> + + ExpiresActive On + ExpiresByType text/css "access plus <%= @node[:chef][:server_proxy][:css_expire_hours] %> hours" + ExpiresByType text/javascript "access plus <%= @node[:chef][:server_proxy][:js_expire_hours] %> hours" + ExpiresByType application/x-javascript "access plus <%= @node[:chef][:server_proxy][:js_expire_hours] %> hours" + ExpiresByType application/javascript "access plus <%= @node[:chef][:server_proxy][:js_expire_hours] %> hours" + + + BalancerMember http://127.0.0.1:4001 + Order deny,allow + Allow from all + + + LogLevel info + ErrorLog <%= @params[:log_dir] %>/<%= @params[:name] %>-error.log + CustomLog <%= @params[:log_dir] %>/<%= @params[:name] %>-access.log combined + + SSLEngine On + SSLCertificateFile /etc/chef/certificates/<%= @params[:server_name] %>.pem + SSLCertificateKeyFile /etc/chef/certificates/<%= @params[:server_name] %>.pem + + RequestHeader set X_FORWARDED_PROTO 'https' + + RewriteEngine On + RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f + RewriteRule ^/(.*)$ balancer://chef_server_openid%{REQUEST_URI} [P,QSA,L] + diff --git a/chef/templates/default/client.rb.erb b/chef/templates/default/client.rb.erb new file mode 100644 index 0000000..a199785 --- /dev/null +++ b/chef/templates/default/client.rb.erb @@ -0,0 +1,30 @@ +# +# Chef Client Config File +# +# Dynamically generated by Chef - local modifications will be replaced +# + +log_level :info +log_location <%= @client_log %> +ssl_verify_mode :verify_none +<% if @node[:chef][:url_type] == "https" -%> +registration_url "https://<%= @node[:chef][:server_fqdn] %>" +openid_url "https://<%= @node[:chef][:server_fqdn] %>:444" +template_url "https://<%= @node[:chef][:server_fqdn] %>" +remotefile_url "https://<%= @node[:chef][:server_fqdn] %>" +search_url "https://<%= @node[:chef][:server_fqdn] %>" +role_url "https://<%= @node[:chef][:server_fqdn] %>" +<% else -%> +registration_url "http://<%= @node[:chef][:server_fqdn] %>:4000" +openid_url "http://<%= @node[:chef][:server_fqdn] %>:4001" +template_url "http://<%= @node[:chef][:server_fqdn] %>:4000" +remotefile_url "http://<%= @node[:chef][:server_fqdn] %>:4000" +search_url "http://<%= @node[:chef][:server_fqdn] %>:4000" +role_url "http://<%= @node[:chef][:server_fqdn] %>:4000" +<% end -%> + +file_cache_path "<%= @node[:chef][:cache_path] %>" + +pid_file "<%= @node[:chef][:run_path] %>/client.pid" + +Chef::Log::Formatter.show_time = <%= @show_time %> diff --git a/chef/templates/default/server.rb.erb b/chef/templates/default/server.rb.erb new file mode 100644 index 0000000..cc0ddf4 --- /dev/null +++ b/chef/templates/default/server.rb.erb @@ -0,0 +1,34 @@ +# +# Chef Server Config File +# +# Dynamically generated by Chef - local modifications will be replaced + +log_level :info +log_location <%= @server_log %> +ssl_verify_mode :verify_none +registration_url "http://<%= @node[:chef][:server_fqdn] %>:4000" +openid_url "http://<%= @node[:chef][:server_fqdn] %>:4001" +template_url "http://<%= @node[:chef][:server_fqdn] %>:4000" +remotefile_url "http://<%= @node[:chef][:server_fqdn] %>:4000" +search_url "http://<%= @node[:chef][:server_fqdn] %>:4000" +role_url "http://<%= @node[:chef][:server_fqdn] %>:4000" + +validation_token "<%= @node[:chef][:server_token] %>" + +cookbook_path [ "<%= @node[:chef][:serve_path] %>/site-cookbooks", "<%= @node[:chef][:serve_path] %>/cookbooks" ] + +file_cache_path "<%= @node[:chef][:cache_path] %>" +node_path "<%= @node[:chef][:serve_path] %>/nodes" +openid_store_path "<%= @node[:chef][:path] %>/openid/store" +openid_cstore_path "<%= @node[:chef][:path] %>/openid/cstore" +search_index_path "<%= @node[:chef][:path] %>/search_index" +role_path "<%= @node[:chef][:serve_path] %>/roles" + +umask <%= @node[:chef][:umask] %> + +# See http://wiki.opscode.com/display/chef/Securing+Chef+Server +# For more information on these settings. +#authorized_openid_providers [ "https://<%= @node[:chef][:server_fqdn]%>", "https://chef", "myopenid.com" ] +#authorized_openid_identifiers [ "" ] + +Chef::Log::Formatter.show_time = <%= @show_time %> diff --git a/collectd/attributes/collectd.rb b/collectd/attributes/collectd.rb new file mode 100755 index 0000000..d8b88d6 --- /dev/null +++ b/collectd/attributes/collectd.rb @@ -0,0 +1,22 @@ +collectd Mash.new unless attribute?("collectd") +collectd[:base_dir] = "/var/lib/collectd" unless collectd.has_key?(:base_dir) +collectd[:plugin_dir] = "/usr/lib/collectd" unless collectd.has_key?(:plugin_dir) +collectd[:types_db] = ["/usr/lib/collectd/types.db", "/etc/collectd/my_types.db"] unless collectd.has_key?(:types_db) +collectd[:interval] = 10 unless collectd.has_key?(:interval) +collectd[:read_threads] = 5 unless collectd.has_key?(:read_threads) +collectd[:server_address] = %w(192.168.1.153 192.168.1.159) +collectd[:server] = false unless collectd.has_key?(:server) + +# if !collectd.has_key?(:plugins) + collectd[:plugins] = + [ + { "name" => "syslog", "options" => [{ "LogLevel" => "Info" }]}, + { "name" => "cpu" }, + { "name" => "df", "options" => [{ "Device" => "/dev/vda1" }, { "Device" => "/dev/sda1" }]}, + { "name" => "disk", "options" => [{ "Disk" => "vda1" }, { "Disk" => "sda1" }]}, + { "name" => "interface", "options" => [{ "Interface" => "eth0" }, { "Interface" => "eth1"}]}, + { "name" => "memory" }, + { "name" => "rrdtool", "options" => [{ "DataDir" => "/var/lib/collectd/rrd" }, { "CacheFlush" => 120 }, { "WritesPerSecond" => 75 }]}, + { "name" => "swap" } + ]; +# end diff --git a/collectd/libraries/default.rb b/collectd/libraries/default.rb new file mode 100755 index 0000000..67608ad --- /dev/null +++ b/collectd/libraries/default.rb @@ -0,0 +1,6 @@ + +def format_option(option) + return option if option.instance_of?(Fixnum) || option == true || option == false + "\"#{option}\"" +end + diff --git a/collectd/metadata.json b/collectd/metadata.json new file mode 100755 index 0000000..a4802ff --- /dev/null +++ b/collectd/metadata.json @@ -0,0 +1,38 @@ +{ + "replacing": { + + }, + "long_description": "", + "attributes": { + + }, + "maintainer": "37signals", + "recommendations": { + + }, + "license": "Apache v2.0", + "recipes": { + "collectd": "" + }, + "maintainer_email": "sysadmins@37signals.com", + "suggestions": { + + }, + "dependencies": { + + }, + "conflicting": { + + }, + "platforms": { + + }, + "description": "Configures collectd", + "version": "0.1.0", + "name": "collectd", + "providing": { + "collectd": [ + + ] + } +} \ No newline at end of file diff --git a/collectd/metadata.rb b/collectd/metadata.rb new file mode 100755 index 0000000..c10d288 --- /dev/null +++ b/collectd/metadata.rb @@ -0,0 +1,4 @@ +maintainer "37signals" +maintainer_email "sysadmins@37signals.com" +description "Configures collectd" +version "0.1" diff --git a/collectd/recipes/default.rb b/collectd/recipes/default.rb new file mode 100755 index 0000000..bf2af0c --- /dev/null +++ b/collectd/recipes/default.rb @@ -0,0 +1,16 @@ +package "collectd" + +service "collectd" do + supports :restart => true, :status => true +end + +%w(collectd collection thresholds).each do |file| + template "/etc/collectd/#{file}.conf" do + source "#{file}.conf.erb" + owner "root" + group "root" + mode "644" + notifies :restart, resources(:service => "collectd") + end +end + diff --git a/collectd/templates/default/collectd.conf.erb b/collectd/templates/default/collectd.conf.erb new file mode 100755 index 0000000..b786842 --- /dev/null +++ b/collectd/templates/default/collectd.conf.erb @@ -0,0 +1,40 @@ +# Config file for collectd(1). +# +# Some plugins need additional configuration and are disabled by default. +# Please read collectd.conf(5) for details. +# +# You should also read /usr/share/doc/collectd/README.Debian.plugins before +# enabling any more plugins. + +Hostname "<%= @node[:fqdn] %>" +FQDNLookup true +BaseDir "<%= @node[:collectd][:base_dir] %>" +PluginDir "<%= @node[:collectd][:plugin_dir] %>" +TypesDB "<%= @node[:collectd][:types_db].join('", "') %>" +Interval <%= @node[:collectd][:interval] %> +ReadThreads <%= @node[:collectd][:read_threads] %> + +<% @node[:collectd][:plugins].each do |plugin| %> +LoadPlugin "<%= plugin[:name] %>" +<% end %> + +<% @node[:collectd][:plugins].each do |plugin| %> +<% if plugin[:options] %> +> + <% plugin[:options].each do |opt| %> + <%= opt.keys.first %> <%= format_option(opt[opt.keys.first]) %> + <% end %> + + +<% end %> +<% end %> + +LoadPlugin "network" + + <% @node[:collectd][:server_address].each do |address| -%> + Server "<%= address %>" + <% end -%> + <% if @node[:collectd][:listen_address] %>Listen "<%= @node[:collectd][:listen_address] %>"<% end -%> + + +Include "/etc/collectd/thresholds.conf" diff --git a/collectd/templates/default/collection.conf.erb b/collectd/templates/default/collection.conf.erb new file mode 100755 index 0000000..958c7a6 --- /dev/null +++ b/collectd/templates/default/collection.conf.erb @@ -0,0 +1,3 @@ +datadir: "/var/lib/collectd/rrd/" +libdir: "/usr/lib/collectd/" + diff --git a/collectd/templates/default/thresholds.conf.erb b/collectd/templates/default/thresholds.conf.erb new file mode 100755 index 0000000..bff223a --- /dev/null +++ b/collectd/templates/default/thresholds.conf.erb @@ -0,0 +1,38 @@ +# Threshold configuration for collectd(1). +# +# See the section "THRESHOLD CONFIGURATION" in collectd.conf(5) for details. + +# +# +# WarningMin 0.00 +# WarningMax 1000.00 +# FailureMin 0 +# FailureMax 1200.00 +# Invert false +# Persist false +# Instance "some_instance" +# +# +# +# Instance "eth0" +# +# DataSource "rx" +# FailureMax 10000000 +# +# +# +# +# +# Instance "idle" +# FailureMin 10 +# +# +# +# +# Instance "cached" +# WarningMin 100000000 +# +# +# +# + diff --git a/couchdb/metadata.json b/couchdb/metadata.json new file mode 100644 index 0000000..35ee567 --- /dev/null +++ b/couchdb/metadata.json @@ -0,0 +1,58 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs CouchDB package and starts service", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "couchdb": "" + }, + "suggestions": { + + }, + "platforms": { + "rhel": [ + + ], + "freebsd": [ + + ], + "ubuntu": [ + ">= 8.10" + ], + "openbsd": [ + + ], + "fedora": [ + + ], + "centos": [ + + ], + "debian": [ + ">= 5.0" + ] + }, + "version": "0.8.0", + "name": "couchdb", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "couchdb": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "Installs the CouchDB package if it is available from an package repository on\nthe node. If the package repository is not available, CouchDB needs to be \ninstalled via some other method, either a backported package, or compiled \ndirectly from source. CouchDB is available on Red Hat-based systems through\nthe EPEL Yum Repository.\n", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/couchdb/metadata.rb b/couchdb/metadata.rb new file mode 100644 index 0000000..18e2046 --- /dev/null +++ b/couchdb/metadata.rb @@ -0,0 +1,21 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs CouchDB package and starts service" +long_description <<-EOH +Installs the CouchDB package if it is available from an package repository on +the node. If the package repository is not available, CouchDB needs to be +installed via some other method, either a backported package, or compiled +directly from source. CouchDB is available on Red Hat-based systems through +the EPEL Yum Repository. +EOH +version "0.8" + +supports "ubuntu", ">= 8.10" # for package in APT +supports "debian", ">= 5.0" # for package in APT +supports "openbsd" +supports "freebsd" + +%w{ rhel centos fedora }.each do |os| + supports os # requires EPEL Yum Repository +end diff --git a/couchdb/recipes/default.rb b/couchdb/recipes/default.rb new file mode 100644 index 0000000..5e6590a --- /dev/null +++ b/couchdb/recipes/default.rb @@ -0,0 +1,47 @@ +# +# Author:: Joshua Timberman +# Cookbook Name:: couchdb +# Recipe:: default +# +# Copyright 2008-2009, Opscode, 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 "couchdb" do + package_name value_for_platform( + "openbsd" => { "default" => "apache-couchdb" }, + "gentoo" => { "default" => "dev-db/couchdb" }, + "default" => "couchdb" + ) +end + +directory "/var/lib/couchdb" do + owner "couchdb" + group "couchdb" + recursive true + path value_for_platform( + "openbsd" => { "default" => "/var/couchdb" }, + "freebsd" => { "default" => "/var/couchdb" }, + "gentoo" => { "default" => "/var/couchdb" }, + "default" => "/var/lib/couchdb" + ) +end + +service "couchdb" do + if platform?("centos","redhat","fedora") + start_command "/sbin/service couchdb start &> /dev/null" + stop_command "/sbin/service couchdb stop &> /dev/null" + end + supports [ :restart, :status ] + action [ :enable, :start ] +end diff --git a/couchdb/templates/default/port_couchdb.erb b/couchdb/templates/default/port_couchdb.erb new file mode 100644 index 0000000..a11f8aa --- /dev/null +++ b/couchdb/templates/default/port_couchdb.erb @@ -0,0 +1,2 @@ +# CouchDB +-A FWR -p tcp -m tcp --dport 5984 -j ACCEPT \ No newline at end of file diff --git a/cron/attributes/cron.rb b/cron/attributes/cron.rb new file mode 100755 index 0000000..5a18f92 --- /dev/null +++ b/cron/attributes/cron.rb @@ -0,0 +1 @@ +cron Mash.new unless attribute?(:cron) \ No newline at end of file diff --git a/cron/metadata.json b/cron/metadata.json new file mode 100755 index 0000000..cc9bc03 --- /dev/null +++ b/cron/metadata.json @@ -0,0 +1,38 @@ +{ + "replacing": { + + }, + "long_description": "", + "attributes": { + + }, + "maintainer": "37signals", + "recommendations": { + + }, + "license": "Apache v2.0", + "recipes": { + "cron": "" + }, + "maintainer_email": "sysadmins@37signals.com", + "suggestions": { + + }, + "dependencies": { + + }, + "conflicting": { + + }, + "platforms": { + + }, + "description": "Configures cron", + "version": "0.1.0", + "name": "cron", + "providing": { + "cron": [ + + ] + } +} \ No newline at end of file diff --git a/cron/metadata.rb b/cron/metadata.rb new file mode 100755 index 0000000..093858f --- /dev/null +++ b/cron/metadata.rb @@ -0,0 +1,4 @@ +maintainer "37signals" +maintainer_email "sysadmins@37signals.com" +description "Configures cron" +version "0.1" diff --git a/cron/recipes/default.rb b/cron/recipes/default.rb new file mode 100755 index 0000000..fe07073 --- /dev/null +++ b/cron/recipes/default.rb @@ -0,0 +1,9 @@ +if node[:cron][:jobs] + node[:cron][:jobs].each do |name, config| + cron name do + config.each do |k,v| + send(k.to_sym, v) + end + end + end +end \ No newline at end of file diff --git a/ddclient/metadata.json b/ddclient/metadata.json new file mode 100755 index 0000000..e7f6851 --- /dev/null +++ b/ddclient/metadata.json @@ -0,0 +1,38 @@ +{ + "replacing": { + + }, + "long_description": "", + "attributes": { + + }, + "maintainer": "37signals", + "recommendations": { + + }, + "license": "Apache v2.0", + "recipes": { + "ddclient": "" + }, + "maintainer_email": "sysadmins@37signals.com", + "suggestions": { + + }, + "dependencies": { + + }, + "conflicting": { + + }, + "platforms": { + + }, + "description": "Configures ddclient", + "version": "0.1.0", + "name": "ddclient", + "providing": { + "ddclient": [ + + ] + } +} \ No newline at end of file diff --git a/ddclient/metadata.rb b/ddclient/metadata.rb new file mode 100755 index 0000000..b75b963 --- /dev/null +++ b/ddclient/metadata.rb @@ -0,0 +1,4 @@ +maintainer "37signals" +maintainer_email "sysadmins@37signals.com" +description "Configures ddclient" +version "0.1" diff --git a/ddclient/recipes/default.rb b/ddclient/recipes/default.rb new file mode 100755 index 0000000..86f56dd --- /dev/null +++ b/ddclient/recipes/default.rb @@ -0,0 +1,24 @@ +package "ddclient" + +service "ddclient" do + supports :restart => true + action :enable +end + +template "/etc/default/ddclient" do + source "ddclient.default.erb" + mode 0644 + owner "root" + notifies :restart, resources(:service => "ddclient") +end + +template "/etc/ddclient.conf" do + source "ddclient.conf.erb" + mode 0600 + owner "root" + notifies :restart, resources(:service => "ddclient") +end + +service "ddclient" do + action :start +end \ No newline at end of file diff --git a/ddclient/templates/default/ddclient.conf.erb b/ddclient/templates/default/ddclient.conf.erb new file mode 100755 index 0000000..7118aef --- /dev/null +++ b/ddclient/templates/default/ddclient.conf.erb @@ -0,0 +1,7 @@ +pid=/var/run/ddclient.pid +protocol=dyndns2 +server=update.dynect.net +use=web +login=<%= @node[:ddclient][:dyndns_login] %> +password=<%= @node[:ddclient][:dyndns_password] %> +<%= "#{@node[:public_fqdn]|| @node[:fqdn]}" %> \ No newline at end of file diff --git a/ddclient/templates/default/ddclient.default.erb b/ddclient/templates/default/ddclient.default.erb new file mode 100755 index 0000000..fa96986 --- /dev/null +++ b/ddclient/templates/default/ddclient.default.erb @@ -0,0 +1,2 @@ +run_daemon="true" +daemon_interval="60" diff --git a/django/README.rdoc b/django/README.rdoc new file mode 100644 index 0000000..9c3a9ca --- /dev/null +++ b/django/README.rdoc @@ -0,0 +1,42 @@ += DESCRIPTION: + +Installs Python Django package and sets up Apache2 to serve a django application. + += REQUIREMENTS: + +Opscode cookbooks, http://github.com/opscode/cookbooks/tree/master: + +* python +* apache2 + += ATTRIBUTES: + +None. + += USAGE: + +Create the django application using the Apache2 cookbook's web_app define. Normally this would be done in a site-cookbook. + + web_app "mysite" do + docroot "/srv/mysite" + template "mysite.conf.erb" + end + +Create the template, 'mysite.conf.erb' within the site-cookbook. Make sure the django settings are correct. The web_app define copies the template over and enables it as an apache2 site. + += LICENSE & AUTHOR: + +Author:: Joshua Timberman () +Copyright:: 2009, Opscode, 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/django/metadata.json b/django/metadata.json new file mode 100644 index 0000000..f3acdc3 --- /dev/null +++ b/django/metadata.json @@ -0,0 +1,48 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs DJango", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "django": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "debian": [ + + ] + }, + "version": "0.7.0", + "name": "django", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "django": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "= DESCRIPTION:\n\nInstalls Python Django package and sets up Apache2 to serve a django application.\n\n= REQUIREMENTS:\n\nOpscode cookbooks, http:\/\/github.com\/opscode\/cookbooks\/tree\/master:\n\n* python\n* apache2\n\n= ATTRIBUTES:\n\nNone.\n\n= USAGE:\n\nCreate the django application using the Apache2 cookbook's web_app define. Normally this would be done in a site-cookbook.\n\n web_app \"mysite\" do\n docroot \"\/srv\/mysite\"\n template \"mysite.conf.erb\"\n end\n\nCreate the template, 'mysite.conf.erb' within the site-cookbook. Make sure the django settings are correct. The web_app define copies the template over and enables it as an apache2 site.\n\n= LICENSE & AUTHOR:\n\nAuthor:: Joshua Timberman ()\nCopyright:: 2009, Opscode, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http:\/\/www.apache.org\/licenses\/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n", + "replacing": { + + }, + "dependencies": { + "python": [ + + ], + "apache2": [ + + ] + } +} \ No newline at end of file diff --git a/django/metadata.rb b/django/metadata.rb new file mode 100644 index 0000000..9cbbb6f --- /dev/null +++ b/django/metadata.rb @@ -0,0 +1,14 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs DJango" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.7" + +%w{ ubuntu debian }.each do |os| + supports os +end + +%w{ apache2 python}.each do |cb| + depends cb +end diff --git a/django/recipes/default.rb b/django/recipes/default.rb new file mode 100644 index 0000000..6a204f3 --- /dev/null +++ b/django/recipes/default.rb @@ -0,0 +1,29 @@ +# +# Cookbook Name:: django +# Recipe:: default +# +# Copyright 2009, Opscode, 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 "apache2" +include_recipe "apache2::mod_python" +include_recipe "python" + +package "apache2-mpm-prefork" do + action :install +end + +package "python-django" do + action :install +end diff --git a/djbdns/attributes/djbdns.rb b/djbdns/attributes/djbdns.rb new file mode 100644 index 0000000..68f2fb7 --- /dev/null +++ b/djbdns/attributes/djbdns.rb @@ -0,0 +1,45 @@ +# +# Cookbook Name:: djbdns +# Recipe:: default +# Author:: Joshua Timberman () +# Author:: Joshua Sierles () +# +# Copyright 2009, Opscode, 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. +# + +set_unless[:djbdns][:tinydns_ipaddress] = "127.0.0.1" +set_unless[:djbdns][:tinydns_internal_ipaddress] = "127.0.0.1" +set_unless[:djbdns][:public_dnscache_ipaddress] = ipaddress +set_unless[:djbdns][:axfrdns_ipaddress] = "127.0.0.1" + +set_unless[:djbdns][:public_dnscache_allowed_networks] = [ipaddress.split(".")[0,2].join(".")] +set_unless[:djbdns][:tinydns_internal_resolved_domain] = domain + +case platform +when "ubuntu" + if platform_version >= "8.10" + set[:djbdns][:bin_dir] = "/usr/bin" + else + set[:djbdns][:bin_dir] = "/usr/local/bin" + end +when "debian" + if platform_version >= "5.0" + set[:djbdns][:bin_dir] = "/usr/bin" + else + set[:djbdns][:bin_dir] = "/usr/local/bin" + end +else + set[:djbdns][:bin_dir] = "/usr/local/bin" +end diff --git a/djbdns/metadata.json b/djbdns/metadata.json new file mode 100644 index 0000000..2bc50cc --- /dev/null +++ b/djbdns/metadata.json @@ -0,0 +1,149 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs djbdns and configures DNS services", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "djbdns::internal_server": "Sets up internal TinyDNS", + "djbdns": "Installs djbdns from package or source and creates users", + "djbdns": "", + "djbdns::server": "Sets up external TinyDNS", + "djbdns::axfr": "Sets up djbdns AXFR service", + "djbdns::cache": "Sets up public dnscache service" + }, + "suggestions": { + + }, + "platforms": { + "rhel": [ + + ], + "ubuntu": [ + + ], + "centos": [ + + ], + "debian": [ + + ] + }, + "version": "0.7.0", + "name": "djbdns", + "conflicting": { + + }, + "attributes": { + "djbdns\/axfrdns_ipaddress": { + "default": "127.0.0.1", + "type": "string", + "multiple_values": false, + "description": "Specify the IP address for AXFR service", + "display_name": "DJB DNS AXFR IP Address", + "recipes": [ + + ], + "required": false + }, + "djbdns\/public_dnscache_allowed_networks": { + "default": [ + "ipaddress.split('.')[0,2].join('.')" + ], + "type": "array", + "multiple_values": false, + "description": "Networks allowed to query the public dnscache", + "display_name": "DJB DNS Public DNS Cache Allowed Networks", + "recipes": [ + + ], + "required": false + }, + "djbdns\/tinydns_internal_ipaddress": { + "default": "127.0.0.1", + "type": "string", + "multiple_values": false, + "description": "Specify the IP address for internal TinyDNS", + "display_name": "DJB DNS TinyDNS Internal IP Address", + "recipes": [ + + ], + "required": false + }, + "djbdns\/tinydns_internal_resolved_domain": { + "default": "domain", + "type": "string", + "multiple_values": false, + "description": "Internal domain TinyDNS is resolver", + "display_name": "DJB DNS TinyDNS Internal Resolved Domain", + "recipes": [ + + ], + "required": false + }, + "djbdns\/public_dnscache_ipaddress": { + "default": "ipaddress", + "type": "string", + "multiple_values": false, + "description": "Specify the IP address for the public dnscache", + "display_name": "DJB DNS Public DNS Cache IP Address", + "recipes": [ + + ], + "required": false + }, + "djbdns\/bin_dir": { + "default": "\/usr\/local\/bin", + "type": "string", + "multiple_values": false, + "description": "Location of the djbdns binaries", + "display_name": "DJB DNS Binaries Directory", + "recipes": [ + + ], + "required": false + }, + "djbdns\/tinydns_ipaddress": { + "default": "127.0.0.1", + "type": "string", + "multiple_values": false, + "description": "Specify the IP address for TinyDNS", + "display_name": "DJB DNS TinyDNS IP Address", + "recipes": [ + + ], + "required": false + } + }, + "providing": { + "djbdns::internal_server": [ + + ], + "djbdns": [ + + ], + "djbdns::server": [ + + ], + "djbdns::axfr": [ + + ], + "djbdns::cache": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + "runit": [ + + ], + "build-essential": [ + + ] + } +} \ No newline at end of file diff --git a/djbdns/metadata.rb b/djbdns/metadata.rb new file mode 100644 index 0000000..06a3f25 --- /dev/null +++ b/djbdns/metadata.rb @@ -0,0 +1,55 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs djbdns and configures DNS services" +version "0.7" +recipe "djbdns", "Installs djbdns from package or source and creates users" +recipe "djbdns::axfr", "Sets up djbdns AXFR service" +recipe "djbdns::cache", "Sets up public dnscache service" +recipe "djbdns::internal_server", "Sets up internal TinyDNS" +recipe "djbdns::server", "Sets up external TinyDNS" + +%w{ build-essential runit }.each do |cb| + depends cb +end + +%w{ ubuntu debian centos rhel }.each do |os| + supports os +end + +attribute "djbdns/tinydns_ipaddress", + :display_name => "DJB DNS TinyDNS IP Address", + :description => "Specify the IP address for TinyDNS", + :default => "127.0.0.1" + +attribute "djbdns/tinydns_internal_ipaddress", + :display_name => "DJB DNS TinyDNS Internal IP Address", + :description => "Specify the IP address for internal TinyDNS", + :default => "127.0.0.1" + +attribute "djbdns/axfrdns_ipaddress", + :display_name => "DJB DNS AXFR IP Address", + :description => "Specify the IP address for AXFR service", + :default => "127.0.0.1" + +attribute "djbdns/public_dnscache_ipaddress", + :display_name => "DJB DNS Public DNS Cache IP Address", + :description => "Specify the IP address for the public dnscache", + :default => "ipaddress" + +attribute "djbdns/public_dnscache_allowed_networks", + :display_name => "DJB DNS Public DNS Cache Allowed Networks", + :description => "Networks allowed to query the public dnscache", + :type => "array", + :default => ["ipaddress.split('.')[0,2].join('.')"] + +attribute "djbdns/tinydns_internal_resolved_domain", + :display_name => "DJB DNS TinyDNS Internal Resolved Domain", + :description => "Internal domain TinyDNS is resolver", + :default => "domain" + +attribute "djbdns/bin_dir", + :display_name => "DJB DNS Binaries Directory", + :description => "Location of the djbdns binaries", + :default => "/usr/local/bin" + diff --git a/djbdns/recipes/axfr.rb b/djbdns/recipes/axfr.rb new file mode 100644 index 0000000..eca2a4d --- /dev/null +++ b/djbdns/recipes/axfr.rb @@ -0,0 +1,40 @@ +# +# Author:: Joshua Timberman () +# Cookbook Name:: djbdns +# Recipe:: axfr +# +# Copyright 2009, Opscode, 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 "djbdns" + +user "axfrdns" do + uid 9996 + case node[:platform] + when "ubuntu","debian" + gid "nogroup" + when "redhat", "centos" + gid "nobody" + else + gid "nobody" + end + shell "/bin/false" + home "/home/axfrdns" +end + +execute "#{node[:djbdns][:bin_dir]}/axfrdns-conf axfrdns dnslog #{node[:runit][:sv_dir]}/axfrdns #{node[:runit][:sv_dir]}/tinydns #{node[:djbdns][:axfrdns_ipaddress]}" do + only_if "/usr/bin/test ! -d #{node[:runit][:sv_dir]}/axfrdns" +end + +runit_service "axfrdns" diff --git a/djbdns/recipes/cache.rb b/djbdns/recipes/cache.rb new file mode 100644 index 0000000..1034e4a --- /dev/null +++ b/djbdns/recipes/cache.rb @@ -0,0 +1,43 @@ +# +# Author:: Joshua Timberman () +# Author:: Joshua Sierles () +# Cookbook Name:: djbdns +# Recipe:: cache +# +# Copyright 2009, Opscode, 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 "djbdns" + +execute "public_cache_update" do + cwd "#{node[:runit][:sv_dir]}/public-dnscache" + command "#{node[:djbdns][:bin_dir]}/dnsip `#{node[:djbdns][:bin_dir]}/dnsqr ns . | awk '/answer:/ { print \$5 ; }' | sort` > root/servers/@" + action :nothing +end + +execute "#{node[:djbdns][:bin_dir]}/dnscache-conf dnscache dnslog #{node[:runit][:sv_dir]}/public-dnscache #{node[:djbdns][:public_dnscache_ipaddress]}" do + only_if "/usr/bin/test ! -d #{node[:runit][:sv_dir]}/public-dnscache" + notifies :run, resources("execute[public_cache_update]") +end + +runit_service "public-dnscache" + +file "#{node[:runit][:sv_dir]}/public-dnscache/root/ip/#{node[:djbdns][:public_dnscache_allowed_networks]}" do + mode 0644 +end + +template "#{node[:runit][:sv_dir]}/public-dnscache/root/servers/#{node[:djbdns][:tinydns_internal_resolved_domain]}" do + source "dnscache-servers.erb" + mode 0644 +end diff --git a/djbdns/recipes/default.rb b/djbdns/recipes/default.rb new file mode 100644 index 0000000..f5238d5 --- /dev/null +++ b/djbdns/recipes/default.rb @@ -0,0 +1,101 @@ +# +# Cookbook Name:: djbdns +# Recipe:: default +# Author:: Joshua Timberman () +# +# Copyright 2009, Opscode, 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 "build-essential" +include_recipe "runit" + +installation_method = value_for_platform( + "debian" => { "4.0" => "source", "default" => "package" }, + "ubuntu" => { + "6.06" => "source", + "6.10" => "source", + "7.04" => "source", + "7.10" => "source", + "8.04" => "source", + "default" => "package" + }, + "default" => { "default" => "source" } +) + +case installation_method +when "package" + package "djbdns" do + action :install + end +when "source" + bash "install_djbdns" do + user "root" + cwd "/tmp" + code <<-EOH + (cd /tmp; wget http://cr.yp.to/ucspi-tcp/ucspi-tcp-0.88.tar.gz) + (cd /tmp; tar zxvf ucspi-tcp-0.88.tar.gz) + (cd /tmp/ucspi-tcp-0.88; perl -pi -e 's/extern int errno;/\#include /' error.h) + (cd /tmp/ucspi-tcp-0.88; make setup check) + (cd /tmp; wget http://cr.yp.to/djbdns/djbdns-1.05.tar.gz) + (cd /tmp; tar xzvf djbdns-1.05.tar.gz) + (cd /tmp/djbdns-1.05; perl -pi -e 's/extern int errno;/\#include /' error.h) + (cd /tmp/djbdns-1.05; make setup check) + EOH + only_if "/usr/bin/test ! -f #{node[:djbdns][:bin_dir]}/tinydns" + end +else + Chef::Log.info("Could not find an installation method for platform #{node[:platform]}, version #{node[:platform_version]}") +end + +user "dnscache" do + uid 9997 + case node[:platform] + when "ubuntu","debian" + gid "nogroup" + when "redhat", "centos" + gid "nobody" + else + gid "nobody" + end + shell "/bin/false" + home "/home/dnscache" +end + +user "dnslog" do + uid 9998 + case node[:platform] + when "ubuntu","debian" + gid "nogroup" + when "redhat", "centos" + gid "nobody" + else + gid "nobody" + end + shell "/bin/false" + home "/home/dnslog" +end + +user "tinydns" do + uid 9999 + case node[:platform] + when "ubuntu","debian" + gid "nogroup" + when "redhat", "centos" + gid "nobody" + else + gid "nobody" + end + shell "/bin/false" + home "/home/tinydns" +end diff --git a/djbdns/recipes/internal_server.rb b/djbdns/recipes/internal_server.rb new file mode 100644 index 0000000..ce4999a --- /dev/null +++ b/djbdns/recipes/internal_server.rb @@ -0,0 +1,38 @@ +# +# Author:: Joshua Timberman () +# Cookbook Name:: djbdns +# Recipe:: internal_server +# +# Copyright 2009, Opscode, 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 "djbdns" + +execute "#{node[:djbdns][:bin_dir]}/tinydns-conf tinydns dnslog #{node[:runit][:sv_dir]}/tinydns-internal #{node[:djbdns][:tinydns_ipaddress]}" do + only_if "/usr/bin/test ! -d #{node[:runit][:sv_dir]}/tinydns-internal" +end + +execute "build-tinydns-internal-data" do + cwd "#{node[:runit][:sv_dir]}/tinydns-internal/root" + command "make" + action :nothing +end + +template "#{node[:runit][:sv_dir]}/tinydns-internal/root/data" do + source "tinydns-internal-data.erb" + mode 0644 + notifies :run, resources("execute[build-tinydns-internal-data]") +end + +runit_service "tinydns-internal" diff --git a/djbdns/recipes/server.rb b/djbdns/recipes/server.rb new file mode 100644 index 0000000..a9a879d --- /dev/null +++ b/djbdns/recipes/server.rb @@ -0,0 +1,38 @@ +# +# Author:: Joshua Timberman () +# Cookbook Name:: djbdns +# Recipe:: server +# +# Copyright 2009, Opscode, 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 "djbdns" + +execute "#{node[:djbdns][:bin_dir]}/tinydns-conf tinydns dnslog #{node[:runit][:sv_dir]}/tinydns #{node[:djbdns][:tinydns_ipaddress]}" do + only_if "/usr/bin/test ! -d #{node[:runit][:sv_dir]}/tinydns" +end + +execute "build-tinydns-data" do + cwd "#{node[:runit][:sv_dir]}/tinydns/root" + command "make" + action :nothing +end + +template "#{node[:runit][:sv_dir]}/tinydns/root/data" do + source "tinydns-data.erb" + mode 0644 + notifies :run, resources("execute[build-tinydns-data]") +end + +runit_service "tinydns" diff --git a/djbdns/templates/default/dnscache-servers.erb b/djbdns/templates/default/dnscache-servers.erb new file mode 100644 index 0000000..e56ea71 --- /dev/null +++ b/djbdns/templates/default/dnscache-servers.erb @@ -0,0 +1 @@ +127.0.0.1 \ No newline at end of file diff --git a/djbdns/templates/default/sv-axfrdns-log-run.erb b/djbdns/templates/default/sv-axfrdns-log-run.erb new file mode 100644 index 0000000..2936bca --- /dev/null +++ b/djbdns/templates/default/sv-axfrdns-log-run.erb @@ -0,0 +1,2 @@ +#!/bin/sh +exec chpst -U dnslog svlogd -tt ./main diff --git a/djbdns/templates/default/sv-axfrdns-run.erb b/djbdns/templates/default/sv-axfrdns-run.erb new file mode 100644 index 0000000..338cafd --- /dev/null +++ b/djbdns/templates/default/sv-axfrdns-run.erb @@ -0,0 +1,4 @@ +#!/bin/sh +exec 2>&1 +exec chpst -e ./env sh -c ' + exec chpst -U axfrdns -d300000 tcpserver -vDRHl0 -x tcp.cdb -- "$IP" 53 <%= @node[:djbdns][:bin_dir] %>/axfrdns' diff --git a/djbdns/templates/default/sv-public-dnscache-log-run.erb b/djbdns/templates/default/sv-public-dnscache-log-run.erb new file mode 100644 index 0000000..2936bca --- /dev/null +++ b/djbdns/templates/default/sv-public-dnscache-log-run.erb @@ -0,0 +1,2 @@ +#!/bin/sh +exec chpst -U dnslog svlogd -tt ./main diff --git a/djbdns/templates/default/sv-public-dnscache-run.erb b/djbdns/templates/default/sv-public-dnscache-run.erb new file mode 100644 index 0000000..32b6248 --- /dev/null +++ b/djbdns/templates/default/sv-public-dnscache-run.erb @@ -0,0 +1,6 @@ +#!/bin/sh +exec 2>&1 +exec /dnscache +' diff --git a/djbdns/templates/default/sv-tinydns-internal-log-run.erb b/djbdns/templates/default/sv-tinydns-internal-log-run.erb new file mode 100644 index 0000000..2936bca --- /dev/null +++ b/djbdns/templates/default/sv-tinydns-internal-log-run.erb @@ -0,0 +1,2 @@ +#!/bin/sh +exec chpst -U dnslog svlogd -tt ./main diff --git a/djbdns/templates/default/sv-tinydns-internal-run.erb b/djbdns/templates/default/sv-tinydns-internal-run.erb new file mode 100644 index 0000000..9a4b80c --- /dev/null +++ b/djbdns/templates/default/sv-tinydns-internal-run.erb @@ -0,0 +1,3 @@ +#!/bin/sh +exec 2>&1 +exec chpst -U tinydns -e ./env -d300000 <%= @node[:djbdns][:bin_dir] %>/tinydns diff --git a/djbdns/templates/default/sv-tinydns-log-run.erb b/djbdns/templates/default/sv-tinydns-log-run.erb new file mode 100644 index 0000000..2936bca --- /dev/null +++ b/djbdns/templates/default/sv-tinydns-log-run.erb @@ -0,0 +1,2 @@ +#!/bin/sh +exec chpst -U dnslog svlogd -tt ./main diff --git a/djbdns/templates/default/sv-tinydns-run.erb b/djbdns/templates/default/sv-tinydns-run.erb new file mode 100644 index 0000000..9a4b80c --- /dev/null +++ b/djbdns/templates/default/sv-tinydns-run.erb @@ -0,0 +1,3 @@ +#!/bin/sh +exec 2>&1 +exec chpst -U tinydns -e ./env -d300000 <%= @node[:djbdns][:bin_dir] %>/tinydns diff --git a/djbdns/templates/default/tinydns-data.erb b/djbdns/templates/default/tinydns-data.erb new file mode 100644 index 0000000..2a7a5df --- /dev/null +++ b/djbdns/templates/default/tinydns-data.erb @@ -0,0 +1,4 @@ +# Auto-generated by chef for <%= @node[:fqdn] %> +# + +.<%= @node[:domain] %>:<%= @node[:djbdns][:tinydns_ipaddress] %>:a:259200 \ No newline at end of file diff --git a/djbdns/templates/default/tinydns-internal-data.erb b/djbdns/templates/default/tinydns-internal-data.erb new file mode 100644 index 0000000..314e5d9 --- /dev/null +++ b/djbdns/templates/default/tinydns-internal-data.erb @@ -0,0 +1,5 @@ +# Auto-generated by chef for <%= @node[:fqdn] %> +# +# This is the internal zone file. + +.<%= @node[:domain] %>:<%= @node[:djbdns][:tinydns_internal_ipaddress] %>:a:259200 \ No newline at end of file diff --git a/dns/metadata.json b/dns/metadata.json new file mode 100755 index 0000000..ef7f435 --- /dev/null +++ b/dns/metadata.json @@ -0,0 +1,42 @@ +{ + "replacing": { + + }, + "long_description": "", + "attributes": { + + }, + "maintainer": "37signals", + "recommendations": { + + }, + "license": "Apache v2.0", + "recipes": { + "dns::client": "", + "dns": "" + }, + "maintainer_email": "sysadmins@37signals.com", + "suggestions": { + + }, + "dependencies": { + + }, + "conflicting": { + + }, + "platforms": { + + }, + "description": "Configures dns", + "version": "0.1.0", + "name": "dns", + "providing": { + "dns::client": [ + + ], + "dns": [ + + ] + } +} \ No newline at end of file diff --git a/dns/metadata.rb b/dns/metadata.rb new file mode 100755 index 0000000..b44c1ee --- /dev/null +++ b/dns/metadata.rb @@ -0,0 +1,4 @@ +maintainer "37signals" +maintainer_email "sysadmins@37signals.com" +description "Configures dns" +version "0.1" diff --git a/dns/recipes/client.rb b/dns/recipes/client.rb new file mode 100755 index 0000000..28fbd48 --- /dev/null +++ b/dns/recipes/client.rb @@ -0,0 +1,7 @@ +if node[:nameservers] + template "/etc/resolv.conf" do + source "resolv.conf.erb" + variables ({:domain => node[:domain], :nameservers => node[:nameservers], :search => node[:domain]}) + not_if { node[:nameservers].include?(node[:ipaddress]) || node.role?("development") } + end +end \ No newline at end of file diff --git a/dns/recipes/default.rb b/dns/recipes/default.rb new file mode 100755 index 0000000..e69de29 diff --git a/dns/templates/default/resolv.conf.erb b/dns/templates/default/resolv.conf.erb new file mode 100755 index 0000000..fb337d0 --- /dev/null +++ b/dns/templates/default/resolv.conf.erb @@ -0,0 +1,4 @@ +domain <%= @domain %> +<% @nameservers.each do |ns| %> +nameserver <%= ns %> +<% end %> \ No newline at end of file diff --git a/drbd/metadata.json b/drbd/metadata.json new file mode 100644 index 0000000..50ee80c --- /dev/null +++ b/drbd/metadata.json @@ -0,0 +1,45 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs but does not configure drbd", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "drbd": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "debian": [ + + ] + }, + "version": "0.7.0", + "name": "drbd", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "drbd": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + "lvm": [ + + ] + } +} \ No newline at end of file diff --git a/drbd/metadata.rb b/drbd/metadata.rb new file mode 100644 index 0000000..07f15d3 --- /dev/null +++ b/drbd/metadata.rb @@ -0,0 +1,10 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs but does not configure drbd" +version "0.7" +depends "lvm" + +%w{ ubuntu debian}.each do |os| + supports os +end diff --git a/drbd/recipes/default.rb b/drbd/recipes/default.rb new file mode 100644 index 0000000..c6aabeb --- /dev/null +++ b/drbd/recipes/default.rb @@ -0,0 +1,35 @@ +# +# Cookbook Name:: drbd +# Recipe:: default +# +# Copyright 2009, Opscode, 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. +# +# = Requirements +# Templates:: +# * /etc/drbd.conf + +include_recipe "lvm" + +package "drbd8-utils" do + action :install +end + +service "drbd" do + supports( + :restart => true, + :status => true + ) + action :enable +end diff --git a/dynomite/README.rdoc b/dynomite/README.rdoc new file mode 100644 index 0000000..4e1b6aa --- /dev/null +++ b/dynomite/README.rdoc @@ -0,0 +1,52 @@ += DESCRIPTION: + +Installs and configures dynomite. + += REQUIREMENTS: + +== Platform: + +Ubuntu, mainly because of dependencies on Ubuntu specific installation methods in dependencies (thrift and boost). + +== Cookbooks: + +Opscode/cookbooks: + +* thrift +** boost +* ruby +* git +* erlang +* runit + += ATTRIBUTES: + +* dynomite[:master] - whether this node is a master cluster node. +* dynomite[:cluster_name] - name of the dynomite cluster. +* dynomite[:data_dir] - location of the data. +* dynomite[:num_nodes] - number of nodes in the cluster. +* dynomite[:node_name] - name of this node. +* dynomite[:ascii_port] - port for ASCII protocol. +* dynomite[:thrift_port] - port for Thrift protocol. +* dynomite[:web_port] - port for web (HTTP). + += USAGE: + +Nothing fancy. Include the recipe, or add to a run_list like any other recipe. This cookbook relies on the ruby-dynomite client, which manages dynomite processes. The cookbook will set up dynomite as a runit service. + += LICENSE and AUTHOR: + +Author:: Joshua Timberman () +Copyright:: 2009, Opscode, 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/dynomite/attributes/dynomite.rb b/dynomite/attributes/dynomite.rb new file mode 100644 index 0000000..a72682b --- /dev/null +++ b/dynomite/attributes/dynomite.rb @@ -0,0 +1,31 @@ +# +# Cookbook Name:: dynomite +# attributes:: dynomite +# +# Copyright 2009, Opscode, 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. +# + +set_unless[:dynomite][:master] = false +set_unless[:dynomite][:cluster_name] = "dynomite" +set_unless[:dynomite][:data_dir] = "/var/db/dynomite" +set_unless[:dynomite][:num_nodes] = 1 +set_unless[:dynomite][:node_name] = hostname +set_unless[:dynomite][:ascii_port] = 11221 +set_unless[:dynomite][:thrift_port] = 11222 +set_unless[:dynomite][:web_port] = 1180 + +master_node = search(:node, "dynomite_master:true", "fqdn").first + +set_unless[:dynomite][:join_node] = master_node diff --git a/dynomite/metadata.json b/dynomite/metadata.json new file mode 100644 index 0000000..3a8fd34 --- /dev/null +++ b/dynomite/metadata.json @@ -0,0 +1,51 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs\/Configures dynomite", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "dynomite": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ] + }, + "version": "0.1.0", + "name": "dynomite", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "dynomite": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "= DESCRIPTION:\n\nInstalls and configures dynomite.\n\n= REQUIREMENTS:\n\n== Platform:\n\nUbuntu, mainly because of dependencies on Ubuntu specific installation methods in dependencies (thrift and boost).\n\n== Cookbooks:\n\nOpscode\/cookbooks:\n\n* thrift\n** boost\n* ruby\n* git\n* erlang\n* runit\n\n= ATTRIBUTES: \n\n* dynomite[:master] - whether this node is a master cluster node.\n* dynomite[:cluster_name] - name of the dynomite cluster.\n* dynomite[:data_dir] - location of the data.\n* dynomite[:num_nodes] - number of nodes in the cluster.\n* dynomite[:node_name] - name of this node.\n* dynomite[:ascii_port] - port for ASCII protocol.\n* dynomite[:thrift_port] - port for Thrift protocol.\n* dynomite[:web_port] - port for web (HTTP).\n\n= USAGE:\n\nNothing fancy. Include the recipe, or add to a run_list like any other recipe. This cookbook relies on the ruby-dynomite client, which manages dynomite processes. The cookbook will set up dynomite as a runit service.\n\n= LICENSE and AUTHOR:\n\nAuthor:: Joshua Timberman ()\nCopyright:: 2009, Opscode, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http:\/\/www.apache.org\/licenses\/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n", + "replacing": { + + }, + "dependencies": { + "runit": [ + + ], + "git": [ + + ], + "ruby": [ + + ], + "erlang": [ + + ] + } +} \ No newline at end of file diff --git a/dynomite/metadata.rb b/dynomite/metadata.rb new file mode 100644 index 0000000..8f230a9 --- /dev/null +++ b/dynomite/metadata.rb @@ -0,0 +1,12 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs/Configures dynomite" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.1" + +supports "ubuntu" + +%w{ ruby git erlang runit }.each do |cb| + depends cb +end diff --git a/dynomite/recipes/default.rb b/dynomite/recipes/default.rb new file mode 100644 index 0000000..8546dbd --- /dev/null +++ b/dynomite/recipes/default.rb @@ -0,0 +1,58 @@ +# +# Cookbook Name:: dynomite +# Recipe:: default +# +# Copyright 2009, Opscode, 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 "ruby" +include_recipe "git" +include_recipe "erlang" + +gem_package "rake" +gem_package "open4" + +bash "install_dynomite" do + user "root" + cwd "/tmp" + code <<-EOH + git clone git://github.com/cliffmoon/dynomite.git + cd dynomite + git submodule init + git submodule update + rake clean + rake build_tarball + (cd /usr/local && tar zxf /tmp/dynomite/build/dynomite.tar.tgz) + EOH + not_if { FileTest.exists?("/usr/local/dynomite/bin/dynomite") } +end + +gem_package "dynomite" do + source "http://gems.opscode.com" +end + +directory node[:dynomite][:data_dir] do + recursive true + owner "root" + group "root" + mode "0644" +end + +directory "/var/log/dynomite" do + owner "root" + group "root" + mode "0644" +end + +runit_service "dynomite" diff --git a/dynomite/templates/default/sv-dynomite-log-run.erb b/dynomite/templates/default/sv-dynomite-log-run.erb new file mode 100644 index 0000000..a79a518 --- /dev/null +++ b/dynomite/templates/default/sv-dynomite-log-run.erb @@ -0,0 +1,2 @@ +#!/bin/sh +exec svlogd -tt ./main diff --git a/dynomite/templates/default/sv-dynomite-run.erb b/dynomite/templates/default/sv-dynomite-run.erb new file mode 100644 index 0000000..459e181 --- /dev/null +++ b/dynomite/templates/default/sv-dynomite-run.erb @@ -0,0 +1,9 @@ +#!/bin/sh +exec 2>&1 +exec /usr/bin/env HOME="/tmp" dynoctl \ + -n <%= @node[:dynomite][:num_nodes] %> \ + -d <%= @node[:dynomite][:data_dir] %> \ + -o <%= @node[:dynomite][:node_name] %> \ + -a <%= @node[:dynomite][:ascii_port] %> \ + -t <%= @node[:dynomite][:thrift_port] %> \ + -h <%= @node[:dynomite][:web_port] %> diff --git a/ec2/attributes/ec2_recipe_options.rb b/ec2/attributes/ec2_recipe_options.rb new file mode 100644 index 0000000..77b23ce --- /dev/null +++ b/ec2/attributes/ec2_recipe_options.rb @@ -0,0 +1,28 @@ +# +# Cookbook Name:: ec2 +# Attribute File:: ec2_recipe_options.rb +# +# Copyright 2008-2009, Opscode, 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. +# + +set_unless[:ec2opts][:lvm][:use_ephemeral] = true +set_unless[:ec2opts][:lvm][:ephemeral_mountpoint] = "/mnt" +set_unless[:ec2opts][:lvm][:ephemeral_volume_group] = "ephemeral" +set_unless[:ec2opts][:lvm][:ephemeral_logical_volume] = "store" +set_unless[:ec2opts][:lvm][:ephemeral_devices] = { + "m1.small" => [ "/dev/sda2" ], + "m1.large" => [ "/dev/sdb", "/dev/sdc" ], + "m1.xlarge" => [ "/dev/sdb", "/dev/sdc", "/dev/sdd", "/dev/sde" ], +} diff --git a/ec2/metadata.rb b/ec2/metadata.rb new file mode 100644 index 0000000..d65e4b5 --- /dev/null +++ b/ec2/metadata.rb @@ -0,0 +1,13 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Manage EC2 metadata as attributes" +version "0.9" + +%w{ ubuntu debian}.each do |os| + supports os +end + +attribute "ec2_metadata", + :display_name => "EC2 Metadata", + :description => "Retrieve EC2 instance metadata" diff --git a/ec2/recipes/default.rb b/ec2/recipes/default.rb new file mode 100644 index 0000000..1ef7cc6 --- /dev/null +++ b/ec2/recipes/default.rb @@ -0,0 +1,19 @@ +# +# Cookbook Name:: ec2 +# Recipe:: default +# +# Copyright 2008-2009, Opscode, 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/ejabberd/metadata.json b/ejabberd/metadata.json new file mode 100755 index 0000000..1882dc3 --- /dev/null +++ b/ejabberd/metadata.json @@ -0,0 +1,38 @@ +{ + "replacing": { + + }, + "long_description": "", + "attributes": { + + }, + "maintainer": "37signals", + "recommendations": { + + }, + "license": "Apache v2.0", + "recipes": { + "ejabberd": "" + }, + "maintainer_email": "sysadmins@37signals.com", + "suggestions": { + + }, + "dependencies": { + + }, + "conflicting": { + + }, + "platforms": { + + }, + "description": "Configures ejabberd", + "version": "0.1.0", + "name": "ejabberd", + "providing": { + "ejabberd": [ + + ] + } +} \ No newline at end of file diff --git a/ejabberd/metadata.rb b/ejabberd/metadata.rb new file mode 100755 index 0000000..f9c0619 --- /dev/null +++ b/ejabberd/metadata.rb @@ -0,0 +1,4 @@ +maintainer "37signals" +maintainer_email "sysadmins@37signals.com" +description "Configures ejabberd" +version "0.1" diff --git a/ejabberd/recipes/default.rb b/ejabberd/recipes/default.rb new file mode 100755 index 0000000..93385fc --- /dev/null +++ b/ejabberd/recipes/default.rb @@ -0,0 +1,20 @@ +package "ejabberd" + +service "ejabberd" do + action :enable + supports :restart => true +end + +template "/etc/ejabberd/ejabberd.cfg" do + source "ejabberd.cfg.erb" + variables(:jabber_domain => node[:jabber_domain]) + notifies :restart, resources(:service => "ejabberd") +end + +# execute "add ejabberd admin user" do +# command "ejabberdctl register admin #{node[:base][:jabber_domain]} #{node[:base][:jabber_admin_password]}" +# end + +service "ejabberd" do + action :start +end diff --git a/ejabberd/templates/default/ejabberd.cfg.erb b/ejabberd/templates/default/ejabberd.cfg.erb new file mode 100755 index 0000000..db84b1c --- /dev/null +++ b/ejabberd/templates/default/ejabberd.cfg.erb @@ -0,0 +1,197 @@ +%%% +%%% Auto-generated by Chef for <%= @node[:fqdn] %> +%%% + +%%override_global. +%%override_local. +%%override_acls. + + +%% Admin user +{acl, admin, {user, "admin", "<%= @jabber_domain %>"}}. + +%% supported domains +{hosts, ["<%= @jabber_domain %>"]}. + + +%% loglevel: Verbosity of log files generated by ejabberd. +%% 0: No ejabberd log at all (not recommended) +%% 1: Critical +%% 2: Error +%% 3: Warning +%% 4: Info +%% 5: Debug +%% +{loglevel, 4}. + +%% +%% watchdog_admins: If an ejabberd process consumes too much memory, +%% send live notifications to those Jabber accounts. +%% +{watchdog_admins, ["admin@<%= @jabber_domain %>"]}. + + +%% listen: Which ports will ejabberd listen, which service handles it +%% and what options to start it with. +%% +{listen, + [ + {5222, ejabberd_c2s, [ + {access, c2s}, + {shaper, c2s_shaper}, + {max_stanza_size, 65536}, + starttls, {certfile, "/etc/ejabberd/ejabberd.pem"} + ]}, + + {5269, ejabberd_s2s_in, [ + {shaper, s2s_shaper}, + {max_stanza_size, 131072} + ]}, + + {5280, ejabberd_http, [ + http_poll, + web_admin + ]} + ]}. + +%% +%% s2s_use_starttls: Enable STARTTLS + Dialback for S2S connections. +%% Allowed values are: true or false. +%% You must specify a certificate file. +%% +{s2s_use_starttls, true}. + +%% +%% s2s_certfile: Specify a certificate file. +%% +{s2s_certfile, "/etc/ejabberd/ejabberd.pem"}. + +%% +%% domain_certfile: Specify a different certificate for each served hostname. +%% +%%{domain_certfile, "example.org", "/path/to/example_org.pem"}. +%%{domain_certfile, "example.com", "/path/to/example_com.pem"}. + + +{auth_method, internal}. + + +%% +%% The "normal" shaper limits traffic speed to 1.000 B/s +%% +{shaper, normal, {maxrate, 1000}}. + +%% +%% The "fast" shaper limits traffic speed to 50.000 B/s +%% +{shaper, fast, {maxrate, 50000}}. + + +%% The 'admin' ACL grants administrative privileges to Jabber accounts. +%% You can put as many accounts as you want. +%% +%%{acl, admin, {user, "aleksey", "localhost"}}. +%%{acl, admin, {user, "ermine", "example.org"}}. + +%% +%% Blocked users +%% +%%{acl, blocked, {user, "baduser", "example.org"}}. +%%{acl, blocked, {user, "test"}}. + +%% +%% Local users: don't modify this line. +%% +{acl, local, {user_regexp, ""}}. + + +%% Define the maximum number of time a single user is allowed to connect: +{access, max_user_sessions, [{10, all}]}. + +%% This rule allows access only for local users: +{access, local, [{allow, local}]}. + +%% Only non-blocked users can use c2s connections: +{access, c2s, [{deny, blocked}, + {allow, all}]}. + +%% For all users except admins used "normal" shaper +{access, c2s_shaper, [{none, admin}, + {normal, all}]}. + +%% For all S2S connections used "fast" shaper +{access, s2s_shaper, [{fast, all}]}. + +%% Only admins can send announcement messages: +{access, announce, [{allow, admin}]}. + +%% Only admins can use configuration interface: +{access, configure, [{allow, admin}]}. + +%% Admins of this server are also admins of MUC service: +{access, muc_admin, [{allow, admin}]}. + +%% All users are allowed to use MUC service: +{access, muc, [{allow, all}]}. + +%% No username can be registered via in-band registration: +%% To enable in-band registration, replace 'deny' with 'allow' +% (note that if you remove mod_register from modules list then users will not +% be able to change their password as well as register). +% This setting is default because it's more safe. +{access, register, [{deny, all}]}. + +%% Everybody can create pubsub nodes +{access, pubsub_createnode, [{allow, all}]}. + + +%% language: Default language used for server messages. +%% +{language, "en"}. + +%% Modules enabled in all ejabberd virtual hosts. +%% +{modules, + [ + {mod_adhoc, []}, + {mod_announce, [{access, announce}]}, % requires mod_adhoc + {mod_caps, []}, + {mod_configure,[]}, % requires mod_adhoc + {mod_ctlextra, []}, + {mod_disco, []}, + %%{mod_echo, [{host, "echo.localhost"}]}, + {mod_irc, []}, + {mod_last, []}, + {mod_muc, [ + %%{host, "conference.@HOST@"}, + {access, muc}, + {access_create, muc}, + {access_persistent, muc}, + {access_admin, muc_admin}, + {max_users, 500} + ]}, + %%{mod_muc_log,[]}, + {mod_offline, []}, + {mod_privacy, []}, + {mod_private, []}, + {mod_proxy65, [ + {access, local}, + {shaper, c2s_shaper} + ]}, + {mod_pubsub, [ % requires mod_caps + {access_createnode, pubsub_createnode}, + {plugins, ["default", "pep"]} + ]}, + {mod_roster, []}, + %%{mod_service_log,[]}, + %%{mod_shared_roster,[]}, + {mod_stats, []}, + {mod_time, []}, + {mod_vcard, []}, + {mod_version, []} + ]}. + +%%% Local Variables: +%%% mode: erlang +%%% End: +%%% vim: set filetype=erlang tabstop=8: diff --git a/emacs/metadata.json b/emacs/metadata.json new file mode 100644 index 0000000..ada5bbf --- /dev/null +++ b/emacs/metadata.json @@ -0,0 +1,49 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs emacs", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "emacs": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "centos": [ + + ], + "redhat": [ + + ], + "debian": [ + + ] + }, + "version": "0.7.0", + "name": "emacs", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "emacs": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/emacs/metadata.rb b/emacs/metadata.rb new file mode 100644 index 0000000..8d4718f --- /dev/null +++ b/emacs/metadata.rb @@ -0,0 +1,9 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs emacs" +version "0.7" + +%w{ ubuntu debian redhat centos }.each do |os| + supports os +end diff --git a/emacs/recipes/default.rb b/emacs/recipes/default.rb new file mode 100644 index 0000000..a7c96de --- /dev/null +++ b/emacs/recipes/default.rb @@ -0,0 +1,21 @@ +# +# Cookbook Name:: emacs +# Recipe:: default +# +# Copyright 2009, Opscode, 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 "emacs" do + action :upgrade +end diff --git a/erlang/attributes/erlang.rb b/erlang/attributes/erlang.rb new file mode 100644 index 0000000..cf9c694 --- /dev/null +++ b/erlang/attributes/erlang.rb @@ -0,0 +1 @@ +set_unless[:erlang][:gui_tools] = false diff --git a/erlang/metadata.json b/erlang/metadata.json new file mode 100644 index 0000000..90df1b5 --- /dev/null +++ b/erlang/metadata.json @@ -0,0 +1,43 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs erlang", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "erlang": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "debian": [ + + ] + }, + "version": "0.7.0", + "name": "erlang", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "erlang": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/erlang/metadata.rb b/erlang/metadata.rb new file mode 100644 index 0000000..1f912ef --- /dev/null +++ b/erlang/metadata.rb @@ -0,0 +1,9 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs erlang" +version "0.7" + +%w{ ubuntu debian }.each do |os| + supports os +end diff --git a/erlang/recipes/default.rb b/erlang/recipes/default.rb new file mode 100644 index 0000000..d3626ab --- /dev/null +++ b/erlang/recipes/default.rb @@ -0,0 +1,29 @@ +# Cookbook Name:: erlang +# Recipe:: default +# Author:: Joe Williams +# +# Copyright 2008-2009, Joe Williams +# +# 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. +# + +case node[:platform] +when "debian", "ubuntu" + erlpkg = node[:erlang][:gui_tools] ? "erlang" : "erlang-nox" + package erlpkg + package "erlang-dev" + package "erlang-manpages" +else + package "erlang" +end + diff --git a/fail2ban/metadata.json b/fail2ban/metadata.json new file mode 100644 index 0000000..a944db8 --- /dev/null +++ b/fail2ban/metadata.json @@ -0,0 +1,43 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs and configures fail2ban", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "fail2ban": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "debian": [ + + ] + }, + "version": "0.7.0", + "name": "fail2ban", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "fail2ban": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/fail2ban/metadata.rb b/fail2ban/metadata.rb new file mode 100644 index 0000000..ae74758 --- /dev/null +++ b/fail2ban/metadata.rb @@ -0,0 +1,9 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs and configures fail2ban" +version "0.7" + +%w{ ubuntu debian }.each do |os| + supports os +end diff --git a/fail2ban/recipes/default.rb b/fail2ban/recipes/default.rb new file mode 100644 index 0000000..5f07d42 --- /dev/null +++ b/fail2ban/recipes/default.rb @@ -0,0 +1,35 @@ +# +# Cookbook Name:: fail2ban +# Recipe:: default +# +# Copyright 2009, Opscode, 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 "fail2ban" do + action :upgrade +end + +service "fail2ban" do + action :enable +end + +%w{ fail2ban jail }.each do |cfg| + template "/etc/fail2ban/#{cfg}.conf" do + source "#{cfg}.conf.erb" + owner "root" + group "root" + mode 0644 + notifies :restart, resources(:service => "fail2ban") + end +end diff --git a/fail2ban/templates/default/fail2ban.conf.erb b/fail2ban/templates/default/fail2ban.conf.erb new file mode 100644 index 0000000..598cc01 --- /dev/null +++ b/fail2ban/templates/default/fail2ban.conf.erb @@ -0,0 +1,34 @@ +# Fail2Ban configuration file +# +# Author: Cyril Jaquier +# +# $Revision: 494 $ +# + +[Definition] + +# Option: loglevel +# Notes.: Set the log level output. +# 1 = ERROR +# 2 = WARN +# 3 = INFO +# 4 = DEBUG +# Values: NUM Default: 3 +# +loglevel = 3 + +# Option: logtarget +# Notes.: Set the log target. This could be a file, SYSLOG, STDERR or STDOUT. +# Only one log target can be specified. +# Values: STDOUT STDERR SYSLOG file Default: /var/log/fail2ban.log +# +logtarget = /var/log/fail2ban.log + +# Option: socket +# Notes.: Set the socket file. This is used to communicate with the daemon. Do +# not remove this file when Fail2ban runs. It will not be possible to +# communicate with the server afterwards. +# Values: FILE Default: /tmp/fail2ban.sock +# +socket = /tmp/fail2ban.sock + diff --git a/fail2ban/templates/default/jail.conf.erb b/fail2ban/templates/default/jail.conf.erb new file mode 100644 index 0000000..658ec78 --- /dev/null +++ b/fail2ban/templates/default/jail.conf.erb @@ -0,0 +1,202 @@ +# Fail2Ban configuration file. +# +# This file was composed for Debian systems from the original one +# provided now under /usr/share/doc/fail2ban/examples/jail.conf +# for additional examples. +# +# To avoid merges during upgrades DO NOT MODIFY THIS FILE +# and rather provide your changes in /etc/fail2ban/jail.local +# +# Author: Yaroslav O. Halchenko +# +# $Revision: 281 $ +# + +# The DEFAULT allows a global definition of the options. They can be override +# in each jail afterwards. + +[DEFAULT] + +# "ignoreip" can be an IP address, a CIDR mask or a DNS host +ignoreip = 127.0.0.1 192.168.100.0 +bantime = 300 +maxretry = 5 + +# "backend" specifies the backend used to get files modification. Available +# options are "gamin", "polling" and "auto". +# yoh: For some reason Debian shipped python-gamin didn't work as expected +# This issue left ToDo, so polling is default backend for now +backend = polling + +# +# Destination email address used solely for the interpolations in +# jail.{conf,local} configuration files. +destemail = root@localhost + +# +# ACTIONS +# + +# Default banning action (e.g. iptables, iptables-new, +# iptables-multiport, shorewall, etc) It is used to define +# action_* variables. Can be overriden globally or per +# section within jail.local file +banaction = iptables-multiport + + +# +# Action shortcuts. To be used to define action parameter + +# The simplest action to take: ban only +action_ = %(banaction)s[name=%(__name__)s, port="%(port)s"] + +# ban & send an e-mail with whois report to the destemail. +action_mw = %(banaction)s[name=%(__name__)s, port="%(port)s"] + mail-whois[name=%(__name__)s, dest="%(destemail)s"] + +# ban & send an e-mail with whois report and relevant log lines +# to the destemail. +action_mwl = %(banaction)s[name=%(__name__)s, port="%(port)s"] + mail-whois-lines[name=%(__name__)s, dest="%(destemail)s", logpath=%(logpath)s] + +# Choose default action. To change, just override value of 'action' with the +# interpolation to the chosen action shortcut (e.g. action_mw, action_mwl, etc) in jail.local +# globally (section [DEFAULT]) or per specific section +action = %(action_)s + +# +# JAILS +# + +# Next jails corresponds to the standard configuration in Fail2ban 0.6 which +# was shipped in Debian. Please enable any defined here jail by including +# +# [SECTION_NAME] +# enabled = true +# +# in /etc/fail2ban/jail.local. +# +# Optionally you may override any other parameter (e.g. banaction, +# action, port, logpath, etc) in that section within jail.local + +[ssh] + +enabled = true +port = ssh,sftp +filter = sshd +logpath = /var/log/auth.log +maxretry = 6 + + +[ssh-ddos] + +enabled = false +port = ssh,sftp +filter = sshd-ddos +logpath = /var/log/auth.log +maxretry = 6 + +# +# HTTP servers +# + +[apache] + +enabled = false +port = http,https +filter = apache-auth +logpath = /var/log/apache*/*access.log +maxretry = 6 + +# default action is now multiport, so apache-multiport jail was left +# for compatibility with previous (<0.7.6-2) releases +[apache-multiport] + +enabled = false +port = http,https +filter = apache-auth +logpath = /var/log/apache*/*access.log +maxretry = 6 + +[apache-noscript] + +enabled = false +port = http,https +filter = apache-noscript +logpath = /var/log/apache*/*error.log +maxretry = 6 + +# +# FTP servers +# + +[vsftpd] + +enabled = false +port = ftp,ftp-data,ftps,ftps-data +filter = vsftpd +logpath = /var/log/vsftpd.log +# or overwrite it in jails.local to be +# logpath = /var/log/auth.log +# if you want to rely on PAM failed login attempts +# vsftpd's failregex should match both of those formats +maxretry = 6 + + +[proftpd] + +enabled = false +port = ftp,ftp-data,ftps,ftps-data +filter = proftpd +logpath = /var/log/proftpd/proftpd.log +maxretry = 6 + + +[wuftpd] + +enabled = false +port = ftp,ftp-data,ftps,ftps-data +filter = wuftpd +logpath = /var/log/auth.log +maxretry = 6 + + +# +# Mail servers +# + +[postfix] + +enabled = false +port = smtp,ssmtp +filter = postfix +logpath = /var/log/maillog + + +[couriersmtp] + +enabled = false +port = smtp,ssmtp +filter = couriersmtp +logpath = /var/log/maillog + + +# +# Mail servers authenticators: might be used for smtp,ftp,imap servers, so +# all relevant ports get banned +# + +[courierauth] + +enabled = false +port = smtp,ssmtp,imap2,imap3,imaps,pop3,pop3s +filter = courierlogin +logpath = /var/log/maillog + + +[sasl] + +enabled = false +port = smtp,ssmtp,imap2,imap3,imaps,pop3,pop3s +filter = sasl +logpath = /var/log/maillog diff --git a/ganglia/attributes/ganglia.rb b/ganglia/attributes/ganglia.rb new file mode 100755 index 0000000..149b038 --- /dev/null +++ b/ganglia/attributes/ganglia.rb @@ -0,0 +1,5 @@ +default[:ganglia][:grid_name] = 'Ganglia' +default[:ganglia][:server_fqdn] = 'ganglia' +default[:ganglia][:cluster_name] = 'Default' +default[:ganglia][:servers] = [ '1.2.3.4:3737', '5.6.7.8:3737' ] +default[:ganglia][:clusters] = [ { :name => 'Default', :port => 1234, :interval => 15 } ] diff --git a/ganglia/metadata.rb b/ganglia/metadata.rb new file mode 100755 index 0000000..eee8d73 --- /dev/null +++ b/ganglia/metadata.rb @@ -0,0 +1,5 @@ +maintainer "ganglia" +maintainer_email "sysadmins@37signals.com" +description "Configures Ganglia" +version "0.1" +depends "apache2" diff --git a/ganglia/recipes/client.rb b/ganglia/recipes/client.rb new file mode 100755 index 0000000..c006eeb --- /dev/null +++ b/ganglia/recipes/client.rb @@ -0,0 +1,22 @@ + +package "ganglia-monitor" + +service "ganglia-monitor" do + enabled true + running true + pattern "gmond" +end + +template "/etc/ganglia/gmond.conf" do + source "gmond.conf.erb" + backup false + owner "ganglia" + group "ganglia" + mode 0644 + variables(:server => false, + :cluster => { + :name => @node[:ganglia][:cluster_name], + :port => @node[:ganglia][:clusters].find { |c| c[:name] == @node[:ganglia][:cluster_name] }[:port] + }) + notifies :restart, resources(:service => "ganglia-monitor") +end diff --git a/ganglia/recipes/default.rb b/ganglia/recipes/default.rb new file mode 100755 index 0000000..8c8ee49 --- /dev/null +++ b/ganglia/recipes/default.rb @@ -0,0 +1,8 @@ +# +# Cookbook Name:: ganglia +# Recipe:: default +# +# Copyright 2009, 37signals +# +# All rights reserved - Do Not Redistribute +# diff --git a/ganglia/recipes/server.rb b/ganglia/recipes/server.rb new file mode 100755 index 0000000..fe9298f --- /dev/null +++ b/ganglia/recipes/server.rb @@ -0,0 +1,38 @@ + +include_recipe "apache2" + +package "ganglia-webfrontend" +package "gmetad" + +template "/etc/ganglia/vhost.conf" do + source "ganglia-vhost.conf.erb" + backup false + owner "root" + group "www-data" + mode 0640 +end + +apache_site "ganglia" do + config_path "/etc/ganglia/vhost.conf" +end + +service "gmetad" do + enabled true +end + +cluster_nodes = {} +search(:node, '*', %w(fqdn ganglia_cluster_name)) do |node| + next unless node['ganglia_cluster_name'] + cluster_nodes[node['ganglia_cluster_name']] ||= [] + cluster_nodes[node['ganglia_cluster_name']] << node['fqdn'].split('.').first +end + +template "/etc/ganglia/gmetad.conf" do + source "gmetad.conf.erb" + backup false + owner "ganglia" + group "ganglia" + mode 0644 + variables(:cluster_nodes => cluster_nodes) + notifies :restart, resources(:service => "gmetad") +end diff --git a/ganglia/templates/default/ganglia-vhost.conf.erb b/ganglia/templates/default/ganglia-vhost.conf.erb new file mode 100755 index 0000000..7e2ecf9 --- /dev/null +++ b/ganglia/templates/default/ganglia-vhost.conf.erb @@ -0,0 +1,6 @@ + + ServerName <%= @node[:ganglia][:server_fqdn] %> + ServerAlias <%= @node[:ganglia][:server_fqdn].split('.').first %> + DocumentRoot /usr/share/ganglia-webfrontend + ErrorLog /var/log/apache2/ganglia_error.log + diff --git a/ganglia/templates/default/gmetad.conf.erb b/ganglia/templates/default/gmetad.conf.erb new file mode 100755 index 0000000..77d922d --- /dev/null +++ b/ganglia/templates/default/gmetad.conf.erb @@ -0,0 +1,117 @@ +# This is an example of a Ganglia Meta Daemon configuration file +# http://ganglia.sourceforge.net/ +# +# $Id: gmetad.conf.in 1639 2008-08-09 23:30:32Z carenas $ +# +#------------------------------------------------------------------------------- +# Setting the debug_level to 1 will keep daemon in the forground and +# show only error messages. Setting this value higher than 1 will make +# gmetad output debugging information and stay in the foreground. +# default: 0 +# debug_level 10 +# +#------------------------------------------------------------------------------- +# What to monitor. The most important section of this file. +# +# The data_source tag specifies either a cluster or a grid to +# monitor. If we detect the source is a cluster, we will maintain a complete +# set of RRD databases for it, which can be used to create historical +# graphs of the metrics. If the source is a grid (it comes from another gmetad), +# we will only maintain summary RRDs for it. +# +# Format: +# data_source "my cluster" [polling interval] address1:port addreses2:port ... +# +# The keyword 'data_source' must immediately be followed by a unique +# string which identifies the source, then an optional polling interval in +# seconds. The source will be polled at this interval on average. +# If the polling interval is omitted, 15sec is asssumed. +# +# A list of machines which service the data source follows, in the +# format ip:port, or name:port. If a port is not specified then 8649 +# (the default gmond port) is assumed. +# default: There is no default value +# +# data_source "my cluster" 10 localhost my.machine.edu:8649 1.2.3.5:8655 +# data_source "my grid" 50 1.3.4.7:8655 grid.org:8651 grid-backup.org:8651 +# data_source "another source" 1.3.4.7:8655 1.3.4.8 + +<% @node[:ganglia][:clusters].each do |cluster| %> +<% next unless @cluster_nodes[cluster[:name]] %> +data_source "<%= cluster[:name] %>" <%= cluster[:interval] %> <%= @cluster_nodes[cluster[:name]].join(' ') %> +<% end %> + +# +# Round-Robin Archives +# You can specify custom Round-Robin archives here (defaults are listed below) +# +# RRAs "RRA:AVERAGE:0.5:1:244" "RRA:AVERAGE:0.5:24:244" "RRA:AVERAGE:0.5:168:244" "RRA:AVERAGE:0.5:672:244" \ +# "RRA:AVERAGE:0.5:5760:374" +# + +# +#------------------------------------------------------------------------------- +# Scalability mode. If on, we summarize over downstream grids, and respect +# authority tags. If off, we take on 2.5.0-era behavior: we do not wrap our output +# in tags, we ignore all tags we see, and always assume +# we are the "authority" on data source feeds. This approach does not scale to +# large groups of clusters, but is provided for backwards compatibility. +# default: on +# scalable off +# +#------------------------------------------------------------------------------- +# The name of this Grid. All the data sources above will be wrapped in a GRID +# tag with this name. +# default: unspecified +gridname "<%= @node[:ganglia][:grid_name] %>" + +#------------------------------------------------------------------------------- +# The authority URL for this grid. Used by other gmetads to locate graphs +# for our data sources. Generally points to a ganglia/ +# website on this machine. +# default: "http://hostname/ganglia/", +# where hostname is the name of this machine, as defined by gethostname(). +# authority "http://mycluster.org/newprefix/" +# +#------------------------------------------------------------------------------- +# List of machines this gmetad will share XML with. Localhost +# is always trusted. +# default: There is no default value +# trusted_hosts 127.0.0.1 169.229.50.165 my.gmetad.org +# +#------------------------------------------------------------------------------- +# If you want any host which connects to the gmetad XML to receive +# data, then set this value to "on" +# default: off +# all_trusted on +# +#------------------------------------------------------------------------------- +# If you don't want gmetad to setuid then set this to off +# default: on +# setuid off +# +#------------------------------------------------------------------------------- +# User gmetad will setuid to (defaults to "nobody") +# default: "nobody" +setuid_username "ganglia" +# +#------------------------------------------------------------------------------- +# The port gmetad will answer requests for XML +# default: 8651 +# xml_port 8651 +# +#------------------------------------------------------------------------------- +# The port gmetad will answer queries for XML. This facility allows +# simple subtree and summation views of the XML tree. +# default: 8652 +# interactive_port 8652 +# +#------------------------------------------------------------------------------- +# The number of threads answering XML requests +# default: 4 +# server_threads 10 +# +#------------------------------------------------------------------------------- +# Where gmetad stores its round-robin databases +# default: "/var/lib/ganglia/rrds" +# rrd_rootdir "/var/lib/ganglia/rrds" diff --git a/ganglia/templates/default/gmond.conf.erb b/ganglia/templates/default/gmond.conf.erb new file mode 100755 index 0000000..ce0be51 --- /dev/null +++ b/ganglia/templates/default/gmond.conf.erb @@ -0,0 +1,336 @@ +/* This configuration is as close to 2.5.x default behavior as possible + The values closely match ./gmond/metric.h definitions in 2.5.x */ +globals { + daemonize = yes + setuid = yes + user = ganglia + debug_level = 0 + max_udp_msg_len = 1472 + mute = no + deaf = no + host_dmax = 0 /*secs */ + cleanup_threshold = 300 /*secs */ + gexec = no + send_metadata_interval = 0 +} + +/* If a cluster attribute is specified, then all gmond hosts are wrapped inside + * of a tag. If you do not specify a cluster tag, then all will + * NOT be wrapped inside of a tag. */ +cluster { + name = "<%= @node[:ganglia][:cluster_name] %>" + owner = "unspecified" + latlong = "unspecified" + url = "unspecified" +} + +/* The host section describes attributes of the host, like the location */ +host { + location = "unspecified" +} + +/* Feel free to specify as many udp_send_channels as you like. Gmond + used to only support having a single channel */ +udp_send_channel { + mcast_join = 239.2.11.71 + port = <%= @cluster[:port] %> +} + +/* You can specify as many udp_recv_channels as you like as well. */ +udp_recv_channel { + mcast_join = 239.2.11.71 + port = <%= @cluster[:port] %> + bind = 239.2.11.71 +} + +/* You can specify as many tcp_accept_channels as you like to share + an xml description of the state of the cluster */ +tcp_accept_channel { + port = 8649 +} + +/* Each metrics module that is referenced by gmond must be specified and + loaded. If the module has been statically linked with gmond, it does not + require a load path. However all dynamically loadable modules must include + a load path. */ +modules { + module { + name = "core_metrics" + } + module { + name = "cpu_module" + path = "/usr/lib/ganglia/modcpu.so" + } + module { + name = "disk_module" + path = "/usr/lib/ganglia/moddisk.so" + } + module { + name = "load_module" + path = "/usr/lib/ganglia/modload.so" + } + module { + name = "mem_module" + path = "/usr/lib/ganglia/modmem.so" + } + module { + name = "net_module" + path = "/usr/lib/ganglia/modnet.so" + } + module { + name = "proc_module" + path = "/usr/lib/ganglia/modproc.so" + } + module { + name = "sys_module" + path = "/usr/lib/ganglia/modsys.so" + } +} + +include ('/etc/ganglia/conf.d/*.conf') + + +/* The old internal 2.5.x metric array has been replaced by the following + collection_group directives. What follows is the default behavior for + collecting and sending metrics that is as close to 2.5.x behavior as + possible. */ + +/* This collection group will cause a heartbeat (or beacon) to be sent every + 20 seconds. In the heartbeat is the GMOND_STARTED data which expresses + the age of the running gmond. */ +collection_group { + collect_once = yes + time_threshold = 20 + metric { + name = "heartbeat" + } +} + +/* This collection group will send general info about this host every 1200 secs. + This information doesn't change between reboots and is only collected once. */ +collection_group { + collect_once = yes + time_threshold = 1200 + metric { + name = "cpu_num" + title = "CPU Count" + } + metric { + name = "cpu_speed" + title = "CPU Speed" + } + metric { + name = "mem_total" + title = "Memory Total" + } + /* Should this be here? Swap can be added/removed between reboots. */ + metric { + name = "swap_total" + title = "Swap Space Total" + } + metric { + name = "boottime" + title = "Last Boot Time" + } + metric { + name = "machine_type" + title = "Machine Type" + } + metric { + name = "os_name" + title = "Operating System" + } + metric { + name = "os_release" + title = "Operating System Release" + } + metric { + name = "location" + title = "Location" + } +} + +/* This collection group will send the status of gexecd for this host every 300 secs */ +/* Unlike 2.5.x the default behavior is to report gexecd OFF. */ +collection_group { + collect_once = yes + time_threshold = 300 + metric { + name = "gexec" + title = "Gexec Status" + } +} + +/* This collection group will collect the CPU status info every 20 secs. + The time threshold is set to 90 seconds. In honesty, this time_threshold could be + set significantly higher to reduce unneccessary network chatter. */ +collection_group { + collect_every = 20 + time_threshold = 90 + /* CPU status */ + metric { + name = "cpu_user" + value_threshold = "1.0" + title = "CPU User" + } + metric { + name = "cpu_system" + value_threshold = "1.0" + title = "CPU System" + } + metric { + name = "cpu_idle" + value_threshold = "5.0" + title = "CPU Idle" + } + metric { + name = "cpu_nice" + value_threshold = "1.0" + title = "CPU Nice" + } + metric { + name = "cpu_aidle" + value_threshold = "5.0" + title = "CPU aidle" + } + metric { + name = "cpu_wio" + value_threshold = "1.0" + title = "CPU wio" + } + /* The next two metrics are optional if you want more detail... + ... since they are accounted for in cpu_system. + metric { + name = "cpu_intr" + value_threshold = "1.0" + title = "CPU intr" + } + metric { + name = "cpu_sintr" + value_threshold = "1.0" + title = "CPU sintr" + } + */ +} + +collection_group { + collect_every = 20 + time_threshold = 90 + /* Load Averages */ + metric { + name = "load_one" + value_threshold = "1.0" + title = "One Minute Load Average" + } + metric { + name = "load_five" + value_threshold = "1.0" + title = "Five Minute Load Average" + } + metric { + name = "load_fifteen" + value_threshold = "1.0" + title = "Fifteen Minute Load Average" + } +} + +/* This group collects the number of running and total processes */ +collection_group { + collect_every = 80 + time_threshold = 950 + metric { + name = "proc_run" + value_threshold = "1.0" + title = "Total Running Processes" + } + metric { + name = "proc_total" + value_threshold = "1.0" + title = "Total Processes" + } +} + +/* This collection group grabs the volatile memory metrics every 40 secs and + sends them at least every 180 secs. This time_threshold can be increased + significantly to reduce unneeded network traffic. */ +collection_group { + collect_every = 40 + time_threshold = 180 + metric { + name = "mem_free" + value_threshold = "1024.0" + title = "Free Memory" + } + metric { + name = "mem_shared" + value_threshold = "1024.0" + title = "Shared Memory" + } + metric { + name = "mem_buffers" + value_threshold = "1024.0" + title = "Memory Buffers" + } + metric { + name = "mem_cached" + value_threshold = "1024.0" + title = "Cached Memory" + } + metric { + name = "swap_free" + value_threshold = "1024.0" + title = "Free Swap Space" + } +} + +collection_group { + collect_every = 40 + time_threshold = 300 + metric { + name = "bytes_out" + value_threshold = 4096 + title = "Bytes Sent" + } + metric { + name = "bytes_in" + value_threshold = 4096 + title = "Bytes Received" + } + metric { + name = "pkts_in" + value_threshold = 256 + title = "Packets Received" + } + metric { + name = "pkts_out" + value_threshold = 256 + title = "Packets Sent" + } +} + +/* Different than 2.5.x default since the old config made no sense */ +collection_group { + collect_every = 1800 + time_threshold = 3600 + metric { + name = "disk_total" + value_threshold = 1.0 + title = "Total Disk Space" + } +} + +collection_group { + collect_every = 40 + time_threshold = 180 + metric { + name = "disk_free" + value_threshold = 1.0 + title = "Disk Space Available" + } + metric { + name = "part_max_used" + value_threshold = 1.0 + title = "Maximum Disk Space Used" + } +} + diff --git a/gems/README.rdoc b/gems/README.rdoc new file mode 100644 index 0000000..e0c1e40 --- /dev/null +++ b/gems/README.rdoc @@ -0,0 +1,31 @@ += DESCRIPTION: + +Installs a set of gems + += REQUIREMENTS: + +== Cookbooks: + +* ruby_enterprise + += ATTRIBUTES: + +* gems - array os hashes with :name, :version and :source for the gem + += LICENSE and AUTHOR: + +Author:: Fabio Akita () +Copyright:: 2010, Prodigus Consulting. + +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/gems/attributes/gems.rb b/gems/attributes/gems.rb new file mode 100644 index 0000000..1e8a1d9 --- /dev/null +++ b/gems/attributes/gems.rb @@ -0,0 +1 @@ +set_unless[:gems] = [{ :name => "rake" }] \ No newline at end of file diff --git a/gems/metadata.json b/gems/metadata.json new file mode 100644 index 0000000..855d8dd --- /dev/null +++ b/gems/metadata.json @@ -0,0 +1,40 @@ +{ + "suggestions": { + + }, + "conflicting": { + + }, + "providing": { + "gems": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "= DESCRIPTION:\n\nInstalls a set of gems\n\n= REQUIREMENTS:\n\n== Cookbooks:\n\n* ruby_enterprise\n\n= ATTRIBUTES:\n\n* gems - array os hashes with :name, :version and :source for the gem\n\n= LICENSE and AUTHOR:\n\nAuthor:: Fabio Akita ()\nCopyright:: 2010, Prodigus Consulting.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\n", + "recipes": { + "gems": "" + }, + "attributes": { + + }, + "replacing": { + + }, + "dependencies": { + "ruby_enterprise": [ + + ] + }, + "platforms": { + + }, + "maintainer": "Prodigus Consulting", + "description": "Installs/Configures gems", + "name": "gems", + "version": "0.1.0", + "recommendations": { + + }, + "maintainer_email": "fabioakita@gmail.com" +} \ No newline at end of file diff --git a/gems/metadata.rb b/gems/metadata.rb new file mode 100644 index 0000000..3f41e54 --- /dev/null +++ b/gems/metadata.rb @@ -0,0 +1,7 @@ +maintainer "Prodigus Consulting" +maintainer_email "fabioakita@gmail.com" +license "Apache 2.0" +description "Installs/Configures gems" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.1" +depends "ruby_enterprise" diff --git a/gems/recipes/default.rb b/gems/recipes/default.rb new file mode 100644 index 0000000..d9d8951 --- /dev/null +++ b/gems/recipes/default.rb @@ -0,0 +1,29 @@ +# +# Cookbook Name:: gems +# Recipe:: default +# +# Copyright 2010, Prodigus Consulting +# +# 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. +# +node[:gems].each do |gem| + gem_package gem[:name] do + if gem[:version] && !gem[:version].empty? + version gem[:version] + end + if gem[:source] + source gem[:source] + end + action :install + end +end \ No newline at end of file diff --git a/git/README.rdoc b/git/README.rdoc new file mode 100644 index 0000000..8bfa17c --- /dev/null +++ b/git/README.rdoc @@ -0,0 +1,37 @@ += DESCRIPTION: + +Installs git. + += REQUIREMENTS: + +== Cookbooks: + +Opscode Cookbooks (http://github.com/opscode/cookbooks/tree/master) + +* runit + += USAGE: + +This cookbook primarily installs git core packages. It can also be used to serve git repositories. + + include_recipe "git::server" + +This creates the directory /srv/git and starts a git daemon, exporting all repositories found. Repositories need to be added manually, but will be available once they are created. + += LICENSE and AUTHOR: + +Author:: Joshua Timberman () + +Copyright:: 2009, Opscode, 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. \ No newline at end of file diff --git a/git/metadata.json b/git/metadata.json new file mode 100644 index 0000000..a435277 --- /dev/null +++ b/git/metadata.json @@ -0,0 +1,52 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs git and\/or sets up a Git server daemon", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "git::server": "Sets up a runit_service for git daemon", + "git": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "debian": [ + + ] + }, + "version": "0.7.0", + "name": "git", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "git::server": [ + + ], + "git": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "= DESCRIPTION:\n\nInstalls git.\n\n= REQUIREMENTS:\n\n== Cookbooks:\n\nOpscode Cookbooks (http:\/\/github.com\/opscode\/cookbooks\/tree\/master)\n\n* runit\n\n= USAGE:\n\nThis cookbook primarily installs git core packages. It can also be used to serve git repositories.\n\n include_recipe \"git::server\"\n\nThis creates the directory \/srv\/git and starts a git daemon, exporting all repositories found. Repositories need to be added manually, but will be available once they are created.\n\n= LICENSE and AUTHOR:\n \nAuthor:: Joshua Timberman ()\n\nCopyright:: 2009, Opscode, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http:\/\/www.apache.org\/licenses\/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.", + "replacing": { + + }, + "dependencies": { + "runit": [ + + ], + "apache2": [ + + ] + } +} \ No newline at end of file diff --git a/git/metadata.rb b/git/metadata.rb new file mode 100644 index 0000000..465b217 --- /dev/null +++ b/git/metadata.rb @@ -0,0 +1,15 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs git and/or sets up a Git server daemon" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.7" +recipe "git::server", "Sets up a runit_service for git daemon" + +%w{ ubuntu debian }.each do |os| + supports os +end + +%w{ apache2 runit }.each do |cb| + depends cb +end diff --git a/git/recipes/default.rb b/git/recipes/default.rb new file mode 100644 index 0000000..36b2121 --- /dev/null +++ b/git/recipes/default.rb @@ -0,0 +1,26 @@ +# +# Cookbook Name:: git +# Recipe:: default +# +# Copyright 2008-2009, Opscode, 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. + +case node[:platform] +when "debian", "ubuntu" + package "git-core" +else + package "git" +end + +package "git-email" diff --git a/git/recipes/server.rb b/git/recipes/server.rb new file mode 100644 index 0000000..8edd5de --- /dev/null +++ b/git/recipes/server.rb @@ -0,0 +1,28 @@ +# +# Cookbook Name:: git +# Recipe:: server +# +# Copyright 2009, Opscode, 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 "git" +include_recipe "runit" + +directory "/srv/git" do + owner "root" + group "root" + mode 0755 +end + +runit_service "git-daemon" diff --git a/git/templates/default/sv-git-daemon-log-run.erb b/git/templates/default/sv-git-daemon-log-run.erb new file mode 100644 index 0000000..a79a518 --- /dev/null +++ b/git/templates/default/sv-git-daemon-log-run.erb @@ -0,0 +1,2 @@ +#!/bin/sh +exec svlogd -tt ./main diff --git a/git/templates/default/sv-git-daemon-run.erb b/git/templates/default/sv-git-daemon-run.erb new file mode 100644 index 0000000..3f3e53d --- /dev/null +++ b/git/templates/default/sv-git-daemon-run.erb @@ -0,0 +1,3 @@ +#!/bin/sh +exec 2>&1 +exec /usr/bin/git daemon --export-all --user nobody --group daemon --base-path=/srv/git /srv/git diff --git a/gitosis/files/default/access.py b/gitosis/files/default/access.py new file mode 100755 index 0000000..a41bc63 --- /dev/null +++ b/gitosis/files/default/access.py @@ -0,0 +1,102 @@ +import os, logging +import re, fnmatch +from ConfigParser import NoSectionError, NoOptionError + +from gitosis import group + +def isWildcardAccessible(path, repos, validpats=re.compile(r"\*|\?|\[.*?\]")): + """ + Check if path is accessible with wildcards. + + Only wildcards containing *, ? or [] are accepted. + """ + for repo in repos: + if not validpats.search(repo): + continue + if fnmatch.fnmatch(path, repo): + return True + return False + +def haveAccess(config, user, mode, path): + """ + Map request for write access to allowed path. + + Note for read-only access, the caller should check for write + access too. + + Returns ``None`` for no access, or a tuple of toplevel directory + containing repositories and a relative path to the physical repository. + """ + log = logging.getLogger('gitosis.access.haveAccess') + + log.debug( + 'Access check for %(user)r as %(mode)r on %(path)r...' + % dict( + user=user, + mode=mode, + path=path, + )) + + basename, ext = os.path.splitext(path) + if ext == '.git': + log.debug( + 'Stripping .git suffix from %(path)r, new value %(basename)r' + % dict( + path=path, + basename=basename, + )) + path = basename + + for groupname in group.getMembership(config=config, user=user): + try: + repos = config.get('group %s' % groupname, mode) + except (NoSectionError, NoOptionError): + repos = [] + else: + repos = repos.split() + + mapping = None + + if path in repos or isWildcardAccessible(path, repos): + log.debug( + 'Access ok for %(user)r as %(mode)r on %(path)r' + % dict( + user=user, + mode=mode, + path=path, + )) + mapping = path + else: + try: + mapping = config.get('group %s' % groupname, + 'map %s %s' % (mode, path)) + except (NoSectionError, NoOptionError): + pass + else: + log.debug( + 'Access ok for %(user)r as %(mode)r on %(path)r=%(mapping)r' + % dict( + user=user, + mode=mode, + path=path, + mapping=mapping, + )) + + if mapping is not None: + prefix = None + try: + prefix = config.get( + 'group %s' % groupname, 'repositories') + except (NoSectionError, NoOptionError): + try: + prefix = config.get('gitosis', 'repositories') + except (NoSectionError, NoOptionError): + prefix = 'repositories' + + log.debug( + 'Using prefix %(prefix)r for %(path)r' + % dict( + prefix=prefix, + path=mapping, + )) + return (prefix, mapping) diff --git a/gitosis/files/default/serve.py b/gitosis/files/default/serve.py new file mode 100755 index 0000000..d62fdd8 --- /dev/null +++ b/gitosis/files/default/serve.py @@ -0,0 +1,207 @@ +""" +Enforce git-shell to only serve allowed by access control policy. +directory. The client should refer to them without any extra directory +prefix. Repository names are forced to match ALLOW_RE. +""" + +import logging + +import sys, os, re + +from gitosis import access +from gitosis import repository +from gitosis import gitweb +from gitosis import gitdaemon +from gitosis import app +from gitosis import util + +log = logging.getLogger('gitosis.serve') + +ALLOW_RE = re.compile("^'/*(?P[a-zA-Z0-9][a-zA-Z0-9@._-]*(/[a-zA-Z0-9][a-zA-Z0-9@._-]*)*)'$") + +COMMANDS_READONLY = [ + 'git-upload-pack', + 'git upload-pack', + ] + +COMMANDS_WRITE = [ + 'git-receive-pack', + 'git receive-pack', + ] + +class ServingError(Exception): + """Serving error""" + + def __str__(self): + return '%s' % self.__doc__ + +class CommandMayNotContainNewlineError(ServingError): + """Command may not contain newline""" + +class UnknownCommandError(ServingError): + """Unknown command denied""" + +class UnsafeArgumentsError(ServingError): + """Arguments to command look dangerous""" + +class AccessDenied(ServingError): + """Access denied to repository""" + +class WriteAccessDenied(AccessDenied): + """Repository write access denied""" + +class ReadAccessDenied(AccessDenied): + """Repository read access denied""" + +def serve( + cfg, + user, + command, + ): + if '\n' in command: + raise CommandMayNotContainNewlineError() + + try: + verb, args = command.split(None, 1) + except ValueError: + # all known "git-foo" commands take one argument; improve + # if/when needed + raise UnknownCommandError() + + if verb == 'git': + try: + subverb, args = args.split(None, 1) + except ValueError: + # all known "git foo" commands take one argument; improve + # if/when needed + raise UnknownCommandError() + verb = '%s %s' % (verb, subverb) + + if (verb not in COMMANDS_WRITE + and verb not in COMMANDS_READONLY): + raise UnknownCommandError() + + match = ALLOW_RE.match(args) + if match is None: + raise UnsafeArgumentsError() + + path = match.group('path') + + # write access is always sufficient + newpath = access.haveAccess( + config=cfg, + user=user, + mode='writable', + path=path) + + if newpath is None: + # didn't have write access; try once more with the popular + # misspelling + newpath = access.haveAccess( + config=cfg, + user=user, + mode='writeable', + path=path) + if newpath is not None: + log.warning( + 'Repository %r config has typo "writeable", ' + +'should be "writable"', + path, + ) + + if newpath is None: + # didn't have write access + + newpath = access.haveAccess( + config=cfg, + user=user, + mode='readonly', + path=path) + + if newpath is None: + raise ReadAccessDenied() + + if verb in COMMANDS_WRITE: + # didn't have write access and tried to write + raise WriteAccessDenied() + + (topdir, relpath) = newpath + assert not relpath.endswith('.git'), \ + 'git extension should have been stripped: %r' % relpath + repopath = '%s.git' % relpath + fullpath = os.path.join(topdir, repopath) + if (not os.path.exists(fullpath) + and verb in COMMANDS_WRITE): + # it doesn't exist on the filesystem, but the configuration + # refers to it, we're serving a write request, and the user is + # authorized to do that: create the repository on the fly + + # create leading directories + p = topdir + for segment in repopath.split(os.sep)[:-1]: + p = os.path.join(p, segment) + util.mkdir(p, 0750) + + repository.init(path=fullpath) + gitweb.set_descriptions( + config=cfg, + ) + generated = util.getGeneratedFilesDir(config=cfg) + gitweb.generate_project_list( + config=cfg, + path=os.path.join(generated, 'projects.list'), + ) + gitdaemon.set_export_ok( + config=cfg, + ) + + # put the verb back together with the new path + newcmd = "%(verb)s '%(path)s'" % dict( + verb=verb, + path=fullpath, + ) + return newcmd + +class Main(app.App): + def create_parser(self): + parser = super(Main, self).create_parser() + parser.set_usage('%prog [OPTS] USER') + parser.set_description( + 'Allow restricted git operations under DIR') + return parser + + def handle_args(self, parser, cfg, options, args): + try: + (user,) = args + except ValueError: + parser.error('Missing argument USER.') + + main_log = logging.getLogger('gitosis.serve.main') + os.umask(0022) + + cmd = os.environ.get('SSH_ORIGINAL_COMMAND', None) + if cmd is None: + main_log.error('Need SSH_ORIGINAL_COMMAND in environment.') + sys.exit(1) + + main_log.debug('Got command %(cmd)r' % dict( + cmd=cmd, + )) + + os.chdir(os.path.expanduser('~')) + + try: + newcmd = serve( + cfg=cfg, + user=user, + command=cmd, + ) + except ServingError, e: + main_log.error('%s', e) + sys.exit(1) + + main_log.debug('Serving %s', newcmd) + os.environ['GITOSIS_USER'] = user + os.execvp('git-shell', ['git-shell', '-c', newcmd]) + main_log.error('Cannot execute git-shell.') + sys.exit(1) diff --git a/gitosis/metadata.json b/gitosis/metadata.json new file mode 100755 index 0000000..6dbc8c8 --- /dev/null +++ b/gitosis/metadata.json @@ -0,0 +1,38 @@ +{ + "replacing": { + + }, + "long_description": "", + "attributes": { + + }, + "maintainer": "37signals", + "recommendations": { + + }, + "license": "Apache v2.0", + "recipes": { + "gitosis": "" + }, + "maintainer_email": "sysadmins@37signals.com", + "suggestions": { + + }, + "dependencies": { + + }, + "conflicting": { + + }, + "platforms": { + + }, + "description": "Configures Gitosis", + "version": "0.1.0", + "name": "gitosis", + "providing": { + "gitosis": [ + + ] + } +} \ No newline at end of file diff --git a/gitosis/metadata.rb b/gitosis/metadata.rb new file mode 100755 index 0000000..deaaa30 --- /dev/null +++ b/gitosis/metadata.rb @@ -0,0 +1,4 @@ +maintainer "37signals" +maintainer_email "sysadmins@37signals.com" +description "Configures Gitosis" +version "0.1" diff --git a/gitosis/recipes/default.rb b/gitosis/recipes/default.rb new file mode 100755 index 0000000..eb25891 --- /dev/null +++ b/gitosis/recipes/default.rb @@ -0,0 +1,20 @@ + +package "gitosis" + +user "gitosis" do + action :remove +end + +group "gitosis" do + action :remove +end + +# Install local modifications to Gitosis +%W(access.py serve.py).each do |patched| + remote_file "/usr/share/python-support/gitosis/gitosis-0.2-py2.5.egg/gitosis/#{patched}" do + source "#{patched}" + owner "root" + group "root" + mode 0755 + end +end diff --git a/gitweb/attributes/gitweb.rb b/gitweb/attributes/gitweb.rb new file mode 100755 index 0000000..e6af5b0 --- /dev/null +++ b/gitweb/attributes/gitweb.rb @@ -0,0 +1 @@ +default.gitweb[:config_path] = "/etc/gitweb" \ No newline at end of file diff --git a/gitweb/metadata.json b/gitweb/metadata.json new file mode 100755 index 0000000..a1cfe66 --- /dev/null +++ b/gitweb/metadata.json @@ -0,0 +1,43 @@ +{ + "replacing": { + + }, + "long_description": "", + "attributes": { + + }, + "maintainer": "37signals", + "recommendations": { + + }, + "license": "Apache v2.0", + "recipes": { + "gitweb": "" + }, + "maintainer_email": "sysadmins@37signals.com", + "suggestions": { + + }, + "dependencies": { + "git": [ + + ], + "apache2": [ + + ] + }, + "conflicting": { + + }, + "platforms": { + + }, + "description": "Configures gitweb", + "version": "0.1.0", + "name": "gitweb", + "providing": { + "gitweb": [ + + ] + } +} \ No newline at end of file diff --git a/gitweb/metadata.rb b/gitweb/metadata.rb new file mode 100755 index 0000000..e8c23b4 --- /dev/null +++ b/gitweb/metadata.rb @@ -0,0 +1,6 @@ +maintainer "37signals" +maintainer_email "sysadmins@37signals.com" +description "Configures gitweb" +version "0.1" +depends "apache2" +depends "git" \ No newline at end of file diff --git a/gitweb/recipes/default.rb b/gitweb/recipes/default.rb new file mode 100755 index 0000000..5e9ce82 --- /dev/null +++ b/gitweb/recipes/default.rb @@ -0,0 +1,18 @@ +require_recipe "git::server" + +package "gitweb" + +directory node[:gitweb][:config_path] do + mode 0755 + recursive true +end + +template "/etc/gitweb/apache.conf" + +template "/etc/gitweb/projects.conf" do + variables :projects => node[:git][:repos] +end + +apache_site "gitweb" do + config_path "/etc/gitweb/apache.conf" +end \ No newline at end of file diff --git a/gitweb/templates/default/apache-vhost.conf.erb b/gitweb/templates/default/apache-vhost.conf.erb new file mode 100755 index 0000000..0026e09 --- /dev/null +++ b/gitweb/templates/default/apache-vhost.conf.erb @@ -0,0 +1,32 @@ + + + DocumentRoot /usr/share/gitweb + ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ + + SSLEngine on + SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem + SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key + + RewriteEngine on + + # support gitc-style URLs + + RewriteRule ^/c/(.+)/(.+)$ /gitweb/$1.git?a=commitdiff&h=$2 [R,L] + + RewriteRule ^/gitweb/([a-zA-Z0-9_\/-]+\.git)/?(\?.*)?$ /cgi-bin/gitweb.cgi/$1 [L,PT] + + Alias /gitweb /usr/share/gitweb + + + Options Indexes FollowSymlinks ExecCGI + DirectoryIndex /cgi-bin/gitweb.cgi + AllowOverride None + + + + Order allow,deny + Allow from all + AllowOverride None + + + \ No newline at end of file diff --git a/gitweb/templates/default/apache.conf.erb b/gitweb/templates/default/apache.conf.erb new file mode 100755 index 0000000..0026e09 --- /dev/null +++ b/gitweb/templates/default/apache.conf.erb @@ -0,0 +1,32 @@ + + + DocumentRoot /usr/share/gitweb + ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ + + SSLEngine on + SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem + SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key + + RewriteEngine on + + # support gitc-style URLs + + RewriteRule ^/c/(.+)/(.+)$ /gitweb/$1.git?a=commitdiff&h=$2 [R,L] + + RewriteRule ^/gitweb/([a-zA-Z0-9_\/-]+\.git)/?(\?.*)?$ /cgi-bin/gitweb.cgi/$1 [L,PT] + + Alias /gitweb /usr/share/gitweb + + + Options Indexes FollowSymlinks ExecCGI + DirectoryIndex /cgi-bin/gitweb.cgi + AllowOverride None + + + + Order allow,deny + Allow from all + AllowOverride None + + + \ No newline at end of file diff --git a/gitweb/templates/default/gitweb.conf.erb b/gitweb/templates/default/gitweb.conf.erb new file mode 100755 index 0000000..2e67548 --- /dev/null +++ b/gitweb/templates/default/gitweb.conf.erb @@ -0,0 +1,26 @@ +# path to git projects (.git) +$projectroot = "<%= @node[:git][:repo_root] %>"; + +# directory to use for temp files +$git_temp = "/tmp"; + +# target of the home link on top of all pages +#$home_link = $my_uri || "/"; + +# html text to include at home page +$home_text = "indextext.html"; + +# file with project list; by default, simply scan the projectroot dir. +$projects_list = "/etc/gitweb/projects.conf"; + +# stylesheet to use +$stylesheet = "/gitweb.css"; + +# logo to use +$logo = "/git-logo.png"; + +# the 'favicon' +$favicon = "/git-favicon.png"; + +# restrict access to projects on visible overview page +$strict_export = true; \ No newline at end of file diff --git a/gitweb/templates/default/projects.conf.erb b/gitweb/templates/default/projects.conf.erb new file mode 100755 index 0000000..b8d9ee6 --- /dev/null +++ b/gitweb/templates/default/projects.conf.erb @@ -0,0 +1,4 @@ +<% @projects.each do |name, conf| %> +<% next if conf[:visible] == false %> +<%= name %> Gitosis+User +<% end %> \ No newline at end of file diff --git a/glassfish/README.rdoc b/glassfish/README.rdoc new file mode 100644 index 0000000..8d77480 --- /dev/null +++ b/glassfish/README.rdoc @@ -0,0 +1,8 @@ += DESCRIPTION: + += REQUIREMENTS: + += ATTRIBUTES: + += USAGE: + diff --git a/glassfish/attributes/glassfish.rb b/glassfish/attributes/glassfish.rb new file mode 100644 index 0000000..686309f --- /dev/null +++ b/glassfish/attributes/glassfish.rb @@ -0,0 +1,82 @@ +# +# Cookbook Name:: glassfish +# Attribute File:: glassfish +# +# Copyright 2009, Opscode, 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. +# +#openInstaller Dry Run Answer File. This File can be used as input to the openInstaller engine using the -a option. + +# unis system user +set_unless[:glassfish][:systemuser]="glassfish" +#unix system group +set_unless[:glassfish][:systemgroup]="glassfish" +# fetch_url +set_unless[:glassfish][:fetch_url]="http://download.java.net/glassfish/v3-prelude/promoted/glassfish-v3-prelude-b28f-unix.sh" +#InstallHome.directory.INSTALL_HOME= +set_unless[:glassfish][:INSTALL_HOME]="/opt/glassfishv3-prelude" +#License.license.ACCEPT_LICENSE=0 +set_unless[:glassfish][:ACCEPT_LICENSE]="0" +#RegistrationOptions.regoptions.CREATE_NEWACCT=CREATE_NEWACCT +set_unless[:glassfish][:CREATE_NEWACCT]="CREATE_NEWACCT" +#RegistrationOptions.regoptions.DUMMY_PROP= +set_unless[:glassfish][:DUMMY_PROP]="" +#RegistrationOptions.regoptions.SKIP_REGISTRATION=SKIP_REGISTRATION +set_unless[:glassfish][:SKIP_REGISTRATION]="SKIP_REGISTRATION" +#RegistrationOptions.regoptions.USERNAME= +set_unless[:glassfish][:USERNAME]="" +#RegistrationOptions.regoptions.USERPASSWORD= +set_unless[:glassfish][:USERPASSWORD]="" +#RegistrationOptions.regoptions.USE_EXISTINGACCT=USE_EXISTINGACCT +set_unless[:glassfish][:USE_EXISTINGACCT]="USE_EXISTINGACCT" +#SOAccountCreation.accountinfo.COMPANYNAME= +set_unless[:glassfish][:COMPANYNAME]="" +#SOAccountCreation.accountinfo.COUNTRY= +set_unless[:glassfish][:COUNTRY]="" +#SOAccountCreation.accountinfo.COUNTRY_DROP_DOWN= +set_unless[:glassfish][:COUNTRY_DROP_DOWN]="" +#SOAccountCreation.accountinfo.EMAIL= +set_unless[:glassfish][:EMAIL]="" +#SOAccountCreation.accountinfo.FIRSTNAME= +set_unless[:glassfish][:FIRSTNAME]="" +#SOAccountCreation.accountinfo.LASTNAME= +set_unless[:glassfish][:LASTNAME]="" +#SOAccountCreation.accountinfo.PASSWORD= +set_unless[:glassfish][:PASSWORD]="" +#SOAccountCreation.accountinfo.REENTERPASSWORD= +set_unless[:glassfish][:REENTERPASSWORD]="" +#glassfish.Administration.ADMIN_PASSWORD=adminadmin +set_unless[:glassfish][:ADMIN_PASSWORD]="adminadmin" +#glassfish.Administration.ADMIN_PORT=4848 +set_unless[:glassfish][:ADMIN_PORT]="4848" +#glassfish.Administration.ADMIN_USER=admin +set_unless[:glassfish][:ADMIN_USER]="admin" +#glassfish.Administration.ANONYMOUS=ANONYMOUS +set_unless[:glassfish][:ANONYMOUS]="ANONYMOUS" +#glassfish.Administration.LOGIN_MODE=true +set_unless[:glassfish][:LOGIN_MODE]="true" +#glassfish.Administration.HTTP_PORT=8080 +set_unless[:glassfish][:HTTP_PORT]="8081" +# Can be set to anonymous or non_anonymous, to require administrator to log in with user name and password. +# glassfish.Administration.NON_ANONYMOUS=NON_ANONYMOUS +set_unless[:glassfish][:NON_ANONYMOUS]="NON_ANONYMOUS" +#updatetool.Configuration.ALLOW_UPDATE_CHECK=true +set_unless[:glassfish][:ALLOW_UPDATE_CHECK]="false" +#updatetool.Configuration.BOOTSTRAP_UPDATETOOL=true +set_unless[:glassfish][:BOOTSTRAP_UPDATETOOL]="false" +#updatetool.Configuration.PROXY_HOST= +set_unless[:glassfish][:PROXY_HOST]= "" +#updatetool.Configuration.PROXY_PORT= +set_unless[:glassfish][:PROXY_PORT]= "" + diff --git a/glassfish/metadata.json b/glassfish/metadata.json new file mode 100644 index 0000000..2b9713e --- /dev/null +++ b/glassfish/metadata.json @@ -0,0 +1,50 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs\/Configures Glassfish", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "glassfish": "Main Glassfish configuration", + "glassfish": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "centos": [ + + ], + "debian": [ + + ], + "redhat": [ + + ] + }, + "version": "0.1.0", + "name": "glassfish", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "glassfish": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "= DESCRIPTION:\n\n= REQUIREMENTS:\n\n= ATTRIBUTES: \n\n= USAGE:\n\n", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/glassfish/metadata.rb b/glassfish/metadata.rb new file mode 100644 index 0000000..3a782db --- /dev/null +++ b/glassfish/metadata.rb @@ -0,0 +1,11 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs/Configures Glassfish" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.1" +recipe "glassfish", "Main Glassfish configuration" + +%w{redhat centos debian ubuntu}.each do |os| + supports os +end diff --git a/glassfish/recipes/default.rb b/glassfish/recipes/default.rb new file mode 100644 index 0000000..b07e4dd --- /dev/null +++ b/glassfish/recipes/default.rb @@ -0,0 +1,73 @@ +# +# Cookbook Name:: glassfish +# Recipe:: default +# +# Copyright 2009, Opscode, 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. +# + + +group node[:glassfish][:systemgroup] do +end + +user node[:glassfish][:systemuser] do + comment "SUN Glassfish" + gid node[:glassfish][:systemgroup] + home node[:glassfish][:INSTALL_HOME] + shell "/bin/sh" +end + +remote_file "/tmp/glassfish.sh" do + owner node[:glassfish][:systemuser] + source node[:glassfish][:fetch_url] + mode "0744" + checksum "6d4a20f14de" +end + +answer_file = "/tmp/v3-prelude-answer" + +template answer_file do + owner node[:glassfish][:systemuser] + source "answer_file.erb" +end + +directory node[:glassfish][:INSTALL_HOME] do + owner node[:glassfish][:systemuser] + group node[:glassfish][:systemgroup] + mode "0755" + action :create + recursive true +end + +execute "install-glassfish" do + command "/tmp/glassfish.sh -a #{answer_file} -s" + creates File.join(node[:glassfish][:INSTALL_HOME],"uninstall.sh") + user node[:glassfish][:systemuser] + action :run +end + +file answer_file do + action :delete +end + +template "/etc/init.d/glassfish" do + source "glassfish-init.d-script.erb" + mode "0755" +end + +service "glassfish" do + supports :start => true, :restart => true, :stop => true + action [ :enable, :start ] +end + diff --git a/glassfish/templates/default/answer_file.erb b/glassfish/templates/default/answer_file.erb new file mode 100644 index 0000000..4880d89 --- /dev/null +++ b/glassfish/templates/default/answer_file.erb @@ -0,0 +1,27 @@ +InstallHome.directory.INSTALL_HOME=<%= @node[:glassfish][:INSTALL_HOME] %> +License.license.ACCEPT_LICENSE=<%= @node[:glassfish][:ACCEPT_LICENSE] %> +RegistrationOptions.regoptions.CREATE_NEWACCT=<%= @node[:glassfish][:CREATE_NEWACCT] %> +RegistrationOptions.regoptions.DUMMY_PROP=<%= @node[:glassfish][:DUMMY_PROP] %> +RegistrationOptions.regoptions.SKIP_REGISTRATION=<%= @node[:glassfish][:SKIP_REGISTRATION] %> +RegistrationOptions.regoptions.USERNAME=<%= @node[:glassfish][:USERNAME] %> +RegistrationOptions.regoptions.USERPASSWORD=<%= @node[:glassfish][:USERPASSWORD] %> +RegistrationOptions.regoptions.USE_EXISTINGACCT=<%= @node[:glassfish][:USE_EXISTINGACCT] %> +SOAccountCreation.accountinfo.COMPANYNAME=<%= @node[:glassfish][:COMPANYNAME] %> +SOAccountCreation.accountinfo.COUNTRY=<%= @node[:glassfish][:COUNTRY] %> +SOAccountCreation.accountinfo.COUNTRY_DROP_DOWN=<%= @node[:glassfish][:COUNTRY_DROP_DOWN] %> +SOAccountCreation.accountinfo.EMAIL=<%= @node[:glassfish][:EMAIL] %> +SOAccountCreation.accountinfo.FIRSTNAME=<%= @node[:glassfish][:FIRSTNAME] %> +SOAccountCreation.accountinfo.LASTNAME=<%= @node[:glassfish][:LASTNAME] %> +SOAccountCreation.accountinfo.PASSWORD=<%= @node[:glassfish][:PASSWORD] %> +SOAccountCreation.accountinfo.REENTERPASSWORD=<%= @node[:glassfish][:REENTERPASSWORD] %> +glassfish.Administration.ADMIN_PASSWORD=<%= @node[:glassfish][:ADMIN_PASSWORD] %> +glassfish.Administration.ADMIN_PORT=<%= @node[:glassfish][:ADMIN_PORT] %> +glassfish.Administration.ADMIN_USER=<%= @node[:glassfish][:ADMIN_USER] %> +glassfish.Administration.ANONYMOUS=<%= @node[:glassfish][:ANONYMOUS] %> +glassfish.Administration.LOGIN_MODE=<%= @node[:glassfish][:LOGIN_MODE] %> +glassfish.Administration.HTTP_PORT=<%= @node[:glassfish][:HTTP_PORT] %> +glassfish.Administration.NON_ANONYMOUS=<%= @node[:glassfish][:NON_ANONYMOUS] %> +updatetool.Configuration.ALLOW_UPDATE_CHECK=<%= @node[:glassfish][:ALLOW_UPDATE_CHECK] %> +updatetool.Configuration.BOOTSTRAP_UPDATETOOL=<%= @node[:glassfish][:BOOTSTRAP_UPDATETOOL] %> +updatetool.Configuration.PROXY_HOST=<%= @node[:glassfish][:PROXY_HOST] %> +updatetool.Configuration.PROXY_PORT=<%= @node[:glassfish][:PROXY_PORT] %> diff --git a/glassfish/templates/default/glassfish-init.d-script.erb b/glassfish/templates/default/glassfish-init.d-script.erb new file mode 100644 index 0000000..f402c77 --- /dev/null +++ b/glassfish/templates/default/glassfish-init.d-script.erb @@ -0,0 +1,44 @@ +#!/bin/bash +# +# glassfish: Startup script for Glassfish Application Server. +# +# chkconfig: 3 80 05 +# description: Startup script for domain1 of Glassfish Application Server. + +GLASSFISH_HOME=<%= File.join(@node[:glassfish][:INSTALL_HOME],"glassfish") %> +export GLASSFISH_HOME + +GLASSFISH_OWNER=<%= @node[:glassfish][:systemuser] %> ; +export GLASSFISH_OWNER + +start() { + echo -n "Starting Glassfish: " + echo "Starting Glassfish at `date`" >> $GLASSFISH_HOME/domains/domain1/logs/startup.log + su $GLASSFISH_OWNER -c "$GLASSFISH_HOME/bin/asadmin start-domain domain1" >> $GLASSFISH_HOME/domains/domain1/logs/startup.log + sleep 2 + echo "done" +} + +stop() { + echo -n "Stopping Glassfish: " + echo "Stopping Glassfish at `date`" >> $GLASSFISH_HOME/domains/domain1/logs/startup.log + su $GLASSFISH_OWNER -c "$GLASSFISH_HOME/bin/asadmin stop-domain domain1" >> $GLASSFISH_HOME/domains/domain1/logs/startup.log + echo "done" +} + +# See how we were called. +case "$1" in + start) + start + ;; + stop) + stop + ;; + restart) + stop + start + ;; + *) + echo $"Usage: glassfish {start|stop|restart}" + exit +esac diff --git a/gnupg/metadata.json b/gnupg/metadata.json new file mode 100755 index 0000000..2635d3a --- /dev/null +++ b/gnupg/metadata.json @@ -0,0 +1,38 @@ +{ + "replacing": { + + }, + "long_description": "", + "attributes": { + + }, + "maintainer": "37signals", + "recommendations": { + + }, + "license": "Apache v2.0", + "recipes": { + "gnupg": "" + }, + "maintainer_email": "sysadmins@37signals.com", + "suggestions": { + + }, + "dependencies": { + + }, + "conflicting": { + + }, + "platforms": { + + }, + "description": "Configures gnupg", + "version": "0.1.0", + "name": "gnupg", + "providing": { + "gnupg": [ + + ] + } +} \ No newline at end of file diff --git a/gnupg/metadata.rb b/gnupg/metadata.rb new file mode 100755 index 0000000..472e01d --- /dev/null +++ b/gnupg/metadata.rb @@ -0,0 +1,4 @@ +maintainer "37signals" +maintainer_email "sysadmins@37signals.com" +description "Configures gnupg" +version "0.1" diff --git a/gnupg/recipes/default.rb b/gnupg/recipes/default.rb new file mode 100755 index 0000000..f8af316 --- /dev/null +++ b/gnupg/recipes/default.rb @@ -0,0 +1 @@ +package "gnupg" diff --git a/god/README.rdoc b/god/README.rdoc new file mode 100644 index 0000000..2a86aa0 --- /dev/null +++ b/god/README.rdoc @@ -0,0 +1,49 @@ += DESCRIPTION: + +Installs god gem, sets up modular configuration directory and provides a define to monitor processes. + += REQUIREMENTS: + +== Platform and Application Environment: + +Tested on Ubuntu 8.10. May work on other platforms, esp Ubuntu/Debian. Sample configuration file uses mongrel_runit for managing mongrels via runit. + +== Cookbooks: + +Opscode cookbooks, http://github.com/opscode/cookbooks/tree/master: + +* ruby +* runit + +Opscode does not yet have a mongrel_runit cookbook. + += ATTRIBUTES: + +No attributes are used. + += USAGE: + +This recipe is designed to be used through the god_monitor define. Create a god configuration file in your application's cookbook and then call god_monitor: + + god_monitor "myproj" do + config "myproj.god.erb" + end + +A sample mongrel.god.erb is provided, though it assumes mongrel_runit is used. This can be used as a baseline for customization. + += LICENSE and AUTHOR: + +Author:: Joshua Timberman () +Copyright:: 2009, Opscode, 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/god/definitions/god_monitor.rb b/god/definitions/god_monitor.rb new file mode 100644 index 0000000..1a13c25 --- /dev/null +++ b/god/definitions/god_monitor.rb @@ -0,0 +1,38 @@ +# +# Cookbook Name:: god +# Definition:: god_monitor +# +# Copyright 2009, Opscode, 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. +# + +define :god_monitor, :config => "mongrel.god.erb", :max_memory => 100, :cpu => 50 do + include_recipe "god" + + template "/etc/god/conf.d/#{params[:name]}.god" do + source params[:config] + owner "root" + group "root" + mode 0644 + variables( + :name => params[:name], + :max_memory => params[:max_memory], + :cpu => params[:cpu], + :sv_bin => node[:runit][:sv_bin], + :params => params + ) + notifies :restart, resources(:service => "god") + end + +end diff --git a/god/metadata.json b/god/metadata.json new file mode 100644 index 0000000..5b47dc8 --- /dev/null +++ b/god/metadata.json @@ -0,0 +1,48 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs and configures god and provides a define for monitoring", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "god": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "debian": [ + + ] + }, + "version": "0.7.0", + "name": "god", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "god": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "= DESCRIPTION:\n\nInstalls god gem, sets up modular configuration directory and provides a define to monitor processes.\n\n= REQUIREMENTS:\n\n== Platform and Application Environment:\n\nTested on Ubuntu 8.10. May work on other platforms, esp Ubuntu\/Debian. Sample configuration file uses mongrel_runit for managing mongrels via runit. \n\n== Cookbooks:\n\nOpscode cookbooks, http:\/\/github.com\/opscode\/cookbooks\/tree\/master:\n\n* ruby\n* runit\n\nOpscode does not yet have a mongrel_runit cookbook.\n\n= ATTRIBUTES: \n\nNo attributes are used.\n\n= USAGE:\n\nThis recipe is designed to be used through the god_monitor define. Create a god configuration file in your application's cookbook and then call god_monitor:\n\n god_monitor \"myproj\" do\n config \"myproj.god.erb\"\n end\n\nA sample mongrel.god.erb is provided, though it assumes mongrel_runit is used. This can be used as a baseline for customization.\n\n= LICENSE and AUTHOR:\n \nAuthor:: Joshua Timberman ()\nCopyright:: 2009, Opscode, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http:\/\/www.apache.org\/licenses\/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n", + "replacing": { + + }, + "dependencies": { + "runit": [ + + ], + "ruby": [ + + ] + } +} \ No newline at end of file diff --git a/god/metadata.rb b/god/metadata.rb new file mode 100644 index 0000000..0657f8f --- /dev/null +++ b/god/metadata.rb @@ -0,0 +1,14 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs and configures god and provides a define for monitoring" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.7" + +%w{debian ubuntu}.each do |os| + supports os +end + +%w{ ruby runit }.each do |cb| + depends cb +end diff --git a/god/recipes/default.rb b/god/recipes/default.rb new file mode 100644 index 0000000..7d98392 --- /dev/null +++ b/god/recipes/default.rb @@ -0,0 +1,41 @@ +# +# Cookbook Name:: god +# Recipe:: default +# +# Copyright 2009, Opscode, 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 "ruby" +include_recipe "runit" + +gem_package "god" do + action :install +end + +directory "/etc/god/conf.d" do + recursive true + owner "root" + group "root" + mode 0755 +end + +template "/etc/god/master.god" do + source "master.god.erb" + owner "root" + group "root" + mode 0755 +end + +runit_service "god" diff --git a/god/templates/default/master.god.erb b/god/templates/default/master.god.erb new file mode 100644 index 0000000..2836258 --- /dev/null +++ b/god/templates/default/master.god.erb @@ -0,0 +1,20 @@ +# +# Generated by Chef for <%= @node[:hostname] %> +# +God.load "/etc/god/conf.d/*.god" + +God::Contacts::Email.message_settings = { + :from => 'god@<%= @node[:domain] %>' +} + +God::Contacts::Email.server_settings = { + :address => "localhost", + :port => 25, + :domain => "<%= @node[:domain] %>", +} + +God.contact(:email) do |c| + c.name = 'ops' + c.email = 'ops@<%= @node[:domain] %>' +end + diff --git a/god/templates/default/mongrel.god.erb b/god/templates/default/mongrel.god.erb new file mode 100644 index 0000000..742e6fa --- /dev/null +++ b/god/templates/default/mongrel.god.erb @@ -0,0 +1,40 @@ +# Generated by Chef + +mongrel_list = Array.new +Dir["/etc/sv/mongrel-<%= @name %>-*"].each do |file| + file =~ /mongrel-(.+)-(\d+)/ + group = $1 + port = $2 + mongrel = Hash.new + mongrel[:name] = "#{group}-#{port}" + mongrel[:start] = "<%= @sv_bin %> start #{file}" + mongrel[:stop] = "<%= @sv_bin %> stop #{file}" + mongrel[:restart] = "<%= @sv_bin %> restart #{file}" + mongrel[:pidfile] = File.join(file, "supervise", "pid") + mongrel[:port] = port + mongrel_list << mongrel +end + +mongrel_list.each do |mongrel| + God.watch do |w| + w.name = mongrel[:name] + w.interval = 30.seconds # default + w.start = mongrel[:start] + w.stop = mongrel[:stop] + w.restart = mongrel[:restart] + w.start_grace = 10.seconds + w.restart_grace = 10.seconds + w.pid_file = mongrel[:pidfile] + + w.restart_if do |restart| + restart.condition(:memory_usage) do |c| + c.above = <%= @max_memory %>.megabytes + end + + restart.condition(:cpu_usage) do |c| + c.above = <%= @cpu %>.percent + c.times = 5 + end + end + end +end diff --git a/god/templates/default/sv-god-log-run.erb b/god/templates/default/sv-god-log-run.erb new file mode 100644 index 0000000..a79a518 --- /dev/null +++ b/god/templates/default/sv-god-log-run.erb @@ -0,0 +1,2 @@ +#!/bin/sh +exec svlogd -tt ./main diff --git a/god/templates/default/sv-god-run.erb b/god/templates/default/sv-god-run.erb new file mode 100644 index 0000000..b3c31d4 --- /dev/null +++ b/god/templates/default/sv-god-run.erb @@ -0,0 +1,6 @@ +#!/bin/sh +exec 2>&1 + +trap 'kill -HUP %1' 1 2 13 15 + +/usr/bin/god -D -c /etc/god/master.god --no-syslog & wait diff --git a/hadoop/README.rdoc b/hadoop/README.rdoc new file mode 100644 index 0000000..e9e1e6b --- /dev/null +++ b/hadoop/README.rdoc @@ -0,0 +1,63 @@ += DESCRIPTION: + +Installs Apache hadoop and sets up a basic distributed cluster per the quick start documentation. + += REQUIREMENTS: + +== Platform: + +Tested on Ubuntu 8.10, though should work on most Linux distributions, see hadoop[:java_home]. + +== Cookbooks: + +Opscode cookbooks, http://github.com/opscode/cookbooks/tree/master: + +* java + += ATTRIBUTES: + +* hadoop[:mirror_url] - Get a mirror from http://www.apache.org/dyn/closer.cgi/hadoop/core/. +* hadoop[:version] - Specify the version of hadoop to install. +* hadoop[:uid] - Default userid of the hadoop user. +* hadoop[:gid] - Default group for the hadoop user. +* hadoop[:java_home] - You will probably want to change this to match where Java is installed on your platform. + +You may wish to add more attributes for tuning the configuration file templates. + += USAGE: + +This cookbook performs the tasks described in the Hadoop Quick Start[1] to get the software installed. You should copy this to a site-cookbook and modify the templates to meet your requirements. + +Once the recipe is run, the distributed filesystem can be formated using the script /usr/bin/hadoop. + + sudo -u hadoop /usr/bin/hadoop namenode -format + +You may need to set up SSH keys for hadoop management commands. + +Note that this is not the 'default' config per se, so using the start-all.sh script won't start the processes because the config files live elsewhere. For running various hadoop processes as services, we suggest runit. A sample 'run' script is provided. The HADOOP_LOG_DIR in the run script must exist for each process. These could be wrapped in a define. + +* datanode +* jobtracker +* namenode +* tasktracker + + +[1] http://hadoop.apache.org/core/docs/current/quickstart.html + += LICENSE and AUTHOR: + +Author:: Joshua Timberman () + +Copyright:: 2009, Opscode, 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. \ No newline at end of file diff --git a/hadoop/metadata.json b/hadoop/metadata.json new file mode 100644 index 0000000..b6f5243 --- /dev/null +++ b/hadoop/metadata.json @@ -0,0 +1,61 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs hadoop and sets up basic cluster per Cloudera's quick start docs", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "hadoop::doc": "", + "hadoop::pig": "", + "hadoop": "", + "hadoop::hive": "", + "hadoop::conf_pseudo": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "debian": [ + + ] + }, + "version": "0.8.0", + "name": "hadoop", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "hadoop::doc": [ + + ], + "hadoop::pig": [ + + ], + "hadoop::hive": [ + + ], + "hadoop": [ + + ], + "hadoop::conf_pseudo": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "= DESCRIPTION:\n\nInstalls Apache hadoop and sets up a basic distributed cluster per the quick start documentation.\n\n= REQUIREMENTS:\n\n== Platform:\n\nTested on Ubuntu 8.10, though should work on most Linux distributions, see hadoop[:java_home].\n\n== Cookbooks:\n\nOpscode cookbooks, http:\/\/github.com\/opscode\/cookbooks\/tree\/master:\n\n* java\n\n= ATTRIBUTES: \n\n* hadoop[:mirror_url] - Get a mirror from http:\/\/www.apache.org\/dyn\/closer.cgi\/hadoop\/core\/.\n* hadoop[:version] - Specify the version of hadoop to install.\n* hadoop[:uid] - Default userid of the hadoop user.\n* hadoop[:gid] - Default group for the hadoop user.\n* hadoop[:java_home] - You will probably want to change this to match where Java is installed on your platform.\n\nYou may wish to add more attributes for tuning the configuration file templates.\n\n= USAGE:\n\nThis cookbook performs the tasks described in the Hadoop Quick Start[1] to get the software installed. You should copy this to a site-cookbook and modify the templates to meet your requirements. \n\nOnce the recipe is run, the distributed filesystem can be formated using the script \/usr\/bin\/hadoop. \n\n sudo -u hadoop \/usr\/bin\/hadoop namenode -format\n \nYou may need to set up SSH keys for hadoop management commands. \n\nNote that this is not the 'default' config per se, so using the start-all.sh script won't start the processes because the config files live elsewhere. For running various hadoop processes as services, we suggest runit. A sample 'run' script is provided. The HADOOP_LOG_DIR in the run script must exist for each process. These could be wrapped in a define. \n\n* datanode\n* jobtracker\n* namenode\n* tasktracker\n\n\n[1] http:\/\/hadoop.apache.org\/core\/docs\/current\/quickstart.html\n\n= LICENSE and AUTHOR:\n \nAuthor:: Joshua Timberman ()\n\nCopyright:: 2009, Opscode, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http:\/\/www.apache.org\/licenses\/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.", + "replacing": { + + }, + "dependencies": { + "java": [ + + ] + } +} \ No newline at end of file diff --git a/hadoop/metadata.rb b/hadoop/metadata.rb new file mode 100644 index 0000000..29d7bc4 --- /dev/null +++ b/hadoop/metadata.rb @@ -0,0 +1,11 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs hadoop and sets up basic cluster per Cloudera's quick start docs" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.8" +depends "java" + +%w{ debian ubuntu }.each do |os| + supports os +end diff --git a/hadoop/recipes/conf_pseudo.rb b/hadoop/recipes/conf_pseudo.rb new file mode 100644 index 0000000..65d4406 --- /dev/null +++ b/hadoop/recipes/conf_pseudo.rb @@ -0,0 +1,29 @@ +# +# Cookbook Name:: hadoop +# Recipe:: conf_pseudo +# +# Copyright 2009, Opscode, 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 "hadoop" + +package "hadoop-conf-pseudo" + +%w{namenode secondarynamenode datanode jobtracker tasktracker}.each do |d| + service "hadoop-#{d}" do + action [ :start, :enable ] + end +end + diff --git a/hadoop/recipes/default.rb b/hadoop/recipes/default.rb new file mode 100644 index 0000000..2104f95 --- /dev/null +++ b/hadoop/recipes/default.rb @@ -0,0 +1,38 @@ +# +# Cookbook Name:: hadoop +# Recipe:: default +# +# Copyright 2009, Opscode, 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 "java" + +execute "apt-get update" do + action :nothing +end + +template "/etc/apt/sources.list.d/cloudera.list" do + owner "root" + mode "0644" + source "cloudera.list.erb" + notifies :run, resources("execute[apt-get update]"), :immediately +end + +execute "curl -s http://archive.cloudera.com/debian/archive.key | apt-key add -" do + not_if "apt-key export 'Cloudera Apt Repository'" +end + +package "hadoop" + diff --git a/hadoop/recipes/doc.rb b/hadoop/recipes/doc.rb new file mode 100644 index 0000000..47cb0ba --- /dev/null +++ b/hadoop/recipes/doc.rb @@ -0,0 +1,22 @@ +# +# Cookbook Name:: hadoop +# Recipe:: doc +# +# Copyright 2009, Opscode, 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 "java" + +package "hadoop-doc" diff --git a/hadoop/recipes/hive.rb b/hadoop/recipes/hive.rb new file mode 100644 index 0000000..df71304 --- /dev/null +++ b/hadoop/recipes/hive.rb @@ -0,0 +1,22 @@ +# +# Cookbook Name:: hadoop +# Recipe:: hive +# +# Copyright 2009, Opscode, 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 "hadoop" + +package "hive" diff --git a/hadoop/recipes/pig.rb b/hadoop/recipes/pig.rb new file mode 100644 index 0000000..65285b0 --- /dev/null +++ b/hadoop/recipes/pig.rb @@ -0,0 +1,22 @@ +# +# Cookbook Name:: hadoop +# Recipe:: pig +# +# Copyright 2009, Opscode, 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 "hadoop" + +package "pig" diff --git a/hadoop/templates/default/cloudera.list.erb b/hadoop/templates/default/cloudera.list.erb new file mode 100644 index 0000000..ab9e5b8 --- /dev/null +++ b/hadoop/templates/default/cloudera.list.erb @@ -0,0 +1,2 @@ +deb http://archive.cloudera.com/debian <%= @node[:lsb][:codename] %> contrib +deb-src http://archive.cloudera.com/debian <%= @node[:lsb][:codename] %> contrib diff --git a/haproxy/README.rdoc b/haproxy/README.rdoc new file mode 100644 index 0000000..a184c78 --- /dev/null +++ b/haproxy/README.rdoc @@ -0,0 +1,37 @@ += DESCRIPTION: + +Installs haproxy and prepares the configuration location. + += REQUIREMENTS: + +== Platform: + +Tested on Ubuntu 8.10. + +== Cookbooks: + += ATTRIBUTES: + +No haproxy-specific attributes are used. + += USAGE: + +Update the haproxy.cfg file with listener(s) for your sites/servers. + += LICENSE and AUTHOR: + +Author:: Joshua Timberman () + +Copyright:: 2009, Opscode, 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/haproxy/metadata.json b/haproxy/metadata.json new file mode 100644 index 0000000..77df8ff --- /dev/null +++ b/haproxy/metadata.json @@ -0,0 +1,43 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs and configures haproxy", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "haproxy": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "debian": [ + + ] + }, + "version": "0.7.0", + "name": "haproxy", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "haproxy": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "= DESCRIPTION:\n\nInstalls haproxy and prepares the configuration location.\n\n= REQUIREMENTS:\n\n== Platform:\n\nTested on Ubuntu 8.10.\n\n== Cookbooks:\n\n= ATTRIBUTES: \n\nNo haproxy-specific attributes are used.\n\n= USAGE:\n\nUpdate the haproxy.cfg file with listener(s) for your sites\/servers.\n\n= LICENSE and AUTHOR:\n \nAuthor:: Joshua Timberman ()\n\nCopyright:: 2009, Opscode, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http:\/\/www.apache.org\/licenses\/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/haproxy/metadata.rb b/haproxy/metadata.rb new file mode 100644 index 0000000..5fb7c37 --- /dev/null +++ b/haproxy/metadata.rb @@ -0,0 +1,10 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs and configures haproxy" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.7" + +%w{ debian ubuntu }.each do |os| + supports os +end diff --git a/haproxy/recipes/default.rb b/haproxy/recipes/default.rb new file mode 100644 index 0000000..54b7f40 --- /dev/null +++ b/haproxy/recipes/default.rb @@ -0,0 +1,42 @@ +# +# Cookbook Name:: haproxy +# Recipe:: default +# +# Copyright 2009, Opscode, 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 "haproxy" do + action :install +end + +template "/etc/default/haproxy" do + source "haproxy-default.erb" + owner "root" + group "root" + mode 0644 +end + +service "haproxy" do + supports :restart => true, :status => true, :reload => true + action [:enable, :start] +end + +template "/etc/haproxy/haproxy.cfg" do + source "haproxy.cfg.erb" + owner "root" + group "root" + mode 0644 + notifies :restart, resources(:service => "haproxy") +end diff --git a/haproxy/templates/default/haproxy-default.erb b/haproxy/templates/default/haproxy-default.erb new file mode 100644 index 0000000..9a2ee79 --- /dev/null +++ b/haproxy/templates/default/haproxy-default.erb @@ -0,0 +1,4 @@ +# Set ENABLED to 1 if you want the init script to start haproxy. +ENABLED=1 +# Add extra flags here. +#EXTRAOPTS="-de -m 16" diff --git a/haproxy/templates/default/haproxy.cfg.erb b/haproxy/templates/default/haproxy.cfg.erb new file mode 100644 index 0000000..5a09bcd --- /dev/null +++ b/haproxy/templates/default/haproxy.cfg.erb @@ -0,0 +1,27 @@ +global + log 127.0.0.1 local0 + log 127.0.0.1 local1 notice + #log loghost local0 info + maxconn 4096 + #debug + #quiet + user haproxy + group haproxy + +defaults + log global + mode http + option httplog + option dontlognull + retries 3 + redispatch + maxconn 2000 + contimeout 5000 + clitimeout 50000 + srvtimeout 50000 + +# Set up application listeners here. +listen application 0.0.0.0:8400 + balance roundrobin + server localhost 127.0.0.1:4000 weight 1 maxconn 5 check + server localhost 127.0.0.1:4001 weight 1 maxconn 5 check diff --git a/heartbeat/metadata.json b/heartbeat/metadata.json new file mode 100644 index 0000000..fae9edb --- /dev/null +++ b/heartbeat/metadata.json @@ -0,0 +1,45 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs but does not configure heartbeat", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "heartbeat": "" + }, + "suggestions": { + "drbd": [ + + ] + }, + "platforms": { + "ubuntu": [ + + ], + "debian": [ + + ] + }, + "version": "0.7.0", + "name": "heartbeat", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "heartbeat": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/heartbeat/metadata.rb b/heartbeat/metadata.rb new file mode 100644 index 0000000..f6db20a --- /dev/null +++ b/heartbeat/metadata.rb @@ -0,0 +1,10 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs but does not configure heartbeat" +version "0.7" +suggests "drbd" + +%w{ debian ubuntu }.each do |os| + supports os +end diff --git a/heartbeat/recipes/default.rb b/heartbeat/recipes/default.rb new file mode 100644 index 0000000..5d6f5f7 --- /dev/null +++ b/heartbeat/recipes/default.rb @@ -0,0 +1,39 @@ +# +# Cookbook Name:: heartbeat +# Recipe:: default +# +# Copyright 2009, Opscode, 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. +# +# = Requirements +# Templates:: +# * /etc/ha.d/ha.cf +# * /etc/ha.d/haresources +# * /etc/ha.d/authkeys + +%w{ heartbeat-2 heartbeat-2-dev }.each do |pkg| + package pkg do + action :install + end +end + +service "heartbeat" do + supports( + :restart => true, + :status => true + ) + action :enable +end + + diff --git a/hosts/attributes/hosts.rb b/hosts/attributes/hosts.rb new file mode 100755 index 0000000..1f15d2e --- /dev/null +++ b/hosts/attributes/hosts.rb @@ -0,0 +1 @@ +hosts Mash.new unless attribute?(:hosts) \ No newline at end of file diff --git a/hosts/metadata.json b/hosts/metadata.json new file mode 100755 index 0000000..b66e578 --- /dev/null +++ b/hosts/metadata.json @@ -0,0 +1,38 @@ +{ + "replacing": { + + }, + "long_description": "", + "attributes": { + + }, + "maintainer": "37signals", + "recommendations": { + + }, + "license": "Apache v2.0", + "recipes": { + "hosts": "" + }, + "maintainer_email": "sysadmins@37signals.com", + "suggestions": { + + }, + "dependencies": { + + }, + "conflicting": { + + }, + "platforms": { + + }, + "description": "Configures hosts", + "version": "0.1.0", + "name": "hosts", + "providing": { + "hosts": [ + + ] + } +} \ No newline at end of file diff --git a/hosts/metadata.rb b/hosts/metadata.rb new file mode 100755 index 0000000..f173c48 --- /dev/null +++ b/hosts/metadata.rb @@ -0,0 +1,4 @@ +maintainer "37signals" +maintainer_email "sysadmins@37signals.com" +description "Configures hosts" +version "0.1" diff --git a/hosts/recipes/default.rb b/hosts/recipes/default.rb new file mode 100755 index 0000000..605d213 --- /dev/null +++ b/hosts/recipes/default.rb @@ -0,0 +1,6 @@ +template "/etc/hosts" do + source "hosts.erb" + owner "root" + group "root" + mode 0644 +end diff --git a/hosts/templates/default/hosts.erb b/hosts/templates/default/hosts.erb new file mode 100755 index 0000000..79e257d --- /dev/null +++ b/hosts/templates/default/hosts.erb @@ -0,0 +1,27 @@ +127.0.0.1 localhost <%= @node[:hosts][:localhost_aliases].join(" ") if @node[:hosts][:localhost_aliases] %> +127.0.1.1 <%= @node['fqdn'] %> <%= @node['hostname'] %> <%= "chef.#{@node['domain']}" if @node.recipes.include?("chef::server") %> + +<% if @node[:hosts][:entries] %> +<% @node[:hosts][:entries].each do |h| %> +<%= h.join(" ") %> +<% end %> +<% end %> + +<% if @node[:domain] == "rack-dfw-int.37signals.com" %> +192.168.0.32 queenbee.37signals.com queenbee +192.168.0.5 ob.37signals.com ob +192.168.1.151 basecamp.db.37signals.com +192.168.2.82 basecamp.search.37signals.com +192.168.1.122 backpack.search.37signals.com +192.168.1.120 backpack.db.37signals.com +192.168.1.127 campfire.db.37signals.com +192.168.1.114 dev.37signals.com +<% end %> + +# The following lines are desirable for IPv6 capable hosts +::1 ip6-localhost ip6-loopback +fe00::0 ip6-localnet +ff00::0 ip6-mcastprefix +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters +ff02::3 ip6-allhosts diff --git a/imagemagick/README.rdoc b/imagemagick/README.rdoc new file mode 100644 index 0000000..f750c67 --- /dev/null +++ b/imagemagick/README.rdoc @@ -0,0 +1,37 @@ += DESCRIPTION: + +Installs ImageMagick and optionally Rmagick (RubyGem). + += REQUIREMENTS: + +Should work on RHEL and Debian plus derivatives. + += USAGE: + +To install just ImageMagick, + + include_recipe "imagemagick" + +In your own recipe/cookbook. To install the RubyGem rmagick, + + include_recipe "imagemagick::rmagick" + +Which will install imagemagick, as well as the development libraries for imagemagick (so rmagick can be built). + += LICENSE: + +Author:: Joshua Timberman () + +Copyright:: 2009, Opscode, 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/imagemagick/metadata.json b/imagemagick/metadata.json new file mode 100644 index 0000000..63253af --- /dev/null +++ b/imagemagick/metadata.json @@ -0,0 +1,56 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs\/Configures imagemagick", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "imagemagick::rmagick": "", + "imagemagick": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "rhel": [ + + ], + "fedora": [ + + ], + "centos": [ + + ], + "debian": [ + + ] + }, + "version": "0.1.0", + "name": "imagemagick", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "imagemagick::rmagick": [ + + ], + "imagemagick": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "= DESCRIPTION:\n\nInstalls ImageMagick and optionally Rmagick (RubyGem).\n\n= REQUIREMENTS:\n\nShould work on RHEL and Debian plus derivatives.\n\n= USAGE:\n\nTo install just ImageMagick,\n\n include_recipe \"imagemagick\"\n \nIn your own recipe\/cookbook. To install the RubyGem rmagick,\n\n include_recipe \"imagemagick::rmagick\"\n \nWhich will install imagemagick, as well as the development libraries for imagemagick (so rmagick can be built).\n\n= LICENSE:\n\nAuthor:: Joshua Timberman ()\n\nCopyright:: 2009, Opscode, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http:\/\/www.apache.org\/licenses\/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/imagemagick/metadata.rb b/imagemagick/metadata.rb new file mode 100644 index 0000000..7b508d5 --- /dev/null +++ b/imagemagick/metadata.rb @@ -0,0 +1,10 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs/Configures imagemagick" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.1" + +%w{fedora centos rhel ubuntu debian}.each do |os| + supports os +end diff --git a/imagemagick/recipes/default.rb b/imagemagick/recipes/default.rb new file mode 100644 index 0000000..921a904 --- /dev/null +++ b/imagemagick/recipes/default.rb @@ -0,0 +1,25 @@ +# +# Cookbook Name:: imagemagick +# Recipe:: default +# +# Copyright 2009, Opscode, 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. +# + +case node[:platform] +when "redhat", "centos", "fedora" + package "ImageMagick" +when "debian", "ubuntu" + package "imagemagick" +end diff --git a/imagemagick/recipes/rmagick.rb b/imagemagick/recipes/rmagick.rb new file mode 100644 index 0000000..f951107 --- /dev/null +++ b/imagemagick/recipes/rmagick.rb @@ -0,0 +1,28 @@ +# +# Cookbook Name:: imagemagick +# Recipe:: rmagick +# +# Copyright 2009, Opscode, 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 "imagemagick" + +case node[:platform] +when "redhat", "centos", "fedora" + package "ImageMagick-devel" +when "debian", "ubuntu" + package "libmagickwand-dev" +end + +gem_package "rmagick" diff --git a/instiki/README.rdoc b/instiki/README.rdoc new file mode 100644 index 0000000..3170119 --- /dev/null +++ b/instiki/README.rdoc @@ -0,0 +1,33 @@ += DESCRIPTION: + +Installs instiki, a Ruby on Rails wiki server under passenger+Apache2. + += REQUIREMENTS: + +Opscode cookbooks: + +* apache2 +* passenger_apache2 +* sqlite +* rails + += USAGE: + +Simply apply the 'instiki' recipe. This installs version 0.17 in /srv/instiki/instiki-0.17. A later version of this cookbook might support setting the version and a different installation path, but for now these are hardcoded. + += LICENSE and AUTHOR: + +Author:: Joshua Timberman + +Copyright 2009, Opscode, 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 diff --git a/instiki/metadata.rb b/instiki/metadata.rb new file mode 100644 index 0000000..0320601 --- /dev/null +++ b/instiki/metadata.rb @@ -0,0 +1,10 @@ +maintainer "Opscode" +maintainer_email "joshua@opscode.com" +license "Apache 2.0" +description "Installs instiki, a Ruby on Rails wiki server under passenger+Apache2." +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.1" + +%w{ apache2 passenger_apache2 sqlite rails }.each do |cb| + depends cb +end diff --git a/instiki/recipes/default.rb b/instiki/recipes/default.rb new file mode 100644 index 0000000..4d25348 --- /dev/null +++ b/instiki/recipes/default.rb @@ -0,0 +1,50 @@ +# +# Cookbook Name:: instiki +# Recipe:: default +# +# Copyright 2009, Opscode +# +# 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 "sqlite" +include_recipe "rails" +include_recipe "apache2" +include_recipe "apache2::mod_rewrite" +include_recipe "passenger_apache2" +include_recipe "passenger_apache2::mod_rails" + +remote_file "/tmp/instiki-0.17.tar.gz" do + source "http://rubyforge.org/frs/download.php/59127/instiki-0.17.tgz" + mode 0644 + owner "root" + group "root" + not_if { ::FileTest.exists?("/tmp/instiki-0.17.tar.gz") } +end + +directory "/srv/instiki" do + owner node[:apache][:user] +end + +execute "tar zxf /tmp/instiki-0.17.tar.gz -C /srv/instiki" do + user node[:apache][:user] + creates "/srv/instiki/instiki-0.17/instiki" +end + +web_app "instiki" do + docroot "/srv/instiki/instiki-0.17/public" + template "instiki.conf.erb" + server_name "wiki.#{node[:domain]}" + server_aliases [ "wiki", "instiki", node[:hostname] ] + rails_env "production" +end diff --git a/instiki/templates/default/instiki.conf.erb b/instiki/templates/default/instiki.conf.erb new file mode 100644 index 0000000..2602e6a --- /dev/null +++ b/instiki/templates/default/instiki.conf.erb @@ -0,0 +1,20 @@ + + ServerName <%= @params[:server_name] %> + ServerAlias <% @params[:server_aliases].each do |a| %><%= "#{a}" %> <% end %> + DocumentRoot <%= @params[:docroot] %> + + RailsBaseURI / + RailsEnv <%= @params[:rails_env] %> + + > + Options FollowSymLinks + AllowOverride None + Order allow,deny + Allow from all + + + LogLevel info + ErrorLog <%= @node[:apache][:log_dir] %>/<%= @params[:name] %>-error.log + CustomLog <%= @node[:apache][:log_dir] %>/<%= @params[:name] %>-access.log combined + + diff --git a/integrity/attributes/integrity.rb b/integrity/attributes/integrity.rb new file mode 100755 index 0000000..1d7386d --- /dev/null +++ b/integrity/attributes/integrity.rb @@ -0,0 +1,11 @@ +integrity Mash.new unless attribute?(:integrity) +integrity[:server_name] = "integrity.37signals.com" unless integrity.has_key?(:server_name) +integrity[:url] = "http://#{integrity[:server_name]}" unless integrity.has_key?(:url) +integrity[:path] = "/u/apps/integrity" unless integrity.has_key?(:path) +integrity[:db_uri] = "sqlite3://#{integrity[:path]}/integrity.db" unless integrity.has_key?(:db_uri) +integrity[:export_dir] = "#{integrity[:path]}/builds" unless integrity.has_key?(:export_dir) +integrity[:log_file] = "#{integrity[:path]}/log/integrity.log" unless integrity.has_key?(:log_file) +integrity[:basic_auth] = "true" unless integrity.has_key?(:basic_auth) +integrity[:admin_username] = "admin" unless integrity.has_key?(:admin_username) +integrity[:admin_password] = "12345678" unless integrity.has_key?(:admin_password) +integrity[:hash_admin_password] = "true" unless integrity.has_key?(:hash_admin_password) diff --git a/integrity/files/default/integrity_build.rb b/integrity/files/default/integrity_build.rb new file mode 100755 index 0000000..9ede31a --- /dev/null +++ b/integrity/files/default/integrity_build.rb @@ -0,0 +1,22 @@ +#!/usr/bin/env ruby + +# Integrity periodic build script. +# Original: http://gist.github.com/88432 + +ENV["RAILS_ENV"] = "test" +ENV["PATH"] = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + +require 'rubygems' +require 'integrity' +require 'notifier/campfire' + +Integrity::Notifier.register(Integrity::Notifier::Campfire) + +Integrity.new(File.dirname(__FILE__) + "/config.yml") + +Integrity::Project.all.each do |project| + last_commit = project.commits.last + build = last_commit ? project.send(:head_of_remote_repo) != last_commit.identifier : false + project.build if build || project.commits.last.nil? +end + diff --git a/integrity/metadata.json b/integrity/metadata.json new file mode 100755 index 0000000..64ea7be --- /dev/null +++ b/integrity/metadata.json @@ -0,0 +1,40 @@ +{ + "replacing": { + + }, + "long_description": "", + "attributes": { + + }, + "maintainer": "37signals", + "recommendations": { + + }, + "license": "Apache v2.0", + "recipes": { + "integrity": "" + }, + "maintainer_email": "sysadmins@37signals.com", + "suggestions": { + + }, + "dependencies": { + "passenger": [ + + ] + }, + "conflicting": { + + }, + "platforms": { + + }, + "description": "Configures integrity", + "version": "0.1.0", + "name": "integrity", + "providing": { + "integrity": [ + + ] + } +} \ No newline at end of file diff --git a/integrity/metadata.rb b/integrity/metadata.rb new file mode 100755 index 0000000..b154a01 --- /dev/null +++ b/integrity/metadata.rb @@ -0,0 +1,5 @@ +maintainer "37signals" +maintainer_email "sysadmins@37signals.com" +description "Configures integrity" +version "0.1" +depends "passenger" \ No newline at end of file diff --git a/integrity/recipes/default.rb b/integrity/recipes/default.rb new file mode 100755 index 0000000..f3693f1 --- /dev/null +++ b/integrity/recipes/default.rb @@ -0,0 +1,111 @@ +require_recipe "passenger" + +gem_package "integrity" do + source "http://localgems" +end + +gem_package "integrity-campfire" do + source "http://localgems" +end + +gem_package "fiveruns-dash-rails" do + source "http://gems.github.com" +end + +gem_package "do_sqlite3" +gem_package "do_mysql" +gem_package "mocha" +gem_package "rcov" +gem_package "ruby-debug" +gem_package "quietbacktrace" +gem_package "tinder" + +if node[:integrity][:projects] + node[:integrity][:projects].each do |app| + if node[:applications][app][:gems] + node[:applications][app][:gems].each do |g| + if g.is_a? Array + gem_package g.first do + version g.last + end + else + gem_package g + end + end + end + + if node[:applications][app][:packages] + node[:applications][app][:packages].each do |package_name| + package package_name + end + end + + if node[:applications][app][:symlinks] + node[:applications][app][:symlinks].each do |target, source| + link target do + to source + end + end + end + end +end + +directory "/u/apps" do + owner "app" + group "app" + mode 0755 + recursive true +end + +execute "setup_integrity" do + command "integrity install #{node[:integrity][:path]} --passenger" + user "app" + group "app" + not_if "test -e /u/apps/integrity" +end + +template "#{node[:integrity][:path]}/config.ru" do + source "config.ru.erb" + owner "app" + group "app" + mode 0644 +end + +template "#{node[:integrity][:path]}/config.yml" do + source "config.yml.erb" + owner "app" + group "app" + mode 0644 +end + +template "#{node[:integrity][:path]}/vhost.conf" do + source "vhost.conf.erb" + owner "app" + group "app" + mode 0644 +end + +remote_file "#{node[:integrity][:path]}/integrity_build.rb" do + source "integrity_build.rb" + owner "app" + group "app" + mode 0700 +end + +cron "integrity_build" do + user "app" + minute "*/10" + command "/usr/local/bin/ruby #{node[:integrity][:path]}/integrity_build.rb" + only_if { File.exist?(File.join(node[:integrity][:path], "integrity_build.rb")) } +end + +apache_site "integrity" do + config_path "#{node[:integrity][:path]}/vhost.conf" + not_if { File.exists?("/etc/apache2/sites-enabled/integrity") } +end + +logrotate "integrity" do + files "#{node[:integrity][:path]}/log/*.log" + frequency "weekly" + restart_command "/etc/init.d/apache2 reload > /dev/null" +end diff --git a/integrity/templates/default/config.ru.erb b/integrity/templates/default/config.ru.erb new file mode 100755 index 0000000..7b513ac --- /dev/null +++ b/integrity/templates/default/config.ru.erb @@ -0,0 +1,14 @@ +#!/usr/bin/env ruby +require "rubygems" +require "integrity" +require 'notifier/campfire' + +# Load configuration and initialize Integrity +Integrity.new(File.dirname(__FILE__) + "/config.yml") +Integrity::Notifier.register(Integrity::Notifier::Campfire) + +# You probably don't want to edit anything below +Integrity::App.set :environment, ENV["RACK_ENV"] || :production +Integrity::App.set :port, 8910 + +run Integrity::App diff --git a/integrity/templates/default/config.yml.erb b/integrity/templates/default/config.yml.erb new file mode 100755 index 0000000..73a2535 --- /dev/null +++ b/integrity/templates/default/config.yml.erb @@ -0,0 +1,41 @@ +# Domain where integrity will be running from. This is used to have +# nice URLs in your notifications. +# For example: +# http://builder.integrityapp.com +:base_uri: <%= @node[:integrity][:url] %> + +# This should be a complete connection string to your database. +# +# Examples: +# * `mysql://user:password@localhost/integrity` +# * `postgres://user:password@localhost/integrity` +# * `sqlite3:///home/integrity/db/integrity.sqlite` +# +# Note: +# * The appropriate data_objects adapter must be installed (`do_mysql`, etc) +# * You must create the `integrity` database on localhost, of course. +:database_uri: <%= @node[:integrity][:db_uri] %> + +# This is where your project's code will be checked out to. Make sure it's +# writable by the user that runs Integrity. +:export_directory: <%= @node[:integrity][:export_dir] %> + +# Path to the integrity log file +:log: <%= @node[:integrity][:log_file] %> + +# Enable or disable HTTP authentication for the app. BE AWARE that if you +# disable this anyone can delete and alter projects, so do it only if your +# app is running in a controlled environment (ie, behind your company's +# firewall.) +:use_basic_auth: <%= @node[:integrity][:basic_auth] %> + +# When `use_basic_auth` is true, the admin's username for HTTP authentication. +:admin_username: <%= @node[:integrity][:admin_username] %> + +# When `use_basic_auth` is true, the admin's password. Usually saved as a +# SHA1 hash. See the next option. +:admin_password: <%= @node[:integrity][:admin_password] %> + +# If this is true, then whenever we authenticate the admin user, will hash +# it using SHA1. If not, we'll assume the provided password is in plain text. +:hash_admin_password: <%= @node[:integrity][:hash_admin_password] %> diff --git a/integrity/templates/default/vhost.conf.erb b/integrity/templates/default/vhost.conf.erb new file mode 100755 index 0000000..6511beb --- /dev/null +++ b/integrity/templates/default/vhost.conf.erb @@ -0,0 +1,12 @@ + + ServerName <%= @node[:integrity][:server_name] %> + DocumentRoot <%= @node[:integrity][:path] %>/public + ErrorLog <%= @node[:integrity][:path] %>/log/error.log + CustomLog <%= @node[:integrity][:path] %>/log/access.log combined + + /public"> + AllowOverride None + Order allow,deny + Allow from all + + \ No newline at end of file diff --git a/iptables/definitions/iptables_rule.rb b/iptables/definitions/iptables_rule.rb new file mode 100644 index 0000000..5ad59d2 --- /dev/null +++ b/iptables/definitions/iptables_rule.rb @@ -0,0 +1,34 @@ +# +# Cookbook Name:: iptables +# Definition:: iptables_rule +# +# Copyright 2008-2009, Opscode, 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. +# + +define :iptables_rule, :enable => true, :source => nil, :variables => {} do + template_source = params[:source] ? params[:source] : "#{params[:name]}.erb" + + template "/etc/iptables.d/#{params[:name]}" do + source template_source + mode 0644 + variables params[:variables] + notifies :run, resources(:execute => "rebuild-iptables") + if params[:enable] + action :create + else + action :delete + end + end +end diff --git a/iptables/files/default/rebuild-iptables b/iptables/files/default/rebuild-iptables new file mode 100644 index 0000000..fda9873 --- /dev/null +++ b/iptables/files/default/rebuild-iptables @@ -0,0 +1,282 @@ +#!/usr/bin/perl -w +our $ID = q$Id: rebuild-iptables 344 2006-10-04 02:48:30Z digant $; + +# +# rebuild-iptables -- Construct an iptables rules file from fragments. +# +# Written by Russ Allbery +# Adapted by Digant C Kasundra +# Copyright 2005, 2006 Board of Trustees, Leland Stanford Jr. University +# +# Constructs an iptables rules file from the prefix, standard, and suffix +# files in the iptables configuration area, adding any additional modules +# specified in the command line, and prints the resulting iptables rules to +# standard output (suitable for saving into /var/lib/iptables or some other +# appropriate location on the system). + +############################################################################## +# Modules and declarations +############################################################################## + +require 5.006; +use strict; + +use Getopt::Long qw(GetOptions); + +# Path to the iptables template area. +our $TEMPLATE = '/etc/iptables.d'; + +############################################################################## +# Installation +############################################################################## + +# Return the prefix +sub prefix { + my $data; + ( $data = <<'END_OF_PREFIX' ) =~ s/^\s+//gm; + *filter + :INPUT ACCEPT + :FORWARD ACCEPT + :OUTPUT ACCEPT + # :FWR - + # -A INPUT -j FWR + # -A FWR -i lo -j ACCEPT +END_OF_PREFIX + + return $data; +} + +# Return the suffix +sub suffix { + my $data; + ( $data = <<'END_OF_SUFFIX' ) =~ s/^\s+//gm; + # Rejects all remaining connections with port-unreachable errors. + + # -A FWR -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN -j REJECT --reject-with icmp-port-unreachable + # -A FWR -p udp -j REJECT --reject-with icmp-port-unreachable + COMMIT +END_OF_SUFFIX + + return $data; +} + +sub snat { + my $data = ""; + if ( -f "/etc/iptables.snat" ) { + open( SNAT, "<", "/etc/iptables.snat" ) + or die "$0: cannot open /etc/iptables.snat: $!\n"; + while () { + $data = $data . $_; + } + close(SNAT); + } + return $data; +} + +# Read in a file, processing includes as required. Returns the contents of +# the file as an array. +sub read_iptables { + my ($file) = @_; + my @data; + $file = $TEMPLATE . '/' . $file unless $file =~ m%^\.?/%; + local *MODULE; + open( MODULE, '<', $file ) or die "$0: cannot open $file: $!\n"; + local $_; + while () { + if (/^\s*include\s+(\S+)$/) { + my $included = $1; + $included = $TEMPLATE . '/' . $included + unless $included =~ m%^\.?/%; + if ( $file eq $included ) { + die "$0: include loop in $file, line $.\n"; + } + push( @data, "\n" ); + push( @data, read_iptables($included) ); + push( @data, "\n" ); + } elsif (/^\s*include\s/) { + die "$0: malformed include line in $file, line $.\n"; + } else { + push( @data, $_ ); + } + } + close MODULE; + return @data; +} + +# Write a file carefully. +sub write_iptables { + my ( $file, @data ) = @_; + open( NEW, "> $file.new" ) or die "$0: cannot create $file.new: $!\n"; + print NEW @data or die "$0: cannot write to $file.new: $!\n"; + close NEW or die "$0: cannot flush $file.new: $!\n"; + rename( "$file.new", $file ) + or die "$0: cannot install new $file: $!\n"; +} + +# Install iptables on a Red Hat system. Takes the array containing the new +# iptables data. +sub install_redhat { + my (@data) = @_; + write_iptables( '/etc/sysconfig/iptables', @data ); + system( "/sbin/service", "iptables", "restart" ); +} + +# Install iptables on a Debian system. Take the array containing the new +# iptables data. +sub install_debian { + my (@data) = @_; + unless ( -d '/etc/iptables' ) { + mkdir( '/etc/iptables', 0755 ) + or die "$0: cannot mkdir /etc/iptables: $!\n"; + } + write_iptables( "/etc/iptables/general", @data ); + system("/sbin/iptables-restore < /etc/iptables/general"); +} + +############################################################################## +# Main routine +############################################################################## + +# Fix things up for error reporting. +$| = 1; +my $fullpath = $0; +$0 =~ s%.*/%%; + +# Parse command-line options. +my ( $help, $version ); +Getopt::Long::config( 'bundling', 'no_ignore_case' ); +GetOptions( + 'h|help' => \$help, + 'v|version' => \$version +) or exit 1; +if ($help) { + print "Feeding myself to perldoc, please wait....\n"; + exec( 'perldoc', '-t', $fullpath ); +} elsif ($version) { + my $version = join( ' ', ( split( ' ', $ID ) )[ 1 .. 3 ] ); + $version =~ s/,v\b//; + $version =~ s/(\S+)$/($1)/; + $version =~ tr%/%-%; + print $version, "\n"; + exit; +} +my @modules; + +if ( -d '/etc/iptables.d' ) { + @modules = ; +} + +# Concatenate everything together. +my @data; +push( @data, prefix() ); +push( @data, "\n" ); +for my $module (@modules) { + push( @data, read_iptables($module) ); + push( @data, "\n" ); +} +push( @data, suffix() ); +push( @data, snat() ); + +if ( -f '/etc/debian_version' ) { + install_debian(@data); +} elsif ( -f '/etc/redhat-release' ) { + install_redhat(@data); +} else { + die "$0: cannot figure out whether this is Red Hat or Debian\n"; +} + +exit 0; +__END__ + +############################################################################## +# Documentation +############################################################################## + +=head1 NAME + +rebuild-iptables - Construct an iptables rules file from fragments + +=head1 SYNOPSIS + +rebuild-iptables [B<-hv>] + +=head1 DESCRIPTION + +B constructs an iptables configuration file by concatenating +various modules found in F. The resulting iptables +configuration file is written to the appropriate file for either Red Hat or +Debian (determined automatically) and iptables is restarted. + +Each module is just a text file located in the directory mentioned above that +contains one or more iptables configuration lines (basically the arguments to +an B invocation), possibly including comments. + +Along with the modules in the directory specified, a standard prefix and suffix +is added. + +Normally, the contents of each module are read in verbatim, but a module may +also contain the directive: + + include + +on a separate line, where is the path to another module to include, +specified the same way as modules given on the command line (hence, either a +file name relative to F or an +absolute path). Such a line will be replaced with the contents of the named +file. Be careful when using this directive to not create loops; files +including themselves will be detected, but more complex loops will not and +will result in infinite output. + +=head1 OPTIONS + +=over 4 + +=item B<-h>, B<--help> + +Print out this documentation (which is done simply by feeding the script to +C). + +=item B<-v>, B<--version> + +Print out the version of B and exit. + +=back + +=head1 FILES + +=over 4 + +=item F + +The default module location. + +=item F + +If this file exists, the system is assumed to be a Debian system for +determining the installation location when B<-i> is used. + +=item F + +The install location of the generated configuration file on Debian. + +=item F + +If this file exists, the system is assumed to be a Red Hat system for +determining the installation location when B<-i> is used. + +=item F + +The install location of the generated configuration file on Red Hat. + +=back + +=head1 AUTHOR + +Russ Allbery +Digant C Kasundra + +=head1 SEE ALSO + +iptables(8) + +=cut diff --git a/iptables/metadata.json b/iptables/metadata.json new file mode 100644 index 0000000..b351efb --- /dev/null +++ b/iptables/metadata.json @@ -0,0 +1,49 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Sets up iptables to use a script to maintain rules", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "iptables": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "centos": [ + + ], + "debian": [ + + ], + "redhat": [ + + ] + }, + "version": "0.7.0", + "name": "iptables", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "iptables": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/iptables/metadata.rb b/iptables/metadata.rb new file mode 100644 index 0000000..9166b0d --- /dev/null +++ b/iptables/metadata.rb @@ -0,0 +1,9 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Sets up iptables to use a script to maintain rules" +version "0.7" + +%w{ redhat centos debian ubuntu}.each do |os| + supports os +end diff --git a/iptables/recipes/default.rb b/iptables/recipes/default.rb new file mode 100644 index 0000000..477ac46 --- /dev/null +++ b/iptables/recipes/default.rb @@ -0,0 +1,36 @@ +# +# Cookbook Name:: iptables +# Recipe:: default +# +# Copyright 2008-2009, Opscode, 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 "iptables" + +execute "rebuild-iptables" do + command "/usr/sbin/rebuild-iptables" + action :nothing +end + +directory "/etc/iptables.d" do + action :create +end + +remote_file "/usr/sbin/rebuild-iptables" do + source "rebuild-iptables" + mode 0755 +end + +iptables_rule "restrictive" diff --git a/iptables/templates/default/restrictive.erb b/iptables/templates/default/restrictive.erb new file mode 100644 index 0000000..88fa22e --- /dev/null +++ b/iptables/templates/default/restrictive.erb @@ -0,0 +1,14 @@ +# Very restricted, only accepts 22, 80, 443 and loopback +-A INPUT -i lo -j ACCEPT +-A OUTPUT -o lo -j ACCEPT +-A OUTPUT -p udp -o eth0 --dport 53 --sport 1024:65535 -j ACCEPT +-A INPUT -p udp -i eth0 --sport 53 --dport 1024:65535 -j ACCEPT +-A OUTPUT -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT +-A INPUT -p tcp -i eth0 --dport 22 --sport 1024:65535 -m state --state NEW -j ACCEPT +-A INPUT -p tcp -i eth0 --dport 80 --sport 1024:65535 -m state --state NEW -j ACCEPT +-A OUTPUT -j ACCEPT -m state --state NEW,ESTABLISHED,RELATED -o eth0 -p tcp -m multiport --dport 80,443 -m multiport --sport 1024:65535 +-A INPUT -j ACCEPT -m state --state ESTABLISHED,RELATED -i eth0 -p tcp +-A INPUT -j DROP +-A OUTPUT -j DROP +-A FORWARD -j DROP + diff --git a/java/README.rdoc b/java/README.rdoc new file mode 100644 index 0000000..8e9d148 --- /dev/null +++ b/java/README.rdoc @@ -0,0 +1,29 @@ += DESCRIPTION: + +Installs Java and Ant. + += REQUIREMENTS: + +Platform: Ubuntu, Debian, Red Hat, CentOS, Fedora. + +Enable the 'multiverse' repository on Ubuntu, 'non-free' on Debian or EPEL on RH/Cent/Fedora to get the Java package, or edit the default recipe to point at the Java package for your platform. + += USAGE: + +Simply include the recipe where you want Java installed. Note the respository requirement above to get the right package. On Debian and Ubuntu systems, the recipe will preseed the package and update java alternaties. + += LICENSE and AUTHOR: + +Copyright 2008-2010, Opscode, 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/java/files/default/java.seed b/java/files/default/java.seed new file mode 100644 index 0000000..bf44093 --- /dev/null +++ b/java/files/default/java.seed @@ -0,0 +1,11 @@ +sun-java6-bin shared/accepted-sun-dlj-v1-1 boolean true +sun-java6-jdk shared/accepted-sun-dlj-v1-1 boolean true +sun-java6-jre shared/accepted-sun-dlj-v1-1 boolean true +sun-java6-jre sun-java6-jre/stopthread boolean true +sun-java6-jre sun-java6-jre/jcepolicy note +sun-java6-bin shared/error-sun-dlj-v1-1 error +sun-java6-jdk shared/error-sun-dlj-v1-1 error +sun-java6-jre shared/error-sun-dlj-v1-1 error +sun-java6-bin shared/present-sun-dlj-v1-1 note +sun-java6-jdk shared/present-sun-dlj-v1-1 note +sun-java6-jre shared/present-sun-dlj-v1-1 note \ No newline at end of file diff --git a/java/metadata.json b/java/metadata.json new file mode 100644 index 0000000..0321b3b --- /dev/null +++ b/java/metadata.json @@ -0,0 +1,43 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs java", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "java": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "debian": [ + + ] + }, + "version": "0.7.0", + "name": "java", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "java": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/java/metadata.rb b/java/metadata.rb new file mode 100644 index 0000000..6e2ccd0 --- /dev/null +++ b/java/metadata.rb @@ -0,0 +1,10 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs java" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.9" + +%w{ debian ubuntu }.each do |os| + supports os +end diff --git a/java/recipes/default.rb b/java/recipes/default.rb new file mode 100644 index 0000000..2b47eae --- /dev/null +++ b/java/recipes/default.rb @@ -0,0 +1,45 @@ +# +# Cookbook Name:: java +# Recipe:: default +# +# Copyright 2008-2009, Opscode, 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. +# + +java_pkg = value_for_platform( + [ "ubuntu", "debian" ] => { + "default" => "sun-java6-jdk" + }, + [ "redhat", "centos", "fedora" ] => { + "default" => "java-1.6.0-openjdk" + }, + "default" => "sun-java6-jdk" +) + +execute "update-java-alternatives" do + command "update-java-alternatives -s java-6-sun --jre" + only_if do platform?("ubuntu", "debian") end + ignore_failure true + action :nothing +end + +package java_pkg do + action :install + if platform?("ubuntu", "debian") + response_file "java.seed" + notifies :run, resources(:execute => "update-java-alternatives"), :immediately + end +end + +package "ant" diff --git a/jira/attributes/jira.rb b/jira/attributes/jira.rb new file mode 100644 index 0000000..7e86b26 --- /dev/null +++ b/jira/attributes/jira.rb @@ -0,0 +1,29 @@ +# +# Cookbook Name:: jira +# Attributes:: jira +# +# Copyright 2008-2009, Opscode, 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. +# + +set_unless[:jira][:virtual_host_name] = "jira.#{domain}" +set_unless[:jira][:virtual_host_alias] = "jira.#{domain}" +# type-version-standalone +set_unless[:jira][:version] = "enterprise-3.13.1" +set_unless[:jira][:install_path] = "/srv/jira" +set_unless[:jira][:run_user] = "www-data" +set_unless[:jira][:database] = "mysql" +set_unless[:jira][:database_host] = "localhost" +set_unless[:jira][:database_user] = "jira" +set_unless[:jira][:database_password] = "change_me" diff --git a/jira/files/default/catalina.sh b/jira/files/default/catalina.sh new file mode 100644 index 0000000..c8ff1e6 --- /dev/null +++ b/jira/files/default/catalina.sh @@ -0,0 +1,323 @@ +#!/bin/sh +# ----------------------------------------------------------------------------- +# Start/Stop Script for the CATALINA Server +# +# Environment Variable Prequisites +# +# CATALINA_HOME May point at your Catalina "build" directory. +# +# CATALINA_BASE (Optional) Base directory for resolving dynamic portions +# of a Catalina installation. If not present, resolves to +# the same directory that CATALINA_HOME points to. +# +# CATALINA_OPTS (Optional) Java runtime options used when the "start", +# "stop", or "run" command is executed. +# +# CATALINA_TMPDIR (Optional) Directory path location of temporary directory +# the JVM should use (java.io.tmpdir). Defaults to +# $CATALINA_BASE/temp. +# +# JAVA_HOME Must point at your Java Development Kit installation. +# Required to run the with the "debug" or "javac" argument. +# +# JRE_HOME Must point at your Java Development Kit installation. +# Defaults to JAVA_HOME if empty. +# +# JAVA_OPTS (Optional) Java runtime options used when the "start", +# "stop", or "run" command is executed. +# +# JPDA_TRANSPORT (Optional) JPDA transport used when the "jpda start" +# command is executed. The default is "dt_socket". +# +# JPDA_ADDRESS (Optional) Java runtime options used when the "jpda start" +# command is executed. The default is 8000. +# +# JSSE_HOME (Optional) May point at your Java Secure Sockets Extension +# (JSSE) installation, whose JAR files will be added to the +# system class path used to start Tomcat. +# +# CATALINA_PID (Optional) Path of the file which should contains the pid +# of catalina startup java process, when start (fork) is used +# +# $Id: catalina.sh 394120 2006-04-14 15:25:07Z yoavs $ +# ----------------------------------------------------------------------------- + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false +os400=false +darwin=false +case "`uname`" in +CYGWIN*) cygwin=true;; +OS400*) os400=true;; +Darwin*) darwin=true;; +esac + +# resolve links - $0 may be a softlink +PRG="$0" + +while [ -h "$PRG" ]; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`/"$link" + fi +done + +# Get standard environment variables +PRGDIR=`dirname "$PRG"` + +# Only set CATALINA_HOME if not already set +[ -z "$CATALINA_HOME" ] && CATALINA_HOME=`cd "$PRGDIR/.." ; pwd` + +if [ -r "$CATALINA_HOME"/bin/setenv.sh ]; then + . "$CATALINA_HOME"/bin/setenv.sh +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$JRE_HOME" ] && JRE_HOME=`cygpath --unix "$JRE_HOME"` + [ -n "$CATALINA_HOME" ] && CATALINA_HOME=`cygpath --unix "$CATALINA_HOME"` + [ -n "$CATALINA_BASE" ] && CATALINA_BASE=`cygpath --unix "$CATALINA_BASE"` + [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --unix "$CLASSPATH"` + [ -n "$JSSE_HOME" ] && JSSE_HOME=`cygpath --absolute --unix "$JSSE_HOME"` +fi + +# For OS400 +if $os400; then + # Set job priority to standard for interactive (interactive - 6) by using + # the interactive priority - 6, the helper threads that respond to requests + # will be running at the same priority as interactive jobs. + COMMAND='chgjob job('$JOBNAME') runpty(6)' + system $COMMAND + + # Enable multi threading + export QIBM_MULTI_THREADED=Y +fi + +# Get standard Java environment variables +if $os400; then + # -r will Only work on the os400 if the files are: + # 1. owned by the user + # 2. owned by the PRIMARY group of the user + # this will not work if the user belongs in secondary groups + BASEDIR="$CATALINA_HOME" + . "$CATALINA_HOME"/bin/setclasspath.sh +else + if [ -r "$CATALINA_HOME"/bin/setclasspath.sh ]; then + BASEDIR="$CATALINA_HOME" + . "$CATALINA_HOME"/bin/setclasspath.sh + else + echo "Cannot find $CATALINA_HOME/bin/setclasspath.sh" + echo "This file is needed to run this program" + exit 1 + fi +fi + +# Add on extra jar files to CLASSPATH +if [ -n "$JSSE_HOME" ]; then + CLASSPATH="$CLASSPATH":"$JSSE_HOME"/lib/jcert.jar:"$JSSE_HOME"/lib/jnet.jar:"$JSSE_HOME"/lib/jsse.jar +fi +CLASSPATH="$CLASSPATH":"$CATALINA_HOME"/bin/bootstrap.jar:"$CATALINA_HOME"/bin/commons-logging-api.jar + +if [ -z "$CATALINA_BASE" ] ; then + CATALINA_BASE="$CATALINA_HOME" +fi + +if [ -z "$CATALINA_TMPDIR" ] ; then + # Define the java.io.tmpdir to use for Catalina + CATALINA_TMPDIR="$CATALINA_BASE"/temp +fi + +# Bugzilla 37848: When no TTY is available, don't output to console +have_tty=0 +if [ "`tty`" != "not a tty" ]; then + have_tty=1 +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + JAVA_HOME=`cygpath --absolute --windows "$JAVA_HOME"` + JRE_HOME=`cygpath --absolute --windows "$JRE_HOME"` + CATALINA_HOME=`cygpath --absolute --windows "$CATALINA_HOME"` + CATALINA_BASE=`cygpath --absolute --windows "$CATALINA_BASE"` + CATALINA_TMPDIR=`cygpath --absolute --windows "$CATALINA_TMPDIR"` + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$JSSE_HOME" ] && JSSE_HOME=`cygpath --absolute --windows "$JSSE_HOME"` + JAVA_ENDORSED_DIRS=`cygpath --path --windows "$JAVA_ENDORSED_DIRS"` +fi + +# Set juli LogManager if it is present +if [ -r "$CATALINA_HOME"/bin/tomcat-juli.jar ]; then + JAVA_OPTS="$JAVA_OPTS "-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager" "-Djava.util.logging.config.file="$CATALINA_BASE/conf/logging.properties" +fi + +# ----- Execute The Requested Command ----------------------------------------- + +# Bugzilla 37848: only output this if we have a TTY +if [ $have_tty -eq 1 ]; then + echo "Using CATALINA_BASE: $CATALINA_BASE" + echo "Using CATALINA_HOME: $CATALINA_HOME" + echo "Using CATALINA_TMPDIR: $CATALINA_TMPDIR" + if [ "$1" = "debug" -o "$1" = "javac" ] ; then + echo "Using JAVA_HOME: $JAVA_HOME" + else + echo "Using JRE_HOME: $JRE_HOME" + fi +fi + +if [ "$1" = "jpda" ] ; then + if [ -z "$JPDA_TRANSPORT" ]; then + JPDA_TRANSPORT="dt_socket" + fi + if [ -z "$JPDA_ADDRESS" ]; then + JPDA_ADDRESS="8000" + fi + if [ -z "$JPDA_OPTS" ]; then + JPDA_OPTS="-Xdebug -Xrunjdwp:transport=$JPDA_TRANSPORT,address=$JPDA_ADDRESS,server=y,suspend=n" + fi + CATALINA_OPTS="$CATALINA_OPTS $JPDA_OPTS" + shift +fi + +if [ "$1" = "debug" ] ; then + if $os400; then + echo "Debug command not available on OS400" + exit 1 + else + shift + if [ "$1" = "-security" ] ; then + echo "Using Security Manager" + shift + exec "$_RUNJDB" $JAVA_OPTS $CATALINA_OPTS \ + -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \ + -sourcepath "$CATALINA_HOME"/../../jakarta-tomcat-catalina/catalina/src/share \ + -Djava.security.manager \ + -Djava.security.policy=="$CATALINA_BASE"/conf/catalina.policy \ + -Dcatalina.base="$CATALINA_BASE" \ + -Dcatalina.home="$CATALINA_HOME" \ + -Djava.io.tmpdir="$CATALINA_TMPDIR" \ + org.apache.catalina.startup.Bootstrap "$@" start + else + exec "$_RUNJDB" $JAVA_OPTS $CATALINA_OPTS \ + -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \ + -sourcepath "$CATALINA_HOME"/../../jakarta-tomcat-catalina/catalina/src/share \ + -Dcatalina.base="$CATALINA_BASE" \ + -Dcatalina.home="$CATALINA_HOME" \ + -Djava.io.tmpdir="$CATALINA_TMPDIR" \ + org.apache.catalina.startup.Bootstrap "$@" start + fi + fi + +elif [ "$1" = "run" ]; then + + shift + if [ "$1" = "-security" ] ; then + echo "Using Security Manager" + shift + exec "$_RUNJAVA" $JAVA_OPTS $CATALINA_OPTS \ + -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \ + -Djava.security.manager \ + -Djava.security.policy=="$CATALINA_BASE"/conf/catalina.policy \ + -Dcatalina.base="$CATALINA_BASE" \ + -Dcatalina.home="$CATALINA_HOME" \ + -Djava.io.tmpdir="$CATALINA_TMPDIR" \ + org.apache.catalina.startup.Bootstrap "$@" start + else + exec "$_RUNJAVA" $JAVA_OPTS $CATALINA_OPTS \ + -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \ + -Dcatalina.base="$CATALINA_BASE" \ + -Dcatalina.home="$CATALINA_HOME" \ + -Djava.io.tmpdir="$CATALINA_TMPDIR" \ + org.apache.catalina.startup.Bootstrap "$@" start + fi + +elif [ "$1" = "start" ] ; then + + shift + touch "$CATALINA_BASE"/logs/catalina.out + if [ "$1" = "-security" ] ; then + echo "Using Security Manager" + shift + "$_RUNJAVA" $JAVA_OPTS $CATALINA_OPTS \ + -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \ + -Djava.security.manager \ + -Djava.security.policy=="$CATALINA_BASE"/conf/catalina.policy \ + -Dcatalina.base="$CATALINA_BASE" \ + -Dcatalina.home="$CATALINA_HOME" \ + -Djava.io.tmpdir="$CATALINA_TMPDIR" \ + org.apache.catalina.startup.Bootstrap "$@" start \ + >> "$CATALINA_BASE"/logs/catalina.out 2>&1 & + + if [ ! -z "$CATALINA_PID" ]; then + echo $! > $CATALINA_PID + fi + else + "$_RUNJAVA" $JAVA_OPTS $CATALINA_OPTS \ + -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \ + -Dcatalina.base="$CATALINA_BASE" \ + -Dcatalina.home="$CATALINA_HOME" \ + -Djava.io.tmpdir="$CATALINA_TMPDIR" \ + org.apache.catalina.startup.Bootstrap "$@" start \ + >> "$CATALINA_BASE"/logs/catalina.out 2>&1 & + + if [ ! -z "$CATALINA_PID" ]; then + echo $! > $CATALINA_PID + fi + fi + +elif [ "$1" = "stop" ] ; then + + shift + FORCE=0 + if [ "$1" = "-force" ]; then + shift + FORCE=1 + fi + + "$_RUNJAVA" $JAVA_OPTS $CATALINA_OPTS \ + -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \ + -Dcatalina.base="$CATALINA_BASE" \ + -Dcatalina.home="$CATALINA_HOME" \ + -Djava.io.tmpdir="$CATALINA_TMPDIR" \ + org.apache.catalina.startup.Bootstrap "$@" stop + + if [ $FORCE -eq 1 ]; then + if [ ! -z "$CATALINA_PID" ]; then + echo "Killing: `cat $CATALINA_PID`" + kill -9 `cat $CATALINA_PID` + else + echo "Kill failed: \$CATALINA_PID not set" + fi + fi + +elif [ "$1" = "version" ] ; then + + "$_RUNJAVA" \ + -classpath "$CATALINA_HOME/server/lib/catalina.jar" \ + org.apache.catalina.util.ServerInfo + +else + + echo "Usage: catalina.sh ( commands ... )" + echo "commands:" + if $os400; then + echo " debug Start Catalina in a debugger (not available on OS400)" + echo " debug -security Debug Catalina with a security manager (not available on OS400)" + else + echo " debug Start Catalina in a debugger" + echo " debug -security Debug Catalina with a security manager" + fi + echo " jpda start Start Catalina under JPDA debugger" + echo " run Start Catalina in the current window" + echo " run -security Start in the current window with security manager" + echo " start Start Catalina in a separate window" + echo " start -security Start in a separate window with security manager" + echo " stop Stop Catalina" + echo " stop -force Stop Catalina (followed by kill -KILL)" + echo " version What version of tomcat are you running?" + exit 1 + +fi diff --git a/jira/files/default/startup.sh b/jira/files/default/startup.sh new file mode 100644 index 0000000..d2f2819 --- /dev/null +++ b/jira/files/default/startup.sh @@ -0,0 +1,48 @@ +#!/bin/sh +# ----------------------------------------------------------------------------- +# Start Script for the CATALINA Server +# +# $Id: startup.sh 385888 2006-03-14 21:04:40Z keith $ +# ----------------------------------------------------------------------------- + +# Better OS/400 detection: see Bugzilla 31132 +os400=false +darwin=false +case "`uname`" in +CYGWIN*) cygwin=true;; +OS400*) os400=true;; +Darwin*) darwin=true;; +esac + +# resolve links - $0 may be a softlink +PRG="$0" + +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`/"$link" + fi +done + +PRGDIR=`dirname "$PRG"` +EXECUTABLE=catalina.sh + +# Check that target executable exists +if $os400; then + # -x will Only work on the os400 if the files are: + # 1. owned by the user + # 2. owned by the PRIMARY group of the user + # this will not work if the user belongs in secondary groups + eval +else + if [ ! -x "$PRGDIR"/"$EXECUTABLE" ]; then + echo "Cannot find $PRGDIR/$EXECUTABLE" + echo "This file is needed to run this program" + exit 1 + fi +fi + +exec "$PRGDIR"/"$EXECUTABLE" run "$@" diff --git a/jira/metadata.json b/jira/metadata.json new file mode 100644 index 0000000..60d52d5 --- /dev/null +++ b/jira/metadata.json @@ -0,0 +1,161 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs and configures jira", + "recommendations": { + "mysql": [ + + ] + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "jira": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "debian": [ + + ] + }, + "version": "0.7.0", + "name": "jira", + "conflicting": { + + }, + "attributes": { + "jira\/database_host": { + "default": "localhost", + "type": "string", + "multiple_values": false, + "description": "Hostname of the database server", + "display_name": "Jira Database Host", + "recipes": [ + + ], + "required": false + }, + "jira\/run_user": { + "default": "www-data", + "type": "string", + "multiple_values": false, + "description": "User the Jira instance should run as", + "display_name": "Jira Run User", + "recipes": [ + + ], + "required": false + }, + "jira\/version": { + "default": "enterprise-3.13.1", + "type": "string", + "multiple_values": false, + "description": "Version of Jira to download and install", + "display_name": "Jira Version", + "recipes": [ + + ], + "required": false + }, + "jira\/virtual_host_name": { + "default": "jira.domain", + "type": "string", + "multiple_values": false, + "description": "Apache ServerName for Jira virtual host", + "display_name": "Jira Virtual Hostname", + "recipes": [ + + ], + "required": false + }, + "jira\/install_path": { + "default": "\/srv\/jira", + "type": "string", + "multiple_values": false, + "description": "Filesystem location for Jira", + "display_name": "Jira Install Path", + "recipes": [ + + ], + "required": false + }, + "jira": { + "type": "hash", + "multiple_values": false, + "description": "Hash of Jira attributes", + "display_name": "Jira", + "recipes": [ + + ], + "required": false + }, + "jira\/database": { + "default": "mysql", + "type": "string", + "multiple_values": false, + "description": "Type of database Jira should use", + "display_name": "Jira Database", + "recipes": [ + + ], + "required": false + }, + "jira\/database_user": { + "default": "jira", + "type": "string", + "multiple_values": false, + "description": "Name of the database user for Jira", + "display_name": "Jira Database User", + "recipes": [ + + ], + "required": false + }, + "jira\/virtual_host_alias": { + "default": "jira", + "type": "string", + "multiple_values": false, + "description": "Apache ServerAlias for Jira virtual host", + "display_name": "Jira Virtual Hostalias", + "recipes": [ + + ], + "required": false + }, + "jira\/database_password": { + "default": "change_me", + "type": "string", + "multiple_values": false, + "description": "Password for the Jira Database User", + "display_name": "Jira Database Password", + "recipes": [ + + ], + "required": false + } + }, + "providing": { + "jira": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + "java": [ + + ], + "runit": [ + + ], + "apache2": [ + + ] + } +} \ No newline at end of file diff --git a/jira/metadata.rb b/jira/metadata.rb new file mode 100644 index 0000000..743f27d --- /dev/null +++ b/jira/metadata.rb @@ -0,0 +1,64 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs and configures jira" +version "0.7" +recommends "mysql" + +%w{ ubuntu debian }.each do |os| + supports os +end + +%w{ runit java apache2 }.each do |cb| + depends cb +end + +attribute "jira", + :display_name => "Jira", + :description => "Hash of Jira attributes", + :type => "hash" + +attribute "jira/virtual_host_name", + :display_name => "Jira Virtual Hostname", + :description => "Apache ServerName for Jira virtual host", + :default => "jira.domain" + +attribute "jira/virtual_host_alias", + :display_name => "Jira Virtual Hostalias", + :description => "Apache ServerAlias for Jira virtual host", + :default => "jira" + +attribute "jira/version", + :display_name => "Jira Version", + :description => "Version of Jira to download and install", + :default => "enterprise-3.13.1" + +attribute "jira/install_path", + :display_name => "Jira Install Path", + :description => "Filesystem location for Jira", + :default => "/srv/jira" + +attribute "jira/run_user", + :display_name => "Jira Run User", + :description => "User the Jira instance should run as", + :default => "www-data" + +attribute "jira/database", + :display_name => "Jira Database", + :description => "Type of database Jira should use", + :default => "mysql" + +attribute "jira/database_host", + :display_name => "Jira Database Host", + :description => "Hostname of the database server", + :default => "localhost" + +attribute "jira/database_user", + :display_name => "Jira Database User", + :description => "Name of the database user for Jira", + :default => "jira" + +attribute "jira/database_password", + :display_name => "Jira Database Password", + :description => "Password for the Jira Database User", + :default => "change_me" diff --git a/jira/recipes/default.rb b/jira/recipes/default.rb new file mode 100644 index 0000000..13db573 --- /dev/null +++ b/jira/recipes/default.rb @@ -0,0 +1,99 @@ +# +# Cookbook Name:: jira +# Recipe:: default +# +# Copyright 2008-2009, Opscode, 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. +# + +# +# Manual Steps! +# +# MySQL: +# +# create database jiradb character set utf8; +# grant all privileges on jiradb.* to '$jira_user'@'localhost' identified by '$jira_password'; +# flush privileges; + +include_recipe "runit" +include_recipe "java" +include_recipe "apache2" +include_recipe "apache2::mod_rewrite" +include_recipe "apache2::mod_proxy" +include_recipe "apache2::mod_proxy_http" +include_recipe "apache2::mod_ssl" + +unless FileTest.exists?(node[:jira][:install_path]) + remote_file "jira" do + path "/tmp/jira.tar.gz" + source "http://www.atlassian.com/software/jira/downloads/binary/atlassian-jira-#{node[:jira][:version]}-standalone.tar.gz" + end + + bash "untar-jira" do + code "(cd /tmp; tar zxvf /tmp/jira.tar.gz)" + end + + bash "install-jira" do + code "mv /tmp/atlassian-jira-#{node[:jira][:version]}-standalone #{node[:jira][:install_path]}" + end + + if node[:jira][:database] == "mysql" + remote_file "mysql-connector" do + path "/tmp/mysql-connector.tar.gz" + source "http://downloads.mysql.com/archives/mysql-connector-java-5.1/mysql-connector-java-5.1.6.tar.gz" + end + + bash "untar-mysql-connector" do + code "(cd /tmp; tar zxvf /tmp/mysql-connector.tar.gz)" + end + + bash "install-mysql-connector" do + code "cp /tmp/mysql-connector-java-5.1.6/mysql-connector-java-5.1.6-bin.jar #{node[:jira][:install_path]}/common/lib" + end + end +end + +directory "#{node[:jira][:install_path]}" do + recursive true + owner "www-data" +end + +remote_file "#{node[:jira][:install_path]}/bin/startup.sh" do + source "startup.sh" + mode 0755 +end + +remote_file "#{node[:jira][:install_path]}/bin/catalina.sh" do + source "catalina.sh" + mode 0755 +end + +template "#{node[:jira][:install_path]}/conf/server.xml" do + source "server.xml.erb" + mode 0755 +end + +template "#{node[:jira][:install_path]}/atlassian-jira/WEB-INF/classes/entityengine.xml" do + source "entityengine.xml.erb" + mode 0755 +end + +runit_service "jira" + +template "#{node[:apache][:dir]}/sites-available/jira.conf" do + source "apache.conf.erb" + mode 0644 +end + +apache_site "jira.conf" diff --git a/jira/templates/default/apache.conf.erb b/jira/templates/default/apache.conf.erb new file mode 100644 index 0000000..1f472f4 --- /dev/null +++ b/jira/templates/default/apache.conf.erb @@ -0,0 +1,32 @@ + + DocumentRoot <%= @node[:jira][:install_path] %> + ServerAdmin ops@<%= @node[:domain] %> + <% if @node[:jira][:virtual_host_name] -%> + ServerName <%= @node[:jira][:virtual_host_name] %> + <% end -%> + <% if @node[:jira][:virtual_host_alias] -%> + <% va_list = @node[:jira][:virtual_host_alias].kind_of?(Array) ? @node[:jira][:virtual_host_alias] : [ @node[:jira][:virtual_host_alias] ] -%> + <% va_list.each do |va| -%> + ServerAlias <%= va %> + <% end -%> + <% end -%> + + ErrorLog <%= @node[:apache][:log_dir] %>/jira-error.log + TransferLog <%= @node[:apache][:log_dir] %>/jira-access.log + RewriteEngine On + RewriteLog <%= @node[:apache][:log_dir] %>/jira-rewrite.log + RewriteLogLevel 0 + + + Order deny,allow + Allow from all + + + ProxyRequests Off + ProxyPreserveHost On + + RewriteEngine On + + RewriteRule ^/(.*)$ http://127.0.0.1:8080/$1 [P,QSA,L] + ProxyPassReverse / http://127.0.0.1:8080 + diff --git a/jira/templates/default/entityengine.xml.erb b/jira/templates/default/entityengine.xml.erb new file mode 100644 index 0000000..3dd6635 --- /dev/null +++ b/jira/templates/default/entityengine.xml.erb @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jira/templates/default/server.xml.erb b/jira/templates/default/server.xml.erb new file mode 100644 index 0000000..b8704f7 --- /dev/null +++ b/jira/templates/default/server.xml.erb @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jira/templates/default/sv-jira-log-run.erb b/jira/templates/default/sv-jira-log-run.erb new file mode 100644 index 0000000..e51ae7e --- /dev/null +++ b/jira/templates/default/sv-jira-log-run.erb @@ -0,0 +1,3 @@ +#!/bin/sh +umask 0027 +exec svlogd -tt ./main diff --git a/jira/templates/default/sv-jira-run.erb b/jira/templates/default/sv-jira-run.erb new file mode 100644 index 0000000..42cbb5d --- /dev/null +++ b/jira/templates/default/sv-jira-run.erb @@ -0,0 +1,5 @@ +#!/bin/bash + +cd <%= @node[:jira][:install_path] %> +exec 2>&1 +exec chpst -u <%= @node[:jira][:run_user] %> env JAVA_HOME=/usr/lib/jvm/java-6-sun JAVA_OPTS="-Xms256m -Xmx256m" <%= @node[:jira][:install_path] %>/bin/startup.sh diff --git a/keepalived/README.rdoc b/keepalived/README.rdoc new file mode 100644 index 0000000..9226876 --- /dev/null +++ b/keepalived/README.rdoc @@ -0,0 +1,33 @@ += DESCRIPTION: + +Installs keepalived and pushes the configuration file out. + += REQUIREMENTS: + +== Platform: + +Tested on Ubuntu 8.10. + += ATTRIBUTES: + += USAGE: + +Modify the sample template to suit your environment and configuration requirements. + += LICENSE and AUTHOR: + +Author:: Joshua Timberman () + +Copyright:: 2009, Opscode, 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/keepalived/metadata.json b/keepalived/metadata.json new file mode 100644 index 0000000..9caf4a3 --- /dev/null +++ b/keepalived/metadata.json @@ -0,0 +1,40 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs and configures keepalived", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "keepalived": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ] + }, + "version": "0.7.0", + "name": "keepalived", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "keepalived": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "= DESCRIPTION:\n\nInstalls keepalived and pushes the configuration file out.\n\n= REQUIREMENTS:\n\n== Platform:\n\nTested on Ubuntu 8.10.\n\n= ATTRIBUTES: \n\n= USAGE: \n\nModify the sample template to suit your environment and configuration requirements.\n\n= LICENSE and AUTHOR:\n \nAuthor:: Joshua Timberman ()\n\nCopyright:: 2009, Opscode, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http:\/\/www.apache.org\/licenses\/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/keepalived/metadata.rb b/keepalived/metadata.rb new file mode 100644 index 0000000..ce47324 --- /dev/null +++ b/keepalived/metadata.rb @@ -0,0 +1,7 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs and configures keepalived" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.7" +supports "ubuntu" diff --git a/keepalived/recipes/default.rb b/keepalived/recipes/default.rb new file mode 100644 index 0000000..e0404d4 --- /dev/null +++ b/keepalived/recipes/default.rb @@ -0,0 +1,35 @@ +# +# Cookbook Name:: keepalived +# Recipe:: default +# +# Copyright 2009, Opscode, 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 "keepalived" do + action :install +end + +service "keepalived" do + supports :restart => true + action [:enable, :start] +end + +template "/etc/keepalived/keepalived.conf" do + source "keepalived.conf.erb" + owner "root" + group "root" + mode 0644 + notifies :restart, resources(:service => "keepalived") +end diff --git a/keepalived/templates/default/keepalived.conf.erb b/keepalived/templates/default/keepalived.conf.erb new file mode 100644 index 0000000..30d9d98 --- /dev/null +++ b/keepalived/templates/default/keepalived.conf.erb @@ -0,0 +1,48 @@ +! Sample Configuration File for keepalived +! Generated by Chef. + +global_defs { + notification_email { + acassen + } + notification_email_from root@<%= @node[:domain] %> + smtp_server 192.168.200.1 + smtp_connect_timeout 30 + router_id LVS_DEVEL +} + +vrrp_instance VI_1 { + interface eth0 + virtual_router_id 50 + nopreempt + priority 100 + advert_int 1 + virtual_ipaddress { + 192.168.200.11 + 192.168.200.12 + 192.168.200.13 + } +} + +virtual_server 10.10.10.2 1358 { + delay_loop 6 + lb_algo rr + lb_kind NAT + persistence_timeout 50 + protocol TCP + + sorry_server 192.168.200.200 1358 + + real_server 192.168.200.2 1358 { + weight 1 + HTTP_GET { + url { + path /canary + digest 640205b7b0fc66c1ea91c463fac6334d + } + connect_timeout 3 + nb_get_retry 3 + delay_before_retry 3 + } + } +} diff --git a/kickstart/README.rdoc b/kickstart/README.rdoc new file mode 100644 index 0000000..3aed317 --- /dev/null +++ b/kickstart/README.rdoc @@ -0,0 +1,51 @@ += DESCRIPTION: + +Creates an apache vhost and serves a very basic kickstart file. + += REQUIREMENTS: + +Red Hat Enterprise Linux, CentOS, or other platforms that support Kickstart :-). + +Opscode/cookbooks: + +* apache2 + += ATTRIBUTES: + +* kickstart[:rootpw] - set the root password. Use an encrypted string[1]. + +[1] a Ruby way to encrypt: +http://www.opensourcery.co.za/2009/05/01/quick-nix-shadow-passwords-with-ruby/ + += USAGE: + +You'll almost certainly want to edit ks.cfg.erb to suit your environment. As is, the provided template is used as a minimal fast install for creating virtual machines to run CentOS 5. Of particular note, the following should definitely be changed: + +* url - mirrors.kernel.org is usually fast for me, but maybe not for you. +* network - change the hostname. +* rootpw - this is an attribute, so you can change it by modifying the server. Use the encrypted password! + +Storage / disks should probably be customized, as well as firewall rules, SELinux policy, and the package list. + +The %post section will install Chef via Matthew Kent's RPMs, per the Chef Wiki instructions. + +To use the recipe on a system that will be the kickstart server, + + include_recipe "kickstart::server" + += LICENSE and AUTHOR: + +Author:: Joshua Timberman () +Copyright:: 2009, Opscode, 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/kickstart/attributes/kickstart.rb b/kickstart/attributes/kickstart.rb new file mode 100644 index 0000000..fa654db --- /dev/null +++ b/kickstart/attributes/kickstart.rb @@ -0,0 +1,2 @@ +set_unless[:kickstart][:rootpw] = nil +set_unless[:kickstart][:virtual_host_name] = "build.#{domain}" diff --git a/kickstart/metadata.json b/kickstart/metadata.json new file mode 100644 index 0000000..e6627a5 --- /dev/null +++ b/kickstart/metadata.json @@ -0,0 +1,49 @@ +{ + "maintainer": "Opscode", + "description": "Installs\/Configures kickstart", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "kickstart::server": "", + "kickstart": "" + }, + "suggestions": { + + }, + "platforms": { + "centos": [ + + ], + "redhat": [ + + ] + }, + "version": "0.2.0", + "name": "kickstart", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "kickstart::server": [ + + ], + "kickstart": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "= DESCRIPTION:\n\nCreates an apache vhost and serves a very basic kickstart file.\n\n= REQUIREMENTS:\n\nRed Hat Enterprise Linux, CentOS, or other platforms that support Kickstart :-).\n\nOpscode\/cookbooks:\n\n* apache2\n\n= ATTRIBUTES: \n\n* kickstart[:rootpw] - set the root password. Use an encrypted string[1].\n\n[1] a Ruby way to encrypt:\nhttp:\/\/www.opensourcery.co.za\/2009\/05\/01\/quick-nix-shadow-passwords-with-ruby\/\n\n= USAGE:\n\nYou'll almost certainly want to edit ks.cfg.erb to suit your environment. As is, the provided template is used as a minimal fast install for creating virtual machines to run CentOS 5. Of particular note, the following should definitely be changed:\n\n* url - mirrors.kernel.org is usually fast for me, but maybe not for you.\n* network - change the hostname.\n* rootpw - this is an attribute, so you can change it by modifying the server. Use the encrypted password!\n\nStorage \/ disks should probably be customized, as well as firewall rules, SELinux policy, and the package list.\n\nThe %post section will install Chef via Matthew Kent's RPMs, per the Chef Wiki instructions.\n\nTo use the recipe on a system that will be the kickstart server,\n\n include_recipe \"kickstart::server\"\n\n= LICENSE and AUTHOR:\n\nAuthor:: Joshua Timberman ()\nCopyright:: 2009, Opscode, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http:\/\/www.apache.org\/licenses\/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n", + "replacing": { + + }, + "dependencies": { + "apache2": [ + + ] + } +} \ No newline at end of file diff --git a/kickstart/metadata.rb b/kickstart/metadata.rb new file mode 100644 index 0000000..462f871 --- /dev/null +++ b/kickstart/metadata.rb @@ -0,0 +1,9 @@ +maintainer "Opscode" +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs/Configures kickstart" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.2" +depends "apache2" +supports "redhat" +supports "centos" diff --git a/kickstart/recipes/default.rb b/kickstart/recipes/default.rb new file mode 100644 index 0000000..83a2140 --- /dev/null +++ b/kickstart/recipes/default.rb @@ -0,0 +1,18 @@ +# +# Cookbook Name:: kickstart +# Recipe:: default +# +# Copyright 2009, Opscode, 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/kickstart/recipes/server.rb b/kickstart/recipes/server.rb new file mode 100644 index 0000000..47aa583 --- /dev/null +++ b/kickstart/recipes/server.rb @@ -0,0 +1,52 @@ +# +# Cookbook Name:: kickstart +# Recipe:: server +# +# Copyright 2009, Opscode, 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 "apache2" + +directory "/srv/kickstart" do + owner "root" + group "root" + mode "0755" +end + +template "/srv/kickstart/ks.cfg" do + source "ks.cfg.erb" + mode "0644" + owner "root" + group "root" +end + +link "/srv/kickstart/index.html" do + to "/srv/kickstart/ks.cfg" +end + +template "#{node[:apache][:dir]}/sites-available/kickstart.conf" do + source "kickstart.conf.erb" + variables( + :virtual_host_name => node[:kickstart][:virtual_host_name], + :docroot => "/srv/kickstart" + ) + mode "0644" + owner "root" + group "root" +end + +apache_site "kickstart.conf" do + enable true +end + diff --git a/kickstart/templates/default/kickstart.conf.erb b/kickstart/templates/default/kickstart.conf.erb new file mode 100644 index 0000000..a8c8544 --- /dev/null +++ b/kickstart/templates/default/kickstart.conf.erb @@ -0,0 +1,27 @@ + + + DocumentRoot <%= @docroot %> + + ServerName <%= @virtual_host_name %> + ServerAlias <%= @virtual_host_name.split('.')[0] %> + + + Options FollowSymLinks + AllowOverride None + + + LogLevel info + ErrorLog <%= @node[:apache][:log_dir] %>/kickstart-error.log + CustomLog <%= @node[:apache][:log_dir] %>/kickstart-access.log combined + + > + Options Indexes FollowSymLinks MultiViews + AllowOverride All + Order allow,deny + allow from all + + + AddOutputFilterByType DEFLATE text/html text/plain text/xml + + + diff --git a/kickstart/templates/default/ks.cfg.erb b/kickstart/templates/default/ks.cfg.erb new file mode 100644 index 0000000..7a55bc3 --- /dev/null +++ b/kickstart/templates/default/ks.cfg.erb @@ -0,0 +1,250 @@ +# Kickstart file automatically generated by anaconda. + +install +text +reboot +url --url http://mirrors.kernel.org/centos/5.3/os/i386 +lang en_US.UTF-8 +keyboard us +network --device eth0 --bootproto dhcp --hostname centos5test.<%= @node[:domain] %> +rootpw --iscrypted <%= @node[:kickstart][:rootpw] %> +firewall --enabled --port=22:tcp +authconfig --enableshadow --enablemd5 +selinux --permissive +timezone --utc America/Los_Angeles +bootloader --location=mbr --driveorder=sda +# The following is the partition information you requested +# Note that any partitions you deleted are not expressed +# here so unless you clear all partitions first, this is +# not guaranteed to work +ignoredisk --drives=sdb,sdc +clearpart --drives=sda --all +part /boot --fstype ext3 --size=256 --asprimary --ondisk=sda +part pv.01 --grow --size=100 --asprimary --ondisk=sda +volgroup vg0 pv.01 --pesize=32768 +logvol / --fstype ext3 --name=rootlv --vgname=vg0 --size=5120 +logvol swap --fstype swap --name=swaplv --vgname=vg0 --size=512 + + +%packages --nobase +acl +anacron +apr +apr-util +attr +audit +audit-libs +audit-libs-python +authconfig +automake +basesystem +bash +bc +beecrypt +bind-libs +bind-utils +bzip2 +bzip2-libs +centos-release +centos-release-notes +checkpolicy +chkconfig +coreutils +cpio +cracklib +cracklib-dicts +cryptsetup-luks +crontabs +curl +cyrus-sasl +cyrus-sasl-lib +db4 +dbus +dbus-glib +device-mapper +diffutils +dmidecode +dmraid +e2fsprogs +e2fsprogs-libs +ed +eject +elfutils-libelf +ethtool +expat +file +filesystem +findutils +gawk +gcc +gdbm +gettext +git +glib2 +glibc +glibc-common +gnu-efi +gnupg +gpm +grep +groff +grub +gzip +hal +hdparm +hwdata +info +initscripts +iproute +iptables +iptstate +iputils +irqbalance +kbd +kernel +kernel-headers +kpartx +krb5-libs +kudzu +less +libacl +libaio +libattr +libcap +libgcc +libgcrypt +libgpg-error +libidn +libselinux +libselinux-python +libsemanage +libsepol +libstdc++ +libsysfs +libtermcap +libusb +libuser +libutempter +libvolume_id +libxml2 +libxml2-python +logrotate +logwatch +lsof +lvm2 +m2crypto +mailcap +mailx +make +MAKEDEV +man +man-pages +mcstrans +mgetty +microcode_ctl +mingetty +mkinitrd +mktemp +mlocate +module-init-tools +mutt +nash +nc +ncurses +neon +net-tools +newt +ntp +ntsysv +openldap +openssh +openssh-clients +openssh-server +openssl +pam +parted +passwd +pciutils +pcre +perl +perl-URI +pm-utils +policycoreutils +popt +postfix +postgresql-libs +prelink +procps +psacct +psmisc +python +python-elementtree +python-sqlite +python-urlgrabber +quota +readline +redhat-logos +rhpl +rootfiles +rpm +rpm-libs +rpm-python +rsync +ruby +ruby-devel +ruby-irb +ruby-libs +ruby-rdoc +screen +sed +selinux-policy +selinux-policy-targeted +setools +setserial +setup +shadow-utils +slang +sqlite +stunnel +subversion +sudo +sysfsutils +sysklogd +sysstat +SysVinit +tar +tcl +tcpdump +tcp_wrappers +telnet +termcap +time +tmpwatch +traceroute +tzdata +udev +unzip +usbutils +usermode +util-linux +vim-common +vim-enhanced +vim-minimal +vixie-cron +w3m +which +wireless-tools +yum +zip +zlib +-dhcpv6_client +-iptables-ipv6 +-Deployment_Guide-en-US +-system-config-securitylevel-tui + +%pre + +%post +rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-3.noarch.rpm +rpm -Uvh http://download.elff.bravenet.com/5/i386/elff-release-5-3.noarch.rpm +yum install -y rubygem-chef diff --git a/kvm/files/default/kvmtool b/kvm/files/default/kvmtool new file mode 100755 index 0000000..e9bd098 --- /dev/null +++ b/kvm/files/default/kvmtool @@ -0,0 +1,54 @@ +#!/usr/bin/env ruby +require 'rubygems' +require 'thor' +require 'yaml' +class KvmTool < Thor + + desc "list", "More useful list of kvm guests" + def list + @total_allocated_mem = 0 + list = `virsh list --all 2>&1` + lines = list.split("\n")[3..-1] + lines.each do |line| + num, name, state = line.split + info = `virsh dominfo #{name} 2>/dev/null | grep -v Connecting` + infoz = YAML.load(info) + cpu = infoz['CPU(s)'] + memory = infoz["Max memory"].split.first.to_i + @total_allocated_mem += memory + memory_in_gb = memory / 1024 / 1024 + puts "#{num} #{name} #{state} #{cpu} #{memory_in_gb}GB" + end + + puts "Total allocated memory: #{@total_allocated_mem / 1024} MB" + end + + desc "build", "Build a new KVM guest" + method_options :memory => :required, :cpu => :required, :hostname => :required, :ip_address => :required, :root_disk_size => :string + def build + root_disk_size = options[:root_disk_size] || "18G" + volume = options[:hostname].gsub("-", "_") + + puts `lvcreate -n kvm_#{volume} -L #{root_disk_size} VolGroupKVM 2>&1` + command = "vmbuilder kvm ubuntu --suite=intrepid --flavour=virtual --arch=amd64 --hostname=#{options[:hostname]} --mem=#{options[:memory]} --cpus=#{options[:cpu]} \ + --mirror=http://apt/archive-ubuntu/ubuntu --dest=/u/kvm/images/#{options[:hostname]} --tmp=/u/kvm/tmp --rootsize=16384 --swapsize=1024 \ + --bridge=br0 --ip=#{options[:ip_address]} --mask=255.255.252.0 --net=192.168.0.0 --bcast=192.168.3.255 --gw=192.168.1.1 --dns=192.168.2.63 \ + --addpkg=openssh-server --addpkg=acpid --addpkg=sysstat --addpkg=emacs22-nox --addpkg=vim --addpkg=git-core \ + --addpkg=mysql-client --addpkg=libmysqlclient15-dev --addpkg=build-essential --addpkg=syslog-ng --addpkg=ntp \ + --addpkg=curl --addpkg=wget --lang=en_US.UTF-8 \ + --templates=/usr/local/share/kvm/templates \ + --copy=/usr/local/share/kvm/files/manifest.txt \ + --execscript=/usr/local/share/kvm/scripts/postinstall.sh \ + --libvirt=qemu:///system --verbose --debug 2>&1" + puts system(command) + puts "Converting qcow2 image to LVM..." + puts `kvm-img convert /u/kvm/images/#{options[:hostname]}/disk0.qcow2 -O raw /u/kvm/images/#{options[:hostname]}/disk0.raw 2>&1` + puts `dd if=/u/kvm/images/#{options[:hostname]}/disk0.raw of=/dev/mapper/VolGroupKVM-kvm_#{volume} bs=1M 2>&1` + + puts "Cleaning up temporary files/directories..." + puts `rm -rvf /u/kvm/images/#{options[:hostname]}` + + end +end + +KvmTool.start \ No newline at end of file diff --git a/kvm/files/default/modules/2.6.27-11-server/kvm-amd.ko b/kvm/files/default/modules/2.6.27-11-server/kvm-amd.ko new file mode 100755 index 0000000..cd5c446 Binary files /dev/null and b/kvm/files/default/modules/2.6.27-11-server/kvm-amd.ko differ diff --git a/kvm/files/default/modules/2.6.27-11-server/kvm-intel.ko b/kvm/files/default/modules/2.6.27-11-server/kvm-intel.ko new file mode 100755 index 0000000..6a4bad3 Binary files /dev/null and b/kvm/files/default/modules/2.6.27-11-server/kvm-intel.ko differ diff --git a/kvm/files/default/modules/2.6.27-11-server/kvm.ko b/kvm/files/default/modules/2.6.27-11-server/kvm.ko new file mode 100755 index 0000000..c765717 Binary files /dev/null and b/kvm/files/default/modules/2.6.27-11-server/kvm.ko differ diff --git a/kvm/files/default/templates/files/event.d/ttyS0 b/kvm/files/default/templates/files/event.d/ttyS0 new file mode 100755 index 0000000..bc95db2 --- /dev/null +++ b/kvm/files/default/templates/files/event.d/ttyS0 @@ -0,0 +1,16 @@ +# ttyS0 - getty +# +# This service maintains a getty on ttyS0 from the point the system is +# started until it is shut down again. + +start on runlevel 2 +start on runlevel 3 +start on runlevel 4 +start on runlevel 5 + +stop on runlevel 0 +stop on runlevel 1 +stop on runlevel 6 + +respawn +exec /sbin/getty 115200 ttyS0 diff --git a/kvm/files/default/templates/files/manifest.txt b/kvm/files/default/templates/files/manifest.txt new file mode 100755 index 0000000..399c8a2 --- /dev/null +++ b/kvm/files/default/templates/files/manifest.txt @@ -0,0 +1 @@ +/usr/local/share/kvm/files/event.d/ttyS0 /etc/event.d/ttyS0 diff --git a/kvm/files/default/templates/scripts/add-172-net.sh b/kvm/files/default/templates/scripts/add-172-net.sh new file mode 100755 index 0000000..eb2fdbe --- /dev/null +++ b/kvm/files/default/templates/scripts/add-172-net.sh @@ -0,0 +1,16 @@ +#!/bin/sh -x + +LAST_OCTET=`grep address $1/etc/network/interfaces | awk -F. '{ print $4 }'` +PRIV_IP="172.28.5.${LAST_OCTET}" + +cp $1/etc/network/interfaces $1/etc/network/interfaces.bak +cat >> $1/etc/network/interfaces < $1/boot/grub/menu.lst.new <> $1/boot/grub/menu.lst.new +cat $1/boot/grub/menu.lst.new | sed "s/^\(kernel.*\)/\\1 console=tty0 console=ttyS0,115200n8/g" > $1/boot/grub/menu.lst diff --git a/kvm/files/default/templates/scripts/postinstall.sh b/kvm/files/default/templates/scripts/postinstall.sh new file mode 100755 index 0000000..578f3c5 --- /dev/null +++ b/kvm/files/default/templates/scripts/postinstall.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +echo "Enabling ttyS0 console..." +sh /usr/local/share/kvm/scripts/grub-console.sh $1 + +echo "Renaming sda[12] to vda[12] in fstab..." +sh /usr/local/share/kvm/scripts/rename-fstab-devices.sh $1 + +echo "Setup private 172.28 network on eth1..." +sh /usr/local/share/kvm/scripts/add-172-net.sh $1 diff --git a/kvm/files/default/templates/scripts/rename-fstab-devices.sh b/kvm/files/default/templates/scripts/rename-fstab-devices.sh new file mode 100755 index 0000000..8064490 --- /dev/null +++ b/kvm/files/default/templates/scripts/rename-fstab-devices.sh @@ -0,0 +1,5 @@ +#!/bin/sh -x + +cp $1/etc/fstab $1/etc/fstab.bak +cat $1/etc/fstab | sed "s/sda/vda/g" > $1/etc/fstab.new +mv $1/etc/fstab.new $1/etc/fstab diff --git a/kvm/files/default/templates/scripts/vmbuild.sh b/kvm/files/default/templates/scripts/vmbuild.sh new file mode 100755 index 0000000..4e76b34 --- /dev/null +++ b/kvm/files/default/templates/scripts/vmbuild.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +NAME=$1 +CPU=$2 +MEM=$3 +IP=$4 +VOLUME=`echo -n ${NAME} | sed "s/\-/_/g"` + +echo "Generating VM:" +echo " - Name: ${NAME}" +echo " - CPUs: ${CPU}" +echo " - RAM: ${MEM}" +echo " - IP: ${IP}" + +PATH=/usr/bin:/sbin:${PATH} + +lvcreate -n kvm_${VOLUME} -L 18G VolGroupKVM +vmbuilder kvm ubuntu --suite=intrepid --flavour=virtual --arch=amd64 --hostname=${NAME} --mem=${MEM} --cpus=${CPU} \ + --mirror=http://apt/archive-ubuntu/ubuntu --dest=/u/kvm/images/${NAME} --tmp=/u/kvm/tmp --rootsize=16384 --swapsize=1024 \ + --bridge=br0 --ip=${IP} --mask=255.255.252.0 --net=192.168.0.0 --bcast=192.168.3.255 --gw=192.168.1.1 --dns=192.168.2.63 \ + --addpkg=openssh-server --addpkg=acpid --addpkg=sysstat --addpkg=emacs22-nox --addpkg=vim --addpkg=git-core \ + --addpkg=mysql-client --addpkg=libmysqlclient15-dev --addpkg=build-essential --addpkg=syslog-ng --addpkg=ntp \ + --addpkg=curl --addpkg=wget --lang=en_US.UTF-8 \ + --templates=/usr/local/share/kvm/templates \ + --copy=/usr/local/share/kvm/files/manifest.txt \ + --execscript=/usr/local/share/kvm/scripts/postinstall.sh \ + --libvirt=qemu:///system --verbose --debug + +echo "Converting qcow2 image to LVM..." +kvm-img convert /u/kvm/images/${NAME}/disk0.qcow2 -O raw /u/kvm/images/${NAME}/disk0.raw +dd if=/u/kvm/images/${NAME}/disk0.raw of=/dev/mapper/VolGroupKVM-kvm_${VOLUME} bs=1M + +echo "Cleaning up temporary files/directories..." +rm -rvf /u/kvm/images/${NAME} diff --git a/kvm/files/default/templates/templates/libvirt/libvirtxml.tmpl b/kvm/files/default/templates/templates/libvirt/libvirtxml.tmpl new file mode 100755 index 0000000..d9feb1e --- /dev/null +++ b/kvm/files/default/templates/templates/libvirt/libvirtxml.tmpl @@ -0,0 +1,53 @@ + + $hostname + #echo $mem * 1024 # + $cpus + + hvm + + + + + + + destroy + restart + destroy + + /usr/bin/kvm +#if $bridge + + +#else + +#if $mac + +#end if + +#end if +#if $virtio_net + +#end if + + + + + + + +#for $disk in $disks + + + + +#end for + + + + + + + + + + diff --git a/kvm/metadata.json b/kvm/metadata.json new file mode 100755 index 0000000..33b1fc5 --- /dev/null +++ b/kvm/metadata.json @@ -0,0 +1,38 @@ +{ + "replacing": { + + }, + "long_description": "", + "attributes": { + + }, + "maintainer": "37signals", + "recommendations": { + + }, + "license": "Apache v2.0", + "recipes": { + "kvm": "" + }, + "maintainer_email": "sysadmins@37signals.com", + "suggestions": { + + }, + "dependencies": { + + }, + "conflicting": { + + }, + "platforms": { + + }, + "description": "Configures KVM virtualization environment", + "version": "0.1.0", + "name": "kvm", + "providing": { + "kvm": [ + + ] + } +} \ No newline at end of file diff --git a/kvm/metadata.rb b/kvm/metadata.rb new file mode 100755 index 0000000..d59a8cf --- /dev/null +++ b/kvm/metadata.rb @@ -0,0 +1,4 @@ +maintainer "37signals" +maintainer_email "sysadmins@37signals.com" +description "Configures KVM virtualization environment" +version "0.1" diff --git a/kvm/recipes/default.rb b/kvm/recipes/default.rb new file mode 100755 index 0000000..efc0e22 --- /dev/null +++ b/kvm/recipes/default.rb @@ -0,0 +1,106 @@ +# custom vmbuilder debs +%W(kvm debootstrap kpartx python-cheetah devscripts python-libvirt).each { |pkg| package pkg } +%W(python-vm-builder_0.9-0ubuntu6_all.deb + ubuntu-vm-builder_0.9-0ubuntu6_all.deb).each do |pkg| + remote_file "/tmp/#{pkg}" do + source "http://dist/debs/intrepid/vmbuilder/#{pkg}" + not_if "test -e /usr/bin/#{pkg.split('_').first.sub('python-vm-', 'vm')}" + end + + package pkg do + provider Chef::Provider::Package::Dpkg + source "/tmp/#{pkg}" + only_if "test -e /tmp/#{pkg}" + end + + execute "remove_deb" do + command "rm -f /tmp/#{pkg}" + only_if "test -e /tmp/#{pkg}" + end +end + +%W(tmp images).each do |dir| + directory "/u/kvm/#{dir}" do + recursive true + end +end + +remote_directory "/usr/local/share/kvm" do + source "templates" + files_backup 2 + files_owner "root" + files_group "admin" + files_mode 0755 + owner "root" + group "admin" + mode 0750 +end + +remote_directory "/lib/modules/#{@node[:kernel][:release]}/extra" do + source "modules/#{@node[:kernel][:release]}" + files_backup 0 + files_owner "root" + files_group "root" + files_mode 0644 + owner "root" + group "root" + mode 0755 + ignore_failure true +end + +kvm_modules = Dir.glob("/lib/modules/#{@node[:kernel][:release]}/extra/kvm*.ko").map { |f| File.basename(f) } +%W(drivers/kvm arch/x86/kvm).each do |module_dir| + Dir.glob("/lib/modules/#{@node[:kernel][:release]}/kernel/#{module_dir}/*.ko").each do |old_module| + execute "backup old kvm module: #{old_module}" do + command "mv #{old_module} #{old_module}.orig" + only_if { kvm_modules.include?(File.basename(old_module)) && File.exist?(old_module) } + end + end +end + +bash "update kvm userspace" do + user "root" + cwd "/tmp" + + code <<-EOH + curl http://dist/misc/kvm-84.tar.bz2 | tar -C /usr/local -xjf - + mkdir /usr/bin/kvm-dist + mv /usr/bin/kvm* /usr/bin/kvm-dist/. + ln -sf /usr/local/kvm/bin/qemu-system-x86_64 /usr/bin/kvm + ln -sf /usr/local/kvm/bin/qemu-img /usr/bin/kvm-img + ln -sf /usr/local/kvm/bin/qemu-nbd /usr/bin/kvm-nbd + EOH + + not_if { File.directory?("/usr/local/kvm") } +end + +execute "modprobe" do + command "/sbin/depmod -a" + action :run + + only_if do + File.exist?("/lib/modules/#{@node[:kernel][:release]}/extra/kvm.ko") && + ( File.mtime("/lib/modules/#{@node[:kernel][:release]}/extra/kvm.ko") > + File.mtime("/lib/modules/#{@node[:kernel][:release]}/modules.dep") ) + end +end + +gem_package "thor" + +remote_file "/usr/local/bin/kvmtool" do + source "kvmtool" + mode 0755 +end + +service "libvirt-bin" do + supports :restart => false, :reload => true + action :enable +end + +template "/etc/libvirt/libvirtd.conf" do + source "libvirtd.conf.erb" + mode 0644 + owner "root" + group "root" + notifies :reload, resources(:service => "libvirt-bin") +end diff --git a/kvm/templates/default/libvirtd.conf.erb b/kvm/templates/default/libvirtd.conf.erb new file mode 100755 index 0000000..4345982 --- /dev/null +++ b/kvm/templates/default/libvirtd.conf.erb @@ -0,0 +1,227 @@ +# Master libvirt daemon configuration file +# +# For further information consult http://libvirt.org/format.html + + +################################################################# +# +# Network connectivity controls +# + +# Flag listening for secure TLS connections on the public TCP/IP port. +# NB, must pass the --listen flag to the libvirtd process for this to +# have any effect. +# +# It is necessary to setup a CA and issue server certificates before +# using this capability. +# +# This is enabled by default, uncomment this to disable it +#listen_tls = 0 + +# Listen for unencrypted TCP connections on the public TCP/IP port. +# NB, must pass the --listen flag to the libvirtd process for this to +# have any effect. +# +# Using the TCP socket requires SASL authentication by default. Only +# SASL mechanisms which support data encryption are allowed. This is +# DIGEST_MD5 and GSSAPI (Kerberos5) +# +# This is disabled by default, uncomment this to enable it. +#listen_tcp = 1 + + + +# Override the port for accepting secure TLS connections +# This can be a port number, or service name +# +#tls_port = "16514" + +# Override the port for accepting insecure TCP connections +# This can be a port number, or service name +# +#tcp_port = "16509" + + +# Override the default configuration which binds to all network +# interfaces. This can be a numeric IPv4/6 address, or hostname +# +# listen_addr = "192.168.0.1" + + +# Flag toggling mDNS advertizement of the libvirt service. +# +# Alternatively can disable for all services on a host by +# stopping the Avahi daemon +# +# This is enabled by default, uncomment this to disable it +#mdns_adv = 0 + +# Override the default mDNS advertizement name. This must be +# unique on the immediate broadcast network. +# +# The default is "Virtualization Host HOSTNAME", where HOSTNAME +# is subsituted for the short hostname of the machine (without domain) +# +#mdns_name = "Virtualization Host Joe Demo" + + +################################################################# +# +# UNIX socket access controls +# + +# Set the UNIX domain socket group ownership. This can be used to +# allow a 'trusted' set of users access to management capabilities +# without becoming root. +# +# This is restricted to 'root' by default. +unix_sock_group = "admin" + +# Set the UNIX socket permissions for the R/O socket. This is used +# for monitoring VM status only +# +# Default allows any user. If setting group ownership may want to +# restrict this to: +#unix_sock_ro_perms = "0777" + +# Set the UNIX socket permissions for the R/W socket. This is used +# for full management of VMs +# +# Default allows only root. If PolicyKit is enabled on the socket, +# the default will change to allow everyone (eg, 0777) +# +# If not using PolicyKit and setting group ownership for access +# control then you may want to relax this to: +unix_sock_rw_perms = "0770" + + + +################################################################# +# +# Authentication. +# +# - none: do not perform auth checks. If you can connect to the +# socket you are allowed. This is suitable if there are +# restrictions on connecting to the socket (eg, UNIX +# socket permissions), or if there is a lower layer in +# the network providing auth (eg, TLS/x509 certificates) +# +# - sasl: use SASL infrastructure. The actual auth scheme is then +# controlled from /etc/sasl2/libvirt.conf. For the TCP +# socket only GSSAPI & DIGEST-MD5 mechanisms will be used. +# For non-TCP or TLS sockets, any scheme is allowed. +# +# - polkit: use PolicyKit to authenticate. This is only suitable +# for use on the UNIX sockets. The default policy will +# require a user to supply their own password to gain +# full read/write access (aka sudo like), while anyone +# is allowed read/only access. +# +# Set an authentication scheme for UNIX read-only sockets +# By default socket permissions allow anyone to connect +# +# To restrict monitoring of domains you may wish to enable +# an authentication mechanism here +auth_unix_ro = "none" + +# Set an authentication scheme for UNIX read-write sockets +# By default socket permissions only allow root. If PolicyKit +# support was compiled into libvirt, the default will be to +# use 'polkit' auth. +# +# If the unix_sock_rw_perms are changed you may wish to enable +# an authentication mechanism here +auth_unix_rw = "none" + +# Change the authentication scheme for TCP sockets. +# +# If you don't enable SASL, then all TCP traffic is cleartext. +# Don't do this outside of a dev/test scenario. For real world +# use, always enable SASL and use the GSSAPI or DIGEST-MD5 +# mechanism in /etc/sasl2/libvirt.conf +#auth_tcp = "sasl" + +# Change the authentication scheme for TLS sockets. +# +# TLS sockets already have encryption provided by the TLS +# layer, and limited authentication is done by certificates +# +# It is possible to make use of any SASL authentication +# mechanism as well, by using 'sasl' for this option +#auth_tls = "none" + + + +################################################################# +# +# TLS x509 certificate configuration +# + + +# Override the default server key file path +# +#key_file = "/etc/pki/libvirt/private/serverkey.pem" + +# Override the default server certificate file path +# +#cert_file = "/etc/pki/libvirt/servercert.pem" + +# Override the default CA certificate path +# +#ca_file = "/etc/pki/CA/cacert.pem" + +# Specify a certificate revocation list. +# +# Defaults to not using a CRL, uncomment to enable it +#crl_file = "/etc/pki/CA/crl.pem" + + + +################################################################# +# +# Authorization controls +# + + +# Flag to disable verification of client certificates +# +# Client certificate verification is the primary authentication mechanism. +# Any client which does not present a certificate signed by the CA +# will be rejected. +# +# Default is to always verify. Uncommenting this will disable +# verification - make sure an IP whitelist is set +#tls_no_verify_certificate = 1 + + +# A whitelist of allowed x509 Distinguished Names +# This list may contain wildcards such as +# +# "C=GB,ST=London,L=London,O=Red Hat,CN=*" +# +# See the POSIX fnmatch function for the format of the wildcards. +# +# NB If this is an empty list, no client can connect, so comment out +# entirely rather than using empty list to disable these checks +# +# By default, no DN's are checked +#tls_allowed_dn_list = ["DN1", "DN2"] + + +# A whitelist of allowed SASL usernames. The format for usernames +# depends on the SASL authentication mechanism. Kerberos usernames +# look like username@REALM +# +# This list may contain wildcards such as +# +# "*@EXAMPLE.COM" +# +# See the POSIX fnmatch function for the format of the wildcards. +# +# NB If this is an empty list, no client can connect, so comment out +# entirely rather than using empty list to disable these checks +# +# By default, no Username's are checked +#sasl_allowed_username_list = ["joe@EXAMPLE.COM", "fred@EXAMPLE.COM" ] + + diff --git a/logrotate/metadata.json b/logrotate/metadata.json new file mode 100644 index 0000000..e20e2b6 --- /dev/null +++ b/logrotate/metadata.json @@ -0,0 +1,49 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs logrotate", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "logrotate": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "centos": [ + + ], + "debian": [ + + ], + "redhat": [ + + ] + }, + "version": "0.7.0", + "name": "logrotate", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "logrotate": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/logrotate/metadata.rb b/logrotate/metadata.rb new file mode 100644 index 0000000..7714a29 --- /dev/null +++ b/logrotate/metadata.rb @@ -0,0 +1,9 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs logrotate" +version "0.7" + +%w{ redhat centos debian ubuntu }.each do |os| + supports os +end diff --git a/logrotate/recipes/default.rb b/logrotate/recipes/default.rb new file mode 100644 index 0000000..b26f7a3 --- /dev/null +++ b/logrotate/recipes/default.rb @@ -0,0 +1,22 @@ +# +# Cookbook Name:: logrotate +# Recipe:: default +# +# Copyright 2009, Opscode, 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" do + action :upgrade +end diff --git a/logwatch/README.rdoc b/logwatch/README.rdoc new file mode 100644 index 0000000..8d77480 --- /dev/null +++ b/logwatch/README.rdoc @@ -0,0 +1,8 @@ += DESCRIPTION: + += REQUIREMENTS: + += ATTRIBUTES: + += USAGE: + diff --git a/logwatch/metadata.json b/logwatch/metadata.json new file mode 100644 index 0000000..67c9e7f --- /dev/null +++ b/logwatch/metadata.json @@ -0,0 +1,51 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs logwatch, a nice log analyzer", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "logwatch": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "centos": [ + + ], + "debian": [ + + ], + "redhat": [ + + ] + }, + "version": "0.1.0", + "name": "logwatch", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "logwatch": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "= DESCRIPTION:\n\n= REQUIREMENTS:\n\n= ATTRIBUTES: \n\n= USAGE:\n\n", + "replacing": { + + }, + "dependencies": { + "perl": [ + + ] + } +} \ No newline at end of file diff --git a/logwatch/metadata.rb b/logwatch/metadata.rb new file mode 100644 index 0000000..75301a8 --- /dev/null +++ b/logwatch/metadata.rb @@ -0,0 +1,12 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs logwatch, a nice log analyzer" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.1" + +depends "perl" + +%w{ redhat centos debian ubuntu }.each do |os| + supports os +end diff --git a/logwatch/recipes/default.rb b/logwatch/recipes/default.rb new file mode 100644 index 0000000..d4f0b89 --- /dev/null +++ b/logwatch/recipes/default.rb @@ -0,0 +1,23 @@ +# +# Cookbook Name:: logwatch +# Recipe:: default +# +# Copyright 2009, Opscode, 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 "perl" + +package "logwatch" + diff --git a/lvm/metadata.json b/lvm/metadata.json new file mode 100644 index 0000000..8390fb3 --- /dev/null +++ b/lvm/metadata.json @@ -0,0 +1,49 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs lvm2 package", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "lvm": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "centos": [ + + ], + "debian": [ + + ], + "redhat": [ + + ] + }, + "version": "0.7.0", + "name": "lvm", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "lvm": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/lvm/metadata.rb b/lvm/metadata.rb new file mode 100644 index 0000000..215ed9b --- /dev/null +++ b/lvm/metadata.rb @@ -0,0 +1,9 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs lvm2 package" +version "0.7" + +%w{ redhat centos debian ubuntu }.each do |os| + supports os +end diff --git a/lvm/recipes/default.rb b/lvm/recipes/default.rb new file mode 100644 index 0000000..40dd2a5 --- /dev/null +++ b/lvm/recipes/default.rb @@ -0,0 +1,21 @@ +# +# Cookbook Name:: lvm +# Recipe:: default +# +# Copyright 2009, Opscode, 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 "lvm2" do + action :upgrade +end diff --git a/maatkit/files/default/maatkit-5014.tar.gz b/maatkit/files/default/maatkit-5014.tar.gz new file mode 100755 index 0000000..f042a92 Binary files /dev/null and b/maatkit/files/default/maatkit-5014.tar.gz differ diff --git a/maatkit/files/default/mk-query-digest b/maatkit/files/default/mk-query-digest new file mode 100755 index 0000000..21933a8 --- /dev/null +++ b/maatkit/files/default/mk-query-digest @@ -0,0 +1,10308 @@ +#!/usr/bin/env perl + +# This program is copyright 2007-@CURRENTYEAR@ Percona Inc. +# Feedback and improvements are welcome. +# +# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, version 2; OR the Perl Artistic License. On UNIX and similar +# systems, you can issue `man perlgpl' or `man perlartistic' to read these +# licenses. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., 59 Temple +# Place, Suite 330, Boston, MA 02111-1307 USA. + +use strict; +use warnings FATAL => 'all'; + +our $VERSION = '@VERSION@'; +our $DISTRIB = '@DISTRIB@'; +our $SVN_REV = sprintf("%d", (q$Revision$ =~ m/(\d+)/g, 0)); + +# ########################################################################### +# DSNParser package 5226 +# ########################################################################### +package DSNParser; + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); +use Data::Dumper; +$Data::Dumper::Indent = 0; +$Data::Dumper::Quotekeys = 0; + +eval { + require DBI; +}; +my $have_dbi = $EVAL_ERROR ? 0 : 1; + +use constant MKDEBUG => $ENV{MKDEBUG}; + +sub new { + my ( $class, @opts ) = @_; + my $self = { + opts => { + A => { + desc => 'Default character set', + dsn => 'charset', + copy => 1, + }, + D => { + desc => 'Database to use', + dsn => 'database', + copy => 1, + }, + F => { + desc => 'Only read default options from the given file', + dsn => 'mysql_read_default_file', + copy => 1, + }, + h => { + desc => 'Connect to host', + dsn => 'host', + copy => 1, + }, + p => { + desc => 'Password to use when connecting', + dsn => 'password', + copy => 1, + }, + P => { + desc => 'Port number to use for connection', + dsn => 'port', + copy => 1, + }, + S => { + desc => 'Socket file to use for connection', + dsn => 'mysql_socket', + copy => 1, + }, + u => { + desc => 'User for login if not current user', + dsn => 'user', + copy => 1, + }, + }, + }; + foreach my $opt ( @opts ) { + MKDEBUG && _d('Adding extra property', $opt->{key}); + $self->{opts}->{$opt->{key}} = { desc => $opt->{desc}, copy => $opt->{copy} }; + } + return bless $self, $class; +} + +sub prop { + my ( $self, $prop, $value ) = @_; + if ( @_ > 2 ) { + MKDEBUG && _d('Setting', $prop, 'property'); + $self->{$prop} = $value; + } + return $self->{$prop}; +} + +sub parse { + my ( $self, $dsn, $prev, $defaults ) = @_; + if ( !$dsn ) { + MKDEBUG && _d('No DSN to parse'); + return; + } + MKDEBUG && _d('Parsing', $dsn); + $prev ||= {}; + $defaults ||= {}; + my %given_props; + my %final_props; + my %opts = %{$self->{opts}}; + + foreach my $dsn_part ( split(/,/, $dsn) ) { + if ( my ($prop_key, $prop_val) = $dsn_part =~ m/^(.)=(.*)$/ ) { + $given_props{$prop_key} = $prop_val; + } + else { + MKDEBUG && _d('Interpreting', $dsn_part, 'as h=', $dsn_part); + $given_props{h} = $dsn_part; + } + } + + foreach my $key ( keys %opts ) { + MKDEBUG && _d('Finding value for', $key); + $final_props{$key} = $given_props{$key}; + if ( !defined $final_props{$key} + && defined $prev->{$key} && $opts{$key}->{copy} ) + { + $final_props{$key} = $prev->{$key}; + MKDEBUG && _d('Copying value for', $key, 'from previous DSN'); + } + if ( !defined $final_props{$key} ) { + $final_props{$key} = $defaults->{$key}; + MKDEBUG && _d('Copying value for', $key, 'from defaults'); + } + } + + foreach my $key ( keys %given_props ) { + die "Unrecognized DSN part '$key' in '$dsn'\n" + unless exists $opts{$key}; + } + if ( (my $required = $self->prop('required')) ) { + foreach my $key ( keys %$required ) { + die "Missing DSN part '$key' in '$dsn'\n" unless $final_props{$key}; + } + } + + return \%final_props; +} + +sub parse_options { + my ( $self, $o ) = @_; + die 'I need an OptionParser object' unless ref $o eq 'OptionParser'; + my $dsn_string + = join(',', + map { "$_=".$o->get($_); } + grep { $o->has($_) && $o->get($_) } + keys %{$self->{opts}} + ); + MKDEBUG && _d('DSN string made from options:', $dsn_string); + return $self->parse($dsn_string); +} + +sub as_string { + my ( $self, $dsn ) = @_; + return $dsn unless ref $dsn; + return join(',', + map { "$_=" . ($_ eq 'p' ? '...' : $dsn->{$_}) } + grep { defined $dsn->{$_} && $self->{opts}->{$_} } + sort keys %$dsn ); +} + +sub usage { + my ( $self ) = @_; + my $usage + = "DSN syntax is key=value[,key=value...] Allowable DSN keys:\n\n" + . " KEY COPY MEANING\n" + . " === ==== =============================================\n"; + my %opts = %{$self->{opts}}; + foreach my $key ( sort keys %opts ) { + $usage .= " $key " + . ($opts{$key}->{copy} ? 'yes ' : 'no ') + . ($opts{$key}->{desc} || '[No description]') + . "\n"; + } + $usage .= "\n If the DSN is a bareword, the word is treated as the 'h' key.\n"; + return $usage; +} + +sub get_cxn_params { + my ( $self, $info ) = @_; + my $dsn; + my %opts = %{$self->{opts}}; + my $driver = $self->prop('dbidriver') || ''; + if ( $driver eq 'Pg' ) { + $dsn = 'DBI:Pg:dbname=' . ( $info->{D} || '' ) . ';' + . join(';', map { "$opts{$_}->{dsn}=$info->{$_}" } + grep { defined $info->{$_} } + qw(h P)); + } + else { + $dsn = 'DBI:mysql:' . ( $info->{D} || '' ) . ';' + . join(';', map { "$opts{$_}->{dsn}=$info->{$_}" } + grep { defined $info->{$_} } + qw(F h P S A)) + . ';mysql_read_default_group=client'; + } + MKDEBUG && _d($dsn); + return ($dsn, $info->{u}, $info->{p}); +} + +sub fill_in_dsn { + my ( $self, $dbh, $dsn ) = @_; + my $vars = $dbh->selectall_hashref('SHOW VARIABLES', 'Variable_name'); + my ($user, $db) = $dbh->selectrow_array('SELECT USER(), DATABASE()'); + $user =~ s/@.*//; + $dsn->{h} ||= $vars->{hostname}->{Value}; + $dsn->{S} ||= $vars->{'socket'}->{Value}; + $dsn->{P} ||= $vars->{port}->{Value}; + $dsn->{u} ||= $user; + $dsn->{D} ||= $db; +} + +sub get_dbh { + my ( $self, $cxn_string, $user, $pass, $opts ) = @_; + $opts ||= {}; + my $defaults = { + AutoCommit => 0, + RaiseError => 1, + PrintError => 0, + ShowErrorStatement => 1, + mysql_enable_utf8 => ($cxn_string =~ m/charset=utf8/ ? 1 : 0), + }; + @{$defaults}{ keys %$opts } = values %$opts; + + if ( !$have_dbi ) { + die "Cannot connect to MySQL because the Perl DBI module is not " + . "installed or not found. Run 'perl -MDBI' to see the directories " + . "that Perl searches for DBI. If DBI is not installed, try:\n" + . " Debian/Ubuntu apt-get install libdbi-perl\n" + . " RHEL/CentOS yum install perl-DBI\n" + . " OpenSolaris pgk install pkg:/SUNWpmdbi\n"; + + } + + my $dbh; + my $tries = 2; + while ( !$dbh && $tries-- ) { + MKDEBUG && _d($cxn_string, ' ', $user, ' ', $pass, ' {', + join(', ', map { "$_=>$defaults->{$_}" } keys %$defaults ), '}'); + + eval { + $dbh = DBI->connect($cxn_string, $user, $pass, $defaults); + + if ( $cxn_string =~ m/mysql/i ) { + my $sql; + + $sql = q{SET @@SQL_QUOTE_SHOW_CREATE = 1} + . q{/*!40101, @@SQL_MODE='NO_AUTO_VALUE_ON_ZERO'*/}; + MKDEBUG && _d($dbh, ':', $sql); + $dbh->do($sql); + + if ( my ($charset) = $cxn_string =~ m/charset=(\w+)/ ) { + $sql = "/*!40101 SET NAMES $charset*/"; + MKDEBUG && _d($dbh, ':', $sql); + $dbh->do($sql); + MKDEBUG && _d('Enabling charset for STDOUT'); + if ( $charset eq 'utf8' ) { + binmode(STDOUT, ':utf8') + or die "Can't binmode(STDOUT, ':utf8'): $OS_ERROR"; + } + else { + binmode(STDOUT) or die "Can't binmode(STDOUT): $OS_ERROR"; + } + } + + if ( $self->prop('set-vars') ) { + $sql = "SET " . $self->prop('set-vars'); + MKDEBUG && _d($dbh, ':', $sql); + $dbh->do($sql); + } + } + }; + if ( !$dbh && $EVAL_ERROR ) { + MKDEBUG && _d($EVAL_ERROR); + if ( $EVAL_ERROR =~ m/not a compiled character set|character set utf8/ ) { + MKDEBUG && _d('Going to try again without utf8 support'); + delete $defaults->{mysql_enable_utf8}; + } + elsif ( $EVAL_ERROR =~ m/locate DBD\/mysql/i ) { + die "Cannot connect to MySQL because the Perl DBD::mysql module is " + . "not installed or not found. Run 'perl -MDBD::mysql' to see " + . "the directories that Perl searches for DBD::mysql. If " + . "DBD::mysql is not installed, try:\n" + . " Debian/Ubuntu apt-get install libdbd-mysql-perl\n" + . " RHEL/CentOS yum install perl-DBD-MySQL\n" + . " OpenSolaris pgk install pkg:/SUNWapu13dbd-mysql\n"; + } + if ( !$tries ) { + die $EVAL_ERROR; + } + } + } + + MKDEBUG && _d('DBH info: ', + $dbh, + Dumper($dbh->selectrow_hashref( + 'SELECT DATABASE(), CONNECTION_ID(), VERSION()/*!50038 , @@hostname*/')), + 'Connection info:', $dbh->{mysql_hostinfo}, + 'Character set info:', Dumper($dbh->selectall_arrayref( + 'SHOW VARIABLES LIKE "character_set%"', { Slice => {}})), + '$DBD::mysql::VERSION:', $DBD::mysql::VERSION, + '$DBI::VERSION:', $DBI::VERSION, + ); + + return $dbh; +} + +sub get_hostname { + my ( $self, $dbh ) = @_; + if ( my ($host) = ($dbh->{mysql_hostinfo} || '') =~ m/^(\w+) via/ ) { + return $host; + } + my ( $hostname, $one ) = $dbh->selectrow_array( + 'SELECT /*!50038 @@hostname, */ 1'); + return $hostname; +} + +sub disconnect { + my ( $self, $dbh ) = @_; + MKDEBUG && $self->print_active_handles($dbh); + $dbh->disconnect; +} + +sub print_active_handles { + my ( $self, $thing, $level ) = @_; + $level ||= 0; + printf("# Active %sh: %s %s %s\n", ($thing->{Type} || 'undef'), "\t" x $level, + $thing, (($thing->{Type} || '') eq 'st' ? $thing->{Statement} || '' : '')) + or die "Cannot print: $OS_ERROR"; + foreach my $handle ( grep {defined} @{ $thing->{ChildHandles} } ) { + $self->print_active_handles( $handle, $level + 1 ); + } +} + +sub copy { + my ( $self, $dsn_1, $dsn_2, %args ) = @_; + die 'I need a dsn_1 argument' unless $dsn_1; + die 'I need a dsn_2 argument' unless $dsn_2; + my %new_dsn = map { + my $key = $_; + my $val; + if ( $args{overwrite} ) { + $val = defined $dsn_1->{$key} ? $dsn_1->{$key} : $dsn_2->{$key}; + } + else { + $val = defined $dsn_2->{$key} ? $dsn_2->{$key} : $dsn_1->{$key}; + } + $key => $val; + } keys %{$self->{opts}}; + return \%new_dsn; +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +1; + +# ########################################################################### +# End DSNParser package +# ########################################################################### + +# ########################################################################### +# Quoter package 4943 +# ########################################################################### +use strict; +use warnings FATAL => 'all'; + +package Quoter; + +use English qw(-no_match_vars); + +use constant MKDEBUG => $ENV{MKDEBUG}; + +sub new { + my ( $class ) = @_; + bless {}, $class; +} + +sub quote { + my ( $self, @vals ) = @_; + foreach my $val ( @vals ) { + $val =~ s/`/``/g; + } + return join('.', map { '`' . $_ . '`' } @vals); +} + +sub quote_val { + my ( $self, $val, $is_numeric ) = @_; + + return 'NULL' unless defined $val; # undef = NULL + return "''" if $val eq ''; # blank string = '' + + if ( !defined $is_numeric ) { + $is_numeric = $val =~ m/^0|\D/ ? 0 : 1; + } + + return $val if $is_numeric; + + $val =~ s/(['\\])/\\$1/g; + return "'$val'"; +} + +sub split_unquote { + my ( $self, $db_tbl, $default_db ) = @_; + $db_tbl =~ s/`//g; + my ( $db, $tbl ) = split(/[.]/, $db_tbl); + if ( !$tbl ) { + $tbl = $db; + $db = $default_db; + } + return ($db, $tbl); +} + +sub literal_like { + my ( $self, $like ) = @_; + return unless $like; + $like =~ s/([%_])/\\$1/g; + return "'$like'"; +} + +1; + +# ########################################################################### +# End Quoter package +# ########################################################################### + +# ########################################################################### +# OptionParser package 4805 +# ########################################################################### +package OptionParser; + +use strict; +use warnings FATAL => 'all'; + +use Getopt::Long; +use List::Util qw(max); +use English qw(-no_match_vars); + +use constant MKDEBUG => $ENV{MKDEBUG}; + +my $POD_link_re = '[LC]<"?([^">]+)"?>'; + +my %attributes = ( + 'type' => 1, + 'short form' => 1, + 'group' => 1, + 'default' => 1, + 'cumulative' => 1, + 'negatable' => 1, +); + +sub new { + my ( $class, %args ) = @_; + foreach my $arg ( qw(description) ) { + die "I need a $arg argument" unless $args{$arg}; + } + my ($program_name) = $PROGRAM_NAME =~ m/([.A-Za-z-]+)$/; + $program_name ||= $PROGRAM_NAME; + my $home = $ENV{HOME} || $ENV{HOMEPATH} || $ENV{USERPROFILE} || '.'; + + my $self = { + description => $args{description}, + prompt => $args{prompt} || '', + strict => (exists $args{strict} ? $args{strict} : 1), + dp => $args{dp} || undef, + program_name => $program_name, + opts => {}, + got_opts => 0, + short_opts => {}, + defaults => {}, + groups => {}, + allowed_groups => {}, + errors => [], + rules => [], # desc of rules for --help + mutex => [], # rule: opts are mutually exclusive + atleast1 => [], # rule: at least one opt is required + disables => {}, # rule: opt disables other opts + defaults_to => {}, # rule: opt defaults to value of other opt + default_files => [ + "/etc/maatkit/maatkit.conf", + "/etc/maatkit/$program_name.conf", + "$home/.maatkit.conf", + "$home/.$program_name.conf", + ], + }; + return bless $self, $class; +} + +sub get_specs { + my ( $self, $file ) = @_; + my @specs = $self->_pod_to_specs($file); + $self->_parse_specs(@specs); + return; +} + +sub get_defaults_files { + my ( $self ) = @_; + return @{$self->{default_files}}; +} + +sub _pod_to_specs { + my ( $self, $file ) = @_; + $file ||= __FILE__; + open my $fh, '<', $file or die "Cannot open $file: $OS_ERROR"; + + my %types = ( + string => 's', # standard Getopt type + 'int' => 'i', # standard Getopt type + float => 'f', # standard Getopt type + Hash => 'H', # hash, formed from a comma-separated list + hash => 'h', # hash as above, but only if a value is given + Array => 'A', # array, similar to Hash + array => 'a', # array, similar to hash + DSN => 'd', # DSN, as provided by a DSNParser which is in $self->{dp} + size => 'z', # size with kMG suffix (powers of 2^10) + 'time' => 'm', # time, with an optional suffix of s/h/m/d + ); + my @specs = (); + my @rules = (); + my $para; + + local $INPUT_RECORD_SEPARATOR = ''; + while ( $para = <$fh> ) { + next unless $para =~ m/^=head1 OPTIONS/; + last; + } + + while ( $para = <$fh> ) { + last if $para =~ m/^=over/; + chomp $para; + $para =~ s/\s+/ /g; + $para =~ s/$POD_link_re/$1/go; + MKDEBUG && _d('Option rule:', $para); + push @rules, $para; + } + + die 'POD has no OPTIONS section' unless $para; + + do { + if ( my ($option) = $para =~ m/^=item --(.*)/ ) { + chomp $para; + MKDEBUG && _d($para); + my %attribs; + + $para = <$fh>; # read next paragraph, possibly attributes + + if ( $para =~ m/: / ) { # attributes + $para =~ s/\s+\Z//g; + %attribs = map { + my ( $attrib, $val) = split(/: /, $_); + die "Unrecognized attribute for --$option: $attrib" + unless $attributes{$attrib}; + ($attrib, $val); + } split(/; /, $para); + if ( $attribs{'short form'} ) { + $attribs{'short form'} =~ s/-//; + } + $para = <$fh>; # read next paragraph, probably short help desc + } + else { + MKDEBUG && _d('Option has no attributes'); + } + + $para =~ s/\s+\Z//g; + $para =~ s/\s+/ /g; + $para =~ s/$POD_link_re/$1/go; + + $para =~ s/\.(?:\n.*| [A-Z].*|\Z)//s; + MKDEBUG && _d('Short help:', $para); + + die "No description after option spec $option" if $para =~ m/^=item/; + + if ( my ($base_option) = $option =~ m/^\[no\](.*)/ ) { + $option = $base_option; + $attribs{'negatable'} = 1; + } + + push @specs, { + spec => $option + . ($attribs{'short form'} ? '|' . $attribs{'short form'} : '' ) + . ($attribs{'negatable'} ? '!' : '' ) + . ($attribs{'cumulative'} ? '+' : '' ) + . ($attribs{'type'} ? '=' . $types{$attribs{type}} : '' ), + desc => $para + . ($attribs{default} ? " (default $attribs{default})" : ''), + group => ($attribs{'group'} ? $attribs{'group'} : 'default'), + }; + } + while ( $para = <$fh> ) { + last unless $para; + + + if ( $para =~ m/^=head1/ ) { + $para = undef; # Can't 'last' out of a do {} block. + last; + } + last if $para =~ m/^=item --/; + } + } while ( $para ); + + die 'No valid specs in POD OPTIONS' unless @specs; + + close $fh; + return @specs, @rules; +} + +sub _parse_specs { + my ( $self, @specs ) = @_; + my %disables; # special rule that requires deferred checking + + foreach my $opt ( @specs ) { + if ( ref $opt ) { # It's an option spec, not a rule. + MKDEBUG && _d('Parsing opt spec:', + map { ($_, '=>', $opt->{$_}) } keys %$opt); + + my ( $long, $short ) = $opt->{spec} =~ m/^([\w-]+)(?:\|([^!+=]*))?/; + if ( !$long ) { + die "Cannot parse long option from spec $opt->{spec}"; + } + $opt->{long} = $long; + + die "Duplicate long option --$long" if exists $self->{opts}->{$long}; + $self->{opts}->{$long} = $opt; + + if ( length $long == 1 ) { + MKDEBUG && _d('Long opt', $long, 'looks like short opt'); + $self->{short_opts}->{$long} = $long; + } + + if ( $short ) { + die "Duplicate short option -$short" + if exists $self->{short_opts}->{$short}; + $self->{short_opts}->{$short} = $long; + $opt->{short} = $short; + } + else { + $opt->{short} = undef; + } + + $opt->{is_negatable} = $opt->{spec} =~ m/!/ ? 1 : 0; + $opt->{is_cumulative} = $opt->{spec} =~ m/\+/ ? 1 : 0; + $opt->{is_required} = $opt->{desc} =~ m/required/ ? 1 : 0; + + $opt->{group} ||= 'default'; + $self->{groups}->{ $opt->{group} }->{$long} = 1; + + $opt->{value} = undef; + $opt->{got} = 0; + + my ( $type ) = $opt->{spec} =~ m/=(.)/; + $opt->{type} = $type; + MKDEBUG && _d($long, 'type:', $type); + + if ( $type && $type eq 'd' && !$self->{dp} ) { + die "$opt->{long} is type DSN (d) but no dp argument " + . "was given when this OptionParser object was created"; + } + + $opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ ); + + if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) { + $self->{defaults}->{$long} = defined $def ? $def : 1; + MKDEBUG && _d($long, 'default:', $def); + } + + if ( $long eq 'config' ) { + $self->{defaults}->{$long} = join(',', $self->get_defaults_files()); + } + + if ( (my ($dis) = $opt->{desc} =~ m/(disables .*)/) ) { + $disables{$long} = $dis; + MKDEBUG && _d('Deferring check of disables rule for', $opt, $dis); + } + + $self->{opts}->{$long} = $opt; + } + else { # It's an option rule, not a spec. + MKDEBUG && _d('Parsing rule:', $opt); + push @{$self->{rules}}, $opt; + my @participants = $self->_get_participants($opt); + my $rule_ok = 0; + + if ( $opt =~ m/mutually exclusive|one and only one/ ) { + $rule_ok = 1; + push @{$self->{mutex}}, \@participants; + MKDEBUG && _d(@participants, 'are mutually exclusive'); + } + if ( $opt =~ m/at least one|one and only one/ ) { + $rule_ok = 1; + push @{$self->{atleast1}}, \@participants; + MKDEBUG && _d(@participants, 'require at least one'); + } + if ( $opt =~ m/default to/ ) { + $rule_ok = 1; + $self->{defaults_to}->{$participants[0]} = $participants[1]; + MKDEBUG && _d($participants[0], 'defaults to', $participants[1]); + } + if ( $opt =~ m/restricted to option groups/ ) { + $rule_ok = 1; + my ($groups) = $opt =~ m/groups ([\w\s\,]+)/; + my @groups = split(',', $groups); + %{$self->{allowed_groups}->{$participants[0]}} = map { + s/\s+//; + $_ => 1; + } @groups; + } + + die "Unrecognized option rule: $opt" unless $rule_ok; + } + } + + foreach my $long ( keys %disables ) { + my @participants = $self->_get_participants($disables{$long}); + $self->{disables}->{$long} = \@participants; + MKDEBUG && _d('Option', $long, 'disables', @participants); + } + + return; +} + +sub _get_participants { + my ( $self, $str ) = @_; + my @participants; + foreach my $long ( $str =~ m/--(?:\[no\])?([\w-]+)/g ) { + die "Option --$long does not exist while processing rule $str" + unless exists $self->{opts}->{$long}; + push @participants, $long; + } + MKDEBUG && _d('Participants for', $str, ':', @participants); + return @participants; +} + +sub opts { + my ( $self ) = @_; + my %opts = %{$self->{opts}}; + return %opts; +} + +sub short_opts { + my ( $self ) = @_; + my %short_opts = %{$self->{short_opts}}; + return %short_opts; +} + +sub set_defaults { + my ( $self, %defaults ) = @_; + $self->{defaults} = {}; + foreach my $long ( keys %defaults ) { + die "Cannot set default for nonexistent option $long" + unless exists $self->{opts}->{$long}; + $self->{defaults}->{$long} = $defaults{$long}; + MKDEBUG && _d('Default val for', $long, ':', $defaults{$long}); + } + return; +} + +sub get_defaults { + my ( $self ) = @_; + return $self->{defaults}; +} + +sub get_groups { + my ( $self ) = @_; + return $self->{groups}; +} + +sub _set_option { + my ( $self, $opt, $val ) = @_; + my $long = exists $self->{opts}->{$opt} ? $opt + : exists $self->{short_opts}->{$opt} ? $self->{short_opts}->{$opt} + : die "Getopt::Long gave a nonexistent option: $opt"; + + $opt = $self->{opts}->{$long}; + if ( $opt->{is_cumulative} ) { + $opt->{value}++; + } + else { + $opt->{value} = $val; + } + $opt->{got} = 1; + MKDEBUG && _d('Got option', $long, '=', $val); +} + +sub get_opts { + my ( $self ) = @_; + + foreach my $long ( keys %{$self->{opts}} ) { + $self->{opts}->{$long}->{got} = 0; + $self->{opts}->{$long}->{value} + = exists $self->{defaults}->{$long} ? $self->{defaults}->{$long} + : $self->{opts}->{$long}->{is_cumulative} ? 0 + : undef; + } + $self->{got_opts} = 0; + + $self->{errors} = []; + + if ( @ARGV && $ARGV[0] eq "--config" ) { + shift @ARGV; + $self->_set_option('config', shift @ARGV); + } + if ( $self->has('config') ) { + my @extra_args; + foreach my $filename ( split(',', $self->get('config')) ) { + eval { + push @extra_args, $self->_read_config_file($filename); + }; + if ( $EVAL_ERROR ) { + if ( $self->got('config') ) { + die $EVAL_ERROR; + } + elsif ( MKDEBUG ) { + _d($EVAL_ERROR); + } + } + } + unshift @ARGV, @extra_args; + } + + Getopt::Long::Configure('no_ignore_case', 'bundling'); + GetOptions( + map { $_->{spec} => sub { $self->_set_option(@_); } } + grep { $_->{long} ne 'config' } # --config is handled specially above. + values %{$self->{opts}} + ) or $self->save_error('Error parsing options'); + + if ( exists $self->{opts}->{version} && $self->{opts}->{version}->{got} ) { + printf("%s Ver %s Distrib %s Changeset %s\n", + $self->{program_name}, $main::VERSION, $main::DISTRIB, $main::SVN_REV) + or die "Cannot print: $OS_ERROR"; + exit 0; + } + + if ( @ARGV && $self->{strict} ) { + $self->save_error("Unrecognized command-line options @ARGV"); + } + + foreach my $mutex ( @{$self->{mutex}} ) { + my @set = grep { $self->{opts}->{$_}->{got} } @$mutex; + if ( @set > 1 ) { + my $err = join(', ', map { "--$self->{opts}->{$_}->{long}" } + @{$mutex}[ 0 .. scalar(@$mutex) - 2] ) + . ' and --'.$self->{opts}->{$mutex->[-1]}->{long} + . ' are mutually exclusive.'; + $self->save_error($err); + } + } + + foreach my $required ( @{$self->{atleast1}} ) { + my @set = grep { $self->{opts}->{$_}->{got} } @$required; + if ( @set == 0 ) { + my $err = join(', ', map { "--$self->{opts}->{$_}->{long}" } + @{$required}[ 0 .. scalar(@$required) - 2] ) + .' or --'.$self->{opts}->{$required->[-1]}->{long}; + $self->save_error("Specify at least one of $err"); + } + } + + foreach my $long ( keys %{$self->{opts}} ) { + my $opt = $self->{opts}->{$long}; + if ( $opt->{got} ) { + if ( exists $self->{disables}->{$long} ) { + my @disable_opts = @{$self->{disables}->{$long}}; + map { $self->{opts}->{$_}->{value} = undef; } @disable_opts; + MKDEBUG && _d('Unset options', @disable_opts, + 'because', $long,'disables them'); + } + + if ( exists $self->{allowed_groups}->{$long} ) { + + my @restricted_groups = grep { + !exists $self->{allowed_groups}->{$long}->{$_} + } keys %{$self->{groups}}; + + my @restricted_opts; + foreach my $restricted_group ( @restricted_groups ) { + RESTRICTED_OPT: + foreach my $restricted_opt ( + keys %{$self->{groups}->{$restricted_group}} ) + { + next RESTRICTED_OPT if $restricted_opt eq $long; + push @restricted_opts, $restricted_opt + if $self->{opts}->{$restricted_opt}->{got}; + } + } + + if ( @restricted_opts ) { + my $err; + if ( @restricted_opts == 1 ) { + $err = "--$restricted_opts[0]"; + } + else { + $err = join(', ', + map { "--$self->{opts}->{$_}->{long}" } + grep { $_ } + @restricted_opts[0..scalar(@restricted_opts) - 2] + ) + . ' or --'.$self->{opts}->{$restricted_opts[-1]}->{long}; + } + $self->save_error("--$long is not allowed with $err"); + } + } + + } + elsif ( $opt->{is_required} ) { + $self->save_error("Required option --$long must be specified"); + } + + $self->_validate_type($opt); + } + + $self->{got_opts} = 1; + return; +} + +sub _validate_type { + my ( $self, $opt ) = @_; + return unless $opt && $opt->{type}; + my $val = $opt->{value}; + + if ( $val && $opt->{type} eq 'm' ) { # type time + MKDEBUG && _d('Parsing option', $opt->{long}, 'as a time value'); + my ( $prefix, $num, $suffix ) = $val =~ m/([+-]?)(\d+)([a-z])?$/; + if ( !$suffix ) { + my ( $s ) = $opt->{desc} =~ m/\(suffix (.)\)/; + $suffix = $s || 's'; + MKDEBUG && _d('No suffix given; using', $suffix, 'for', + $opt->{long}, '(value:', $val, ')'); + } + if ( $suffix =~ m/[smhd]/ ) { + $val = $suffix eq 's' ? $num # Seconds + : $suffix eq 'm' ? $num * 60 # Minutes + : $suffix eq 'h' ? $num * 3600 # Hours + : $num * 86400; # Days + $opt->{value} = ($prefix || '') . $val; + MKDEBUG && _d('Setting option', $opt->{long}, 'to', $val); + } + else { + $self->save_error("Invalid time suffix for --$opt->{long}"); + } + } + elsif ( $val && $opt->{type} eq 'd' ) { # type DSN + MKDEBUG && _d('Parsing option', $opt->{long}, 'as a DSN'); + my $prev = {}; + my $from_key = $self->{defaults_to}->{ $opt->{long} }; + if ( $from_key ) { + MKDEBUG && _d($opt->{long}, 'DSN copies from', $from_key, 'DSN'); + $prev = $self->{opts}->{$from_key}->{value}; + } + my $defaults = $self->{dp}->parse_options($self); + $opt->{value} = $self->{dp}->parse($val, $prev, $defaults); + } + elsif ( $val && $opt->{type} eq 'z' ) { # type size + MKDEBUG && _d('Parsing option', $opt->{long}, 'as a size value'); + my %factor_for = (k => 1_024, M => 1_048_576, G => 1_073_741_824); + my ($pre, $num, $factor) = $val =~ m/^([+-])?(\d+)([kMG])?$/; + if ( defined $num ) { + if ( $factor ) { + $num *= $factor_for{$factor}; + MKDEBUG && _d('Setting option', $opt->{y}, + 'to num', $num, '* factor', $factor); + } + $opt->{value} = ($pre || '') . $num; + } + else { + $self->save_error("Invalid size for --$opt->{long}"); + } + } + elsif ( $opt->{type} eq 'H' || (defined $val && $opt->{type} eq 'h') ) { + $opt->{value} = { map { $_ => 1 } split(',', ($val || '')) }; + } + elsif ( $opt->{type} eq 'A' || (defined $val && $opt->{type} eq 'a') ) { + $opt->{value} = [ split(/(?{long}, 'type', $opt->{type}, 'value', $val); + } + + return; +} + +sub get { + my ( $self, $opt ) = @_; + my $long = (length $opt == 1 ? $self->{short_opts}->{$opt} : $opt); + die "Option $opt does not exist" + unless $long && exists $self->{opts}->{$long}; + return $self->{opts}->{$long}->{value}; +} + +sub got { + my ( $self, $opt ) = @_; + my $long = (length $opt == 1 ? $self->{short_opts}->{$opt} : $opt); + die "Option $opt does not exist" + unless $long && exists $self->{opts}->{$long}; + return $self->{opts}->{$long}->{got}; +} + +sub has { + my ( $self, $opt ) = @_; + my $long = (length $opt == 1 ? $self->{short_opts}->{$opt} : $opt); + return defined $long ? exists $self->{opts}->{$long} : 0; +} + +sub set { + my ( $self, $opt, $val ) = @_; + my $long = (length $opt == 1 ? $self->{short_opts}->{$opt} : $opt); + die "Option $opt does not exist" + unless $long && exists $self->{opts}->{$long}; + $self->{opts}->{$long}->{value} = $val; + return; +} + +sub save_error { + my ( $self, $error ) = @_; + push @{$self->{errors}}, $error; +} + +sub errors { + my ( $self ) = @_; + return $self->{errors}; +} + +sub prompt { + my ( $self ) = @_; + return "Usage: $PROGRAM_NAME $self->{prompt}\n"; +} + +sub descr { + my ( $self ) = @_; + my $descr = $self->{program_name} . ' ' . ($self->{description} || '') + . " For more details, please use the --help option, " + . "or try 'perldoc $PROGRAM_NAME' " + . "for complete documentation."; + $descr = join("\n", $descr =~ m/(.{0,80})(?:\s+|$)/g); + $descr =~ s/ +$//mg; + return $descr; +} + +sub usage_or_errors { + my ( $self ) = @_; + if ( $self->{opts}->{help}->{got} ) { + print $self->print_usage() or die "Cannot print usage: $OS_ERROR"; + exit 0; + } + elsif ( scalar @{$self->{errors}} ) { + print $self->print_errors() or die "Cannot print errors: $OS_ERROR"; + exit 0; + } + return; +} + +sub print_errors { + my ( $self ) = @_; + my $usage = $self->prompt() . "\n"; + if ( (my @errors = @{$self->{errors}}) ) { + $usage .= join("\n * ", 'Errors in command-line arguments:', @errors) + . "\n"; + } + return $usage . "\n" . $self->descr(); +} + +sub print_usage { + my ( $self ) = @_; + die "Run get_opts() before print_usage()" unless $self->{got_opts}; + my @opts = values %{$self->{opts}}; + + my $maxl = max( + map { length($_->{long}) + ($_->{is_negatable} ? 4 : 0) } + @opts); + + my $maxs = max(0, + map { length($_) + ($self->{opts}->{$_}->{is_negatable} ? 4 : 0) } + values %{$self->{short_opts}}); + + my $lcol = max($maxl, ($maxs + 3)); + my $rcol = 80 - $lcol - 6; + my $rpad = ' ' x ( 80 - $rcol ); + + $maxs = max($lcol - 3, $maxs); + + my $usage = $self->descr() . "\n" . $self->prompt(); + + my @groups = reverse sort grep { $_ ne 'default'; } keys %{$self->{groups}}; + push @groups, 'default'; + + foreach my $group ( reverse @groups ) { + $usage .= "\n".($group eq 'default' ? 'Options' : $group).":\n\n"; + foreach my $opt ( + sort { $a->{long} cmp $b->{long} } + grep { $_->{group} eq $group } + @opts ) + { + my $long = $opt->{is_negatable} ? "[no]$opt->{long}" : $opt->{long}; + my $short = $opt->{short}; + my $desc = $opt->{desc}; + if ( $opt->{type} && $opt->{type} eq 'm' ) { + my ($s) = $desc =~ m/\(suffix (.)\)/; + $s ||= 's'; + $desc =~ s/\s+\(suffix .\)//; + $desc .= ". Optional suffix s=seconds, m=minutes, h=hours, " + . "d=days; if no suffix, $s is used."; + } + $desc = join("\n$rpad", grep { $_ } $desc =~ m/(.{0,$rcol})(?:\s+|$)/g); + $desc =~ s/ +$//mg; + if ( $short ) { + $usage .= sprintf(" --%-${maxs}s -%s %s\n", $long, $short, $desc); + } + else { + $usage .= sprintf(" --%-${lcol}s %s\n", $long, $desc); + } + } + } + + if ( (my @rules = @{$self->{rules}}) ) { + $usage .= "\nRules:\n\n"; + $usage .= join("\n", map { " $_" } @rules) . "\n"; + } + if ( $self->{dp} ) { + $usage .= "\n" . $self->{dp}->usage(); + } + $usage .= "\nOptions and values after processing arguments:\n\n"; + foreach my $opt ( sort { $a->{long} cmp $b->{long} } @opts ) { + my $val = $opt->{value}; + my $type = $opt->{type} || ''; + my $bool = $opt->{spec} =~ m/^[\w-]+(?:\|[\w-])?!?$/; + $val = $bool ? ( $val ? 'TRUE' : 'FALSE' ) + : !defined $val ? '(No value)' + : $type eq 'd' ? $self->{dp}->as_string($val) + : $type =~ m/H|h/ ? join(',', sort keys %$val) + : $type =~ m/A|a/ ? join(',', @$val) + : $val; + $usage .= sprintf(" --%-${lcol}s %s\n", $opt->{long}, $val); + } + return $usage; +} + +sub prompt_noecho { + shift @_ if ref $_[0] eq __PACKAGE__; + my ( $prompt ) = @_; + local $OUTPUT_AUTOFLUSH = 1; + print $prompt + or die "Cannot print: $OS_ERROR"; + my $response; + eval { + require Term::ReadKey; + Term::ReadKey::ReadMode('noecho'); + chomp($response = ); + Term::ReadKey::ReadMode('normal'); + print "\n" + or die "Cannot print: $OS_ERROR"; + }; + if ( $EVAL_ERROR ) { + die "Cannot read response; is Term::ReadKey installed? $EVAL_ERROR"; + } + return $response; +} + +if ( MKDEBUG ) { + print '# ', $^X, ' ', $], "\n"; + my $uname = `uname -a`; + if ( $uname ) { + $uname =~ s/\s+/ /g; + print "# $uname\n"; + } + printf("# %s Ver %s Distrib %s Changeset %s line %d\n", + $PROGRAM_NAME, ($main::VERSION || ''), ($main::DISTRIB || ''), + ($main::SVN_REV || ''), __LINE__); + print('# Arguments: ', + join(' ', map { my $a = "_[$_]_"; $a =~ s/\n/\n# /g; $a; } @ARGV), "\n"); +} + +sub _read_config_file { + my ( $self, $filename ) = @_; + open my $fh, "<", $filename or die "Cannot open $filename: $OS_ERROR\n"; + my @args; + my $prefix = '--'; + my $parse = 1; + + LINE: + while ( my $line = <$fh> ) { + chomp $line; + next LINE if $line =~ m/^\s*(?:\#|\;|$)/; + $line =~ s/\s+#.*$//g; + $line =~ s/^\s+|\s+$//g; + if ( $line eq '--' ) { + $prefix = ''; + $parse = 0; + next LINE; + } + if ( $parse + && (my($opt, $arg) = $line =~ m/^\s*([^=\s]+?)(?:\s*=\s*(.*?)\s*)?$/) + ) { + push @args, grep { defined $_ } ("$prefix$opt", $arg); + } + elsif ( $line =~ m/./ ) { + push @args, $line; + } + else { + die "Syntax error in file $filename at line $INPUT_LINE_NUMBER"; + } + } + close $fh; + return @args; +} + +sub read_para_after { + my ( $self, $file, $regex ) = @_; + open my $fh, "<", $file or die "Can't open $file: $OS_ERROR"; + local $INPUT_RECORD_SEPARATOR = ''; + my $para; + while ( $para = <$fh> ) { + next unless $para =~ m/^=pod$/m; + last; + } + while ( $para = <$fh> ) { + next unless $para =~ m/$regex/; + last; + } + $para = <$fh>; + chomp($para); + close $fh or die "Can't close $file: $OS_ERROR"; + return $para; +} + +sub clone { + my ( $self ) = @_; + + my %clone = map { + my $hashref = $self->{$_}; + my $val_copy = {}; + foreach my $key ( keys %$hashref ) { + my $ref = ref $hashref->{$key}; + $val_copy->{$key} = !$ref ? $hashref->{$key} + : $ref eq 'HASH' ? { %{$hashref->{$key}} } + : $ref eq 'ARRAY' ? [ @{$hashref->{$key}} ] + : $hashref->{$key}; + } + $_ => $val_copy; + } qw(opts short_opts defaults); + + foreach my $scalar ( qw(got_opts) ) { + $clone{$scalar} = $self->{$scalar}; + } + + return bless \%clone; +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +1; + +# ########################################################################### +# End OptionParser package +# ########################################################################### + +# ########################################################################### +# Transformers package 5144 +# ########################################################################### + +package Transformers; + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); +use Time::Local qw(timegm timelocal); +use Digest::MD5 qw(md5_hex); + +use constant MKDEBUG => $ENV{MKDEBUG}; + +require Exporter; +our @ISA = qw(Exporter); +our %EXPORT_TAGS = (); +our @EXPORT = (); +our @EXPORT_OK = qw( + micro_t + percentage_of + secs_to_time + shorten + ts + parse_timestamp + unix_timestamp + any_unix_timestamp + make_checksum +); + +our $mysql_ts = qr/(\d\d)(\d\d)(\d\d) +(\d+):(\d+):(\d+)(\.\d+)?/; +our $proper_ts = qr/(\d\d\d\d)-(\d\d)-(\d\d)[T ](\d\d):(\d\d):(\d\d)(\.\d+)?/; +our $n_ts = qr/(\d{1,5})([shmd]?)/; # Limit \d{1,5} because \d{6} looks + +sub micro_t { + my ( $t, %args ) = @_; + my $p_ms = defined $args{p_ms} ? $args{p_ms} : 0; # precision for ms vals + my $p_s = defined $args{p_s} ? $args{p_s} : 0; # precision for s vals + my $f; + + $t = 0 if $t < 0; + + $t = sprintf('%.17f', $t) if $t =~ /e/; + + $t =~ s/\.(\d{1,6})\d*/\.$1/; + + if ($t > 0 && $t <= 0.000999) { + $f = ($t * 1000000) . 'us'; + } + elsif ($t >= 0.001000 && $t <= 0.999999) { + $f = sprintf("%.${p_ms}f", $t * 1000); + $f = ($f * 1) . 'ms'; # * 1 to remove insignificant zeros + } + elsif ($t >= 1) { + $f = sprintf("%.${p_s}f", $t); + $f = ($f * 1) . 's'; # * 1 to remove insignificant zeros + } + else { + $f = 0; # $t should = 0 at this point + } + + return $f; +} + +sub percentage_of { + my ( $is, $of, %args ) = @_; + my $p = $args{p} || 0; # float precision + my $fmt = $p ? "%.${p}f" : "%d"; + return sprintf $fmt, ($is * 100) / ($of ||= 1); +} + +sub secs_to_time { + my ( $secs, $fmt ) = @_; + $secs ||= 0; + return '00:00' unless $secs; + + $fmt ||= $secs >= 86_400 ? 'd' + : $secs >= 3_600 ? 'h' + : 'm'; + + return + $fmt eq 'd' ? sprintf( + "%d+%02d:%02d:%02d", + int($secs / 86_400), + int(($secs % 86_400) / 3_600), + int(($secs % 3_600) / 60), + $secs % 60) + : $fmt eq 'h' ? sprintf( + "%02d:%02d:%02d", + int(($secs % 86_400) / 3_600), + int(($secs % 3_600) / 60), + $secs % 60) + : sprintf( + "%02d:%02d", + int(($secs % 3_600) / 60), + $secs % 60); +} + +sub shorten { + my ( $num, %args ) = @_; + my $p = defined $args{p} ? $args{p} : 2; # float precision + my $d = defined $args{d} ? $args{d} : 1_024; # divisor + my $n = 0; + my @units = ('', qw(k M G T P E Z Y)); + while ( $num >= $d && $n < @units - 1 ) { + $num /= $d; + ++$n; + } + return sprintf( + $num =~ m/\./ || $n + ? "%.${p}f%s" + : '%d', + $num, $units[$n]); +} + +sub ts { + my ( $time, $gmt ) = @_; + my ( $sec, $min, $hour, $mday, $mon, $year ) + = $gmt ? gmtime($time) : localtime($time); + $mon += 1; + $year += 1900; + my $val = sprintf("%d-%02d-%02dT%02d:%02d:%02d", + $year, $mon, $mday, $hour, $min, $sec); + if ( my ($us) = $time =~ m/(\.\d+)$/ ) { + $us = sprintf("%.6f", $us); + $us =~ s/^0\././; + $val .= $us; + } + return $val; +} + +sub parse_timestamp { + my ( $val ) = @_; + if ( my($y, $m, $d, $h, $i, $s, $f) + = $val =~ m/^$mysql_ts$/ ) + { + return sprintf "%d-%02d-%02d %02d:%02d:" + . (defined $f ? '%02.6f' : '%02d'), + $y + 2000, $m, $d, $h, $i, (defined $f ? $s + $f : $s); + } + return $val; +} + +sub unix_timestamp { + my ( $val, $gmt ) = @_; + if ( my($y, $m, $d, $h, $i, $s, $us) = $val =~ m/^$proper_ts$/ ) { + $val = $gmt + ? timegm($s, $i, $h, $d, $m - 1, $y) + : timelocal($s, $i, $h, $d, $m - 1, $y); + if ( defined $us ) { + $us = sprintf('%.6f', $us); + $us =~ s/^0\././; + $val .= $us; + } + } + return $val; +} + +sub any_unix_timestamp { + my ( $val, $callback ) = @_; + + if ( my ($n, $suffix) = $val =~ m/^$n_ts$/ ) { + $n = $suffix eq 's' ? $n # Seconds + : $suffix eq 'm' ? $n * 60 # Minutes + : $suffix eq 'h' ? $n * 3600 # Hours + : $suffix eq 'd' ? $n * 86400 # Days + : $n; # default: Seconds + MKDEBUG && _d('ts is now - N[shmd]:', $n); + return time - $n; + } + elsif ( my ($ymd, $hms) = $val =~ m/^(\d{6})(?:\s+(\d+:\d+:\d+))?/ ) { + MKDEBUG && _d('ts is MySQL slow log timestamp'); + $val .= ' 00:00:00' unless $hms; + return unix_timestamp(parse_timestamp($val)); + } + elsif ( ($ymd, $hms) = $val =~ m/^(\d{4}-\d\d-\d\d)(?:[T ](\d+:\d+:\d+))?/) { + MKDEBUG && _d('ts is properly formatted timestamp'); + $val .= ' 00:00:00' unless $hms; + return unix_timestamp($val); + } + else { + MKDEBUG && _d('ts is MySQL expression'); + return $callback->($val) if $callback && ref $callback eq 'CODE'; + } + + MKDEBUG && _d('Unknown ts type:', $val); + return; +} + +sub make_checksum { + my ( $val ) = @_; + my $checksum = uc substr(md5_hex($val), -16); + MKDEBUG && _d($checksum, 'checksum for', $val); + return $checksum; +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +1; + +# ########################################################################### +# End Transformers package +# ########################################################################### + +# ########################################################################### +# QueryRewriter package 5228 +# ########################################################################### +use strict; +use warnings FATAL => 'all'; + +package QueryRewriter; + +use English qw(-no_match_vars); + +use constant MKDEBUG => $ENV{MKDEBUG}; + +our $verbs = qr{^SHOW|^FLUSH|^COMMIT|^ROLLBACK|^BEGIN|SELECT|INSERT + |UPDATE|DELETE|REPLACE|^SET|UNION|^START|^LOCK}xi; +my $quote_re = qr/"(?:(?!(? [^()]+ ) # Non-parens without backtracking + | + (??{ $bal }) # Group with matching parens + )* + \) + /x; + +my $olc_re = qr/(?:--|#)[^'"\r\n]*(?=[\r\n]|\Z)/; # One-line comments +my $mlc_re = qr#/\*[^!].*?\*/#sm; # But not /*!version */ + +sub new { + my ( $class, %args ) = @_; + my $self = { %args }; + return bless $self, $class; +} + +sub strip_comments { + my ( $self, $query ) = @_; + $query =~ s/$olc_re//go; + $query =~ s/$mlc_re//go; + return $query; +} + +sub shorten { + my ( $self, $query, $length ) = @_; + $query =~ s{ + \A( + (?:INSERT|REPLACE) + (?:\s+LOW_PRIORITY|DELAYED|HIGH_PRIORITY|IGNORE)? + (?:\s\w+)*\s+\S+\s+VALUES\s*\(.*?\) + ) + \s*,\s*\(.*?(ON\s+DUPLICATE|\Z)} + {$1 /*... omitted ...*/$2}xsi; + + return $query unless $query =~ m/IN\s*\(\s*(?!select)/i; + + my $last_length = 0; + my $query_length = length($query); + while ( + $length > 0 + && $query_length > $length + && $query_length < ( $last_length || $query_length + 1 ) + ) { + $last_length = $query_length; + $query =~ s{ + (\bIN\s*\() # The opening of an IN list + ([^\)]+) # Contents of the list, assuming no item contains paren + (?=\)) # Close of the list + } + { + $1 . __shorten($2) + }gexsi; + } + + return $query; +} + +sub __shorten { + my ( $snippet ) = @_; + my @vals = split(/,/, $snippet); + return $snippet unless @vals > 20; + my @keep = splice(@vals, 0, 20); # Remove and save the first 20 items + return + join(',', @keep) + . "/*... omitted " + . scalar(@vals) + . " items ...*/"; +} + +sub fingerprint { + my ( $self, $query ) = @_; + + $query =~ m#\ASELECT /\*!40001 SQL_NO_CACHE \*/ \* FROM `# # mysqldump query + && return 'mysqldump'; + $query =~ m#/\*\w+\.\w+:[0-9]/[0-9]\*/# # mk-table-checksum, etc query + && return 'maatkit'; + $query =~ m/\A# administrator command: / + && return $query; + $query =~ m/\A\s*(call\s+\S+)\(/i + && return lc($1); # Warning! $1 used, be careful. + if ( my ($beginning) = $query =~ m/\A((?:INSERT|REPLACE)(?: IGNORE)?\s+INTO.+?VALUES\s*\(.*?\))\s*,\s*\(/is ) { + $query = $beginning; # Shorten multi-value INSERT statements ASAP + } + + $query =~ s/$olc_re//go; + $query =~ s/$mlc_re//go; + $query =~ s/\Ause \S+\Z/use ?/i # Abstract the DB in USE + && return $query; + + $query =~ s/\\["']//g; # quoted strings + $query =~ s/".*?"/?/sg; # quoted strings + $query =~ s/'.*?'/?/sg; # quoted strings + $query =~ s/[0-9+-][0-9a-f.xb+-]*/?/g;# Anything vaguely resembling numbers + $query =~ s/[xb.+-]\?/?/g; # Clean up leftovers + $query =~ s/\A\s+//; # Chop off leading whitespace + chomp $query; # Kill trailing whitespace + $query =~ tr[ \n\t\r\f][ ]s; # Collapse whitespace + $query = lc $query; + $query =~ s/\bnull\b/?/g; # Get rid of NULLs + $query =~ s{ # Collapse IN and VALUES lists + \b(in|values?)(?:[\s,]*\([\s?,]*\))+ + } + {$1(?+)}gx; + $query =~ s{ # Collapse UNION + \b(select\s.*?)(?:(\sunion(?:\sall)?)\s\1)+ + } + {$1 /*repeat$2*/}xg; + $query =~ s/\blimit \?(?:, ?\?| offset \?)?/limit ?/; # LIMIT + return $query; +} + +sub _distill_verbs { + my ( $self, $query ) = @_; + + $query =~ m/\A\s*call\s+(\S+)\(/i + && return "CALL $1"; # Warning! $1 used, be careful. + $query =~ m/\A# administrator/ + && return "ADMIN"; + $query =~ m/\A\s*use\s+/ + && return "USE"; + $query =~ m/\A\s*UNLOCK TABLES/i + && return "UNLOCK"; + $query =~ m/\A\s*xa\s+(\S+)/i + && return "XA_$1"; + + $query = $self->strip_comments($query); + + if ( $query =~ m/\A\s*SHOW\s+/i ) { + my @what = $query =~ m/SHOW\s+(\S+)(?:\s+(\S+))?/i; + MKDEBUG && _d('SHOW', @what); + return unless scalar @what; + @what = map { uc $_ } grep { defined $_ } @what; + if ( $what[0] =~ m/CREATE/ || ($what[1] && $what[1] =~ m/STATUS/) ) { + return "SHOW $what[0] $what[1]"; + } + else { + return "SHOW $what[0]"; + } + } + + eval $QueryParser::data_def_stmts; + eval $QueryParser::tbl_ident; + my ( $dds ) = $query =~ /^\s*($QueryParser::data_def_stmts)\b/i; + if ( $dds ) { + my ( $obj ) = $query =~ m/$dds.+(DATABASE|TABLE)\b/i; + $obj = uc $obj if $obj; + MKDEBUG && _d('Data def statment:', $dds, 'obj:', $obj); + my ($db_or_tbl) + = $query =~ m/(?:TABLE|DATABASE)\s+($QueryParser::tbl_ident)(\s+.*)?/i; + MKDEBUG && _d('Matches db or table:', $db_or_tbl); + return uc($dds . ($obj ? " $obj" : '')), $db_or_tbl; + } + + my @verbs = $query =~ m/\b($verbs)\b/gio; + @verbs = do { + my $last = ''; + grep { my $pass = $_ ne $last; $last = $_; $pass } map { uc } @verbs; + }; + my $verbs = join(q{ }, @verbs); + $verbs =~ s/( UNION SELECT)+/ UNION/g; + + return $verbs; +} + +sub _distill_tables { + my ( $self, $query, $table, %args ) = @_; + my $qp = $args{QueryParser} || $self->{QueryParser}; + die "I need a QueryParser argument" unless $qp; + + my @tables = map { + $_ =~ s/`//g; + $_ =~ s/(_?)[0-9]+/$1?/g; + $_; + } grep { defined $_ } $qp->get_tables($query); + + push @tables, $table if $table; + + @tables = do { + my $last = ''; + grep { my $pass = $_ ne $last; $last = $_; $pass } @tables; + }; + + return @tables; +} + +sub distill { + my ( $self, $query, %args ) = @_; + + if ( $args{generic} ) { + my ($cmd, $arg) = $query =~ m/^(\S+)\s+(\S+)/; + return '' unless $cmd; + $query = (uc $cmd) . ($arg ? " $arg" : ''); + } + else { + my ($verbs, $table) = $self->_distill_verbs($query, %args); + my @tables = $self->_distill_tables($query, $table, %args); + $query = join(q{ }, $verbs, @tables); + } + + if ( $args{trf} ) { + $query = $args{trf}->($query, %args); + } + + return $query; +} + +sub convert_to_select { + my ( $self, $query ) = @_; + return unless $query; + $query =~ s{ + \A.*? + update\s+(.*?) + \s+set\b(.*?) + (?:\s*where\b(.*?))? + (limit\s*[0-9]+(?:\s*,\s*[0-9]+)?)? + \Z + } + {__update_to_select($1, $2, $3, $4)}exsi + || $query =~ s{ + \A.*? + (?:insert|replace)\s+ + .*?\binto\b(.*?)\(([^\)]+)\)\s* + values?\s*(\(.*?\))\s* + (?:\blimit\b|on\s*duplicate\s*key.*)?\s* + \Z + } + {__insert_to_select($1, $2, $3)}exsi + || $query =~ s{ + \A.*? + delete\s+(.*?) + \bfrom\b(.*) + \Z + } + {__delete_to_select($1, $2)}exsi; + $query =~ s/\s*on\s+duplicate\s+key\s+update.*\Z//si; + $query =~ s/\A.*?(?=\bSELECT\s*\b)//ism; + return $query; +} + +sub convert_select_list { + my ( $self, $query ) = @_; + $query =~ s{ + \A\s*select(.*?)\bfrom\b + } + {$1 =~ m/\*/ ? "select 1 from" : "select isnull(coalesce($1)) from"}exi; + return $query; +} + +sub __delete_to_select { + my ( $delete, $join ) = @_; + if ( $join =~ m/\bjoin\b/ ) { + return "select 1 from $join"; + } + return "select * from $join"; +} + +sub __insert_to_select { + my ( $tbl, $cols, $vals ) = @_; + MKDEBUG && _d('Args:', @_); + my @cols = split(/,/, $cols); + MKDEBUG && _d('Cols:', @cols); + $vals =~ s/^\(|\)$//g; # Strip leading/trailing parens + my @vals = $vals =~ m/($quote_re|[^,]*${bal}[^,]*|[^,]+)/g; + MKDEBUG && _d('Vals:', @vals); + if ( @cols == @vals ) { + return "select * from $tbl where " + . join(' and ', map { "$cols[$_]=$vals[$_]" } (0..$#cols)); + } + else { + return "select * from $tbl limit 1"; + } +} + +sub __update_to_select { + my ( $from, $set, $where, $limit ) = @_; + return "select $set from $from " + . ( $where ? "where $where" : '' ) + . ( $limit ? " $limit " : '' ); +} + +sub wrap_in_derived { + my ( $self, $query ) = @_; + return unless $query; + return $query =~ m/\A\s*select/i + ? "select 1 from ($query) as x limit 1" + : $query; +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +1; + +# ########################################################################### +# End QueryRewriter package +# ########################################################################### + +# ########################################################################### +# Processlist package 5148 +# ########################################################################### +package Processlist; + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); + +use Data::Dumper; +$Data::Dumper::Indent = 1; +$Data::Dumper::Sortkeys = 1; +$Data::Dumper::Quotekeys = 0; + +use constant MKDEBUG => $ENV{MKDEBUG}; +use constant { + ID => 0, + USER => 1, + HOST => 2, + DB => 3, + COMMAND => 4, + TIME => 5, + STATE => 6, + INFO => 7, + START => 8, # Calculated start time of statement + ETIME => 9, # Exec time of SHOW PROCESSLIST (margin of error in START) + FSEEN => 10, # First time ever seen +}; + +sub new { + my ( $class, %args ) = @_; + my $self = { + prev_rows => [], + new_rows => [], + curr_row => undef, + prev_row => undef, + }; + return bless $self, $class; +} + +sub parse_event { + my ( $self, %args ) = @_; + my @required_args = qw(misc); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my ($misc) = @args{@required_args}; + + my $code = $misc->{code}; + die "I need a code arg to misc" unless $code; + + my @curr; + if ( $self->{curr_rows} ) { + MKDEBUG && _d('Current rows from last call'); + @curr = @{$self->{curr_rows}}; + } + else { + my $rows = $code->(); + if ( $rows && scalar @$rows ) { + MKDEBUG && _d('Got new current rows'); + @curr = sort { $a->[ID] <=> $b->[ID] } @$rows; + } + else { + MKDEBUG && _d('No current rows'); + } + } + + my @prev = @{$self->{prev_rows} ||= []}; + my @new = @{$self->{new_rows} ||= []};; # Becomes next invocation's @prev + my $curr = $self->{curr_row}; # Rows from each source + my $prev = $self->{prev_row}; + my $event; + + MKDEBUG && _d('Rows:', scalar @prev, 'prev,', scalar @curr, 'current'); + + if ( !$curr && @curr ) { + MKDEBUG && _d('Fetching row from curr'); + $curr = shift @curr; + } + if ( !$prev && @prev ) { + MKDEBUG && _d('Fetching row from prev'); + $prev = shift @prev; + } + if ( $curr || $prev ) { + if ( $curr && $prev && $curr->[ID] == $prev->[ID] ) { + MKDEBUG && _d('$curr and $prev are the same cxn'); + my $fudge = $curr->[TIME] =~ m/\D/ ? 0.001 : 1; # Micro-precision? + my $is_new = 0; + if ( $prev->[INFO] ) { + if (!$curr->[INFO] || $prev->[INFO] ne $curr->[INFO]) { + MKDEBUG && _d('$curr has a new query'); + $is_new = 1; + } + elsif (defined $curr->[TIME] && $curr->[TIME] < $prev->[TIME]) { + MKDEBUG && _d('$curr time is less than $prev time'); + $is_new = 1; + } + elsif ( $curr->[INFO] && defined $curr->[TIME] + && $misc->{time} - $curr->[TIME] - $prev->[START] + - $prev->[ETIME] - $misc->{etime} > $fudge + ) { + MKDEBUG && _d('$curr has same query that restarted'); + $is_new = 1; + } + if ( $is_new ) { + $event = $self->make_event($prev, $misc->{time}); + } + } + if ( $curr->[INFO] ) { + if ( $prev->[INFO] && !$is_new ) { + MKDEBUG && _d('Pushing old history item back onto $prev'); + push @new, [ @$prev ]; + } + else { + MKDEBUG && _d('Pushing new history item onto $prev'); + push @new, + [ @$curr, int($misc->{time} - $curr->[TIME]), + $misc->{etime}, $misc->{time} ]; + } + } + $curr = $prev = undef; # Fetch another from each. + } + elsif ( !$curr + || ($curr && $prev && $curr->[ID] > $prev->[ID]) ) { + MKDEBUG && _d('$curr is not in $prev'); + $event = $self->make_event($prev, $misc->{time}); + $prev = undef; + } + else { # This else must be entered, to prevent infinite loops. + MKDEBUG && _d('$prev is not in $curr'); + if ( $curr->[INFO] && defined $curr->[TIME] ) { + MKDEBUG && _d('Pushing new history item onto $prev'); + push @new, + [ @$curr, int($misc->{time} - $curr->[TIME]), + $misc->{etime}, $misc->{time} ]; + } + $curr = undef; # No infinite loops. + } + } + + $self->{prev_rows} = \@new; + $self->{prev_row} = $prev; + $self->{curr_rows} = scalar @curr ? \@curr : undef; + $self->{curr_row} = $curr; + + return $event; +} + +sub make_event { + my ( $self, $row, $time ) = @_; + my $Query_time = $row->[TIME]; + if ( $row->[TIME] < $time - $row->[FSEEN] ) { + $Query_time = $time - $row->[FSEEN]; + } + my $event = { + id => $row->[ID], + db => $row->[DB], + user => $row->[USER], + host => $row->[HOST], + arg => $row->[INFO], + bytes => length($row->[INFO]), + ts => Transformers::ts($row->[START] + $row->[TIME]), # Query END time + Query_time => $Query_time, + Lock_time => 0, # TODO + }; + MKDEBUG && _d('Properties of event:', Dumper($event)); + return $event; +} + +sub _get_rows { + my ( $self ) = @_; + my %rows = map { $_ => $self->{$_} } + qw(prev_rows new_rows curr_row prev_row); + return \%rows; +} + +sub find { + my ( $self, $proclist, %find_spec ) = @_; + MKDEBUG && _d('find specs:', Dumper(\%find_spec)); + my @matches; + QUERY: + foreach my $query ( @$proclist ) { + MKDEBUG && _d('Checking query', Dumper($query)); + my $matched = 0; + + if ( $find_spec{busy_time} && ($query->{Command} || '') eq 'Query' ) { + if ( $query->{Time} < $find_spec{busy_time} ) { + MKDEBUG && _d("Query isn't running long enough"); + next QUERY; + } + MKDEBUG && _d('Exceeds busy time'); + $matched++; + } + + if ( $find_spec{idle_time} && ($query->{Command} || '') eq 'Sleep' ) { + if ( $query->{Time} < $find_spec{idle_time} ) { + MKDEBUG && _d("Query isn't idle long enough"); + next QUERY; + } + MKDEBUG && _d('Exceeds idle time'); + $matched++; + } + + PROPERTY: + foreach my $property ( qw(Id User Host db State Command Info) ) { + my $filter = "_find_match_$property"; + if ( defined $find_spec{ignore}->{$property} + && $self->$filter($query, $find_spec{ignore}->{$property}) ) { + MKDEBUG && _d('Query matches ignore', $property, 'spec'); + next QUERY; + } + if ( defined $find_spec{match}->{$property} ) { + if ( !$self->$filter($query, $find_spec{match}->{$property}) ) { + MKDEBUG && _d('Query does not match', $property, 'spec'); + next QUERY; + } + MKDEBUG && _d('Query matches', $property, 'spec'); + $matched++; + } + } + if ( $matched ) { + MKDEBUG && _d("Query matched one or more specs, adding"); + push @matches, $query; + next QUERY; + } + MKDEBUG && _d('Query does not match any specs, ignoring'); + } # QUERY + + if ( @matches && $find_spec{only_oldest} ) { + my ( $oldest ) = reverse sort { $a->{Time} <=> $b->{Time} } @matches; + MKDEBUG && _d('Oldest query:', Dumper($oldest)); + @matches = $oldest; + } + + return @matches; +} + +sub _find_match_Id { + my ( $self, $query, $property ) = @_; + return defined $property && defined $query->{Id} && $query->{Id} == $property; +} + +sub _find_match_User { + my ( $self, $query, $property ) = @_; + return defined $property && defined $query->{User} + && $query->{User} =~ m/$property/; +} + +sub _find_match_Host { + my ( $self, $query, $property ) = @_; + return defined $property && defined $query->{Host} + && $query->{Host} =~ m/$property/; +} + +sub _find_match_db { + my ( $self, $query, $property ) = @_; + return defined $property && defined $query->{db} + && $query->{db} =~ m/$property/; +} + +sub _find_match_State { + my ( $self, $query, $property ) = @_; + return defined $property && defined $query->{State} + && $query->{State} =~ m/$property/; +} + +sub _find_match_Command { + my ( $self, $query, $property ) = @_; + return defined $property && defined $query->{Command} + && $query->{Command} =~ m/$property/; +} + +sub _find_match_Info { + my ( $self, $query, $property ) = @_; + return defined $property && defined $query->{Info} + && $query->{Info} =~ m/$property/; +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +1; + +# ########################################################################### +# End Processlist package +# ########################################################################### + +# ########################################################################### +# TcpdumpParser package 5155 +# ########################################################################### +package TcpdumpParser; + + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); +use Data::Dumper; +$Data::Dumper::Indent = 1; +$Data::Dumper::Sortkeys = 1; + +use constant MKDEBUG => $ENV{MKDEBUG}; + +sub new { + my ( $class, %args ) = @_; + my $self = {}; + return bless $self, $class; +} + +sub parse_event { + my ( $self, %args ) = @_; + my @required_args = qw(fh); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my $fh = @args{@required_args}; + + if ( !$fh ) { + MKDEBUG && _d('No filehandle'); + return; + } + + local $INPUT_RECORD_SEPARATOR = "\n20"; + + my $pos_in_log = tell($fh); + while ( defined(my $raw_packet = <$fh>) ) { + next if $raw_packet =~ m/^$/; # issue 564 + $pos_in_log -= 1 if $pos_in_log; + + $raw_packet =~ s/\n20\Z//; + $raw_packet = "20$raw_packet" unless $raw_packet =~ m/\A20/; + + my $packet = $self->_parse_packet($raw_packet); + $packet->{pos_in_log} = $pos_in_log; + $packet->{raw_packet} = $raw_packet; + + return $packet; + } + + $args{oktorun}->(0) if $args{oktorun}; + return; +} + +sub _parse_packet { + my ( $self, $packet ) = @_; + die "I need a packet" unless $packet; + + my ( $ts, $source, $dest ) = $packet =~ m/\A(\S+ \S+) IP .*?(\S+) > (\S+):/; + my ( $src_host, $src_port ) = $source =~ m/((?:\d+\.){3}\d+)\.(\w+)/; + my ( $dst_host, $dst_port ) = $dest =~ m/((?:\d+\.){3}\d+)\.(\w+)/; + + $src_port = $self->port_number($src_port); + $dst_port = $self->port_number($dst_port); + + my $hex = qr/[0-9a-f]/; + (my $data = join('', $packet =~ m/\s+0x$hex+:\s((?:\s$hex{2,4})+)/go)) =~ s/\s+//g; + + my $ip_hlen = hex(substr($data, 1, 1)); # Num of 32-bit words in header. + my $ip_plen = hex(substr($data, 4, 4)); # Num of BYTES in IPv4 datagram. + my $complete = length($data) == 2 * $ip_plen ? 1 : 0; + + my $tcp_hlen = hex(substr($data, ($ip_hlen + 3) * 8, 1)); + + my $seq = hex(substr($data, ($ip_hlen + 1) * 8, 8)); + my $ack = hex(substr($data, ($ip_hlen + 2) * 8, 8)); + + my $flags = hex(substr($data, (($ip_hlen + 3) * 8) + 2, 2)); + + $data = substr($data, ($ip_hlen + $tcp_hlen) * 8); + + my $pkt = { + ts => $ts, + seq => $seq, + ack => $ack, + fin => $flags & 0x01, + syn => $flags & 0x02, + rst => $flags & 0x04, + src_host => $src_host, + src_port => $src_port, + dst_host => $dst_host, + dst_port => $dst_port, + complete => $complete, + ip_hlen => $ip_hlen, + tcp_hlen => $tcp_hlen, + dgram_len => $ip_plen, + data_len => $ip_plen - (($ip_hlen + $tcp_hlen) * 4), + data => $data ? substr($data, 0, 8).(length $data > 8 ? '...' : '') + : '', + }; + MKDEBUG && _d('packet:', Dumper($pkt)); + $pkt->{data} = $data; + return $pkt; +} + +sub port_number { + my ( $self, $port ) = @_; + return unless $port; + return $port eq 'memcached' ? 11211 + : $port eq 'http' ? 80 + : $port eq 'mysql' ? 3306 + : $port; +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +1; + +# ########################################################################### +# End TcpdumpParser package +# ########################################################################### + +# ########################################################################### +# MySQLProtocolParser package 5178 +# ########################################################################### +package MySQLProtocolParser; + + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); + +eval { + require IO::Uncompress::Inflate; + IO::Uncompress::Inflate->import(qw(inflate $InflateError)); +}; + +use Data::Dumper; +$Data::Dumper::Indent = 1; +$Data::Dumper::Sortkeys = 1; +$Data::Dumper::Quotekeys = 0; + +require Exporter; +our @ISA = qw(Exporter); +our %EXPORT_TAGS = (); +our @EXPORT = (); +our @EXPORT_OK = qw( + parse_error_packet + parse_ok_packet + parse_server_handshake_packet + parse_client_handshake_packet + parse_com_packet + parse_flags +); + +use constant MKDEBUG => $ENV{MKDEBUG}; +use constant { + COM_SLEEP => '00', + COM_QUIT => '01', + COM_INIT_DB => '02', + COM_QUERY => '03', + COM_FIELD_LIST => '04', + COM_CREATE_DB => '05', + COM_DROP_DB => '06', + COM_REFRESH => '07', + COM_SHUTDOWN => '08', + COM_STATISTICS => '09', + COM_PROCESS_INFO => '0a', + COM_CONNECT => '0b', + COM_PROCESS_KILL => '0c', + COM_DEBUG => '0d', + COM_PING => '0e', + COM_TIME => '0f', + COM_DELAYED_INSERT => '10', + COM_CHANGE_USER => '11', + COM_BINLOG_DUMP => '12', + COM_TABLE_DUMP => '13', + COM_CONNECT_OUT => '14', + COM_REGISTER_SLAVE => '15', + COM_STMT_PREPARE => '16', + COM_STMT_EXECUTE => '17', + COM_STMT_SEND_LONG_DATA => '18', + COM_STMT_CLOSE => '19', + COM_STMT_RESET => '1a', + COM_SET_OPTION => '1b', + COM_STMT_FETCH => '1c', + SERVER_QUERY_NO_GOOD_INDEX_USED => 16, + SERVER_QUERY_NO_INDEX_USED => 32, +}; + +my %com_for = ( + '00' => 'COM_SLEEP', + '01' => 'COM_QUIT', + '02' => 'COM_INIT_DB', + '03' => 'COM_QUERY', + '04' => 'COM_FIELD_LIST', + '05' => 'COM_CREATE_DB', + '06' => 'COM_DROP_DB', + '07' => 'COM_REFRESH', + '08' => 'COM_SHUTDOWN', + '09' => 'COM_STATISTICS', + '0a' => 'COM_PROCESS_INFO', + '0b' => 'COM_CONNECT', + '0c' => 'COM_PROCESS_KILL', + '0d' => 'COM_DEBUG', + '0e' => 'COM_PING', + '0f' => 'COM_TIME', + '10' => 'COM_DELAYED_INSERT', + '11' => 'COM_CHANGE_USER', + '12' => 'COM_BINLOG_DUMP', + '13' => 'COM_TABLE_DUMP', + '14' => 'COM_CONNECT_OUT', + '15' => 'COM_REGISTER_SLAVE', + '16' => 'COM_STMT_PREPARE', + '17' => 'COM_STMT_EXECUTE', + '18' => 'COM_STMT_SEND_LONG_DATA', + '19' => 'COM_STMT_CLOSE', + '1a' => 'COM_STMT_RESET', + '1b' => 'COM_SET_OPTION', + '1c' => 'COM_STMT_FETCH', +); + +my %flag_for = ( + 'CLIENT_LONG_PASSWORD' => 1, # new more secure passwords + 'CLIENT_FOUND_ROWS' => 2, # Found instead of affected rows + 'CLIENT_LONG_FLAG' => 4, # Get all column flags + 'CLIENT_CONNECT_WITH_DB' => 8, # One can specify db on connect + 'CLIENT_NO_SCHEMA' => 16, # Don't allow database.table.column + 'CLIENT_COMPRESS' => 32, # Can use compression protocol + 'CLIENT_ODBC' => 64, # Odbc client + 'CLIENT_LOCAL_FILES' => 128, # Can use LOAD DATA LOCAL + 'CLIENT_IGNORE_SPACE' => 256, # Ignore spaces before '(' + 'CLIENT_PROTOCOL_41' => 512, # New 4.1 protocol + 'CLIENT_INTERACTIVE' => 1024, # This is an interactive client + 'CLIENT_SSL' => 2048, # Switch to SSL after handshake + 'CLIENT_IGNORE_SIGPIPE' => 4096, # IGNORE sigpipes + 'CLIENT_TRANSACTIONS' => 8192, # Client knows about transactions + 'CLIENT_RESERVED' => 16384, # Old flag for 4.1 protocol + 'CLIENT_SECURE_CONNECTION' => 32768, # New 4.1 authentication + 'CLIENT_MULTI_STATEMENTS' => 65536, # Enable/disable multi-stmt support + 'CLIENT_MULTI_RESULTS' => 131072, # Enable/disable multi-results +); + +sub new { + my ( $class, %args ) = @_; + + my ( $server_port ) + = $args{server} ? $args{server} =~ m/:(\w+)/ : ('3306|mysql'); + $server_port ||= '3306|mysql'; # In case $args{server} doesn't have a port. + + my $self = { + server => $args{server}, + server_port => $server_port, + version => '41', # MySQL proto version; not used yet + sessions => {}, + o => $args{o}, + fake_thread_id => 2**32, # see _make_event() + }; + MKDEBUG && $self->{server} && _d('Watching only server', $self->{server}); + return bless $self, $class; +} + +sub parse_event { + my ( $self, %args ) = @_; + my @required_args = qw(event); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my $packet = @args{@required_args}; + + my $src_host = "$packet->{src_host}:$packet->{src_port}"; + my $dst_host = "$packet->{dst_host}:$packet->{dst_port}"; + + if ( my $server = $self->{server} ) { # Watch only the given server. + if ( $src_host ne $server && $dst_host ne $server ) { + MKDEBUG && _d('Packet is not to or from', $server); + return; + } + } + + my $packet_from; + my $client; + if ( $src_host =~ m/:$self->{server_port}$/ ) { + $packet_from = 'server'; + $client = $dst_host; + } + elsif ( $dst_host =~ m/:$self->{server_port}$/ ) { + $packet_from = 'client'; + $client = $src_host; + } + else { + MKDEBUG && _d('Packet is not to or from a MySQL server'); + return; + } + MKDEBUG && _d('Client:', $client); + + if ( !exists $self->{sessions}->{$client} ) { + MKDEBUG && _d('New session'); + $self->{sessions}->{$client} = { + client => $client, + ts => $packet->{ts}, + state => undef, + compress => undef, + raw_packets => [], + buff => '', + }; + }; + my $session = $self->{sessions}->{$client}; + + if ( $packet->{data_len} == 0 ) { + MKDEBUG && _d('No TCP/MySQL data'); + if ( ($session->{state} || '') eq 'closing' ) { + delete $self->{sessions}->{$session->{client}}; + MKDEBUG && _d('Session deleted'); + } + return; + } + + push @{$session->{raw_packets}}, $packet->{raw_packet}; + + if ( $session->{compress} ) { + return unless $self->uncompress_packet($packet, $session); + } + + if ( $session->{buff} && $packet_from eq 'client' ) { + $packet->{data} = $session->{buff} . $packet->{data}; + $session->{buff_left} -= $packet->{data_len}; + + $packet->{mysql_data_len} = $session->{mysql_data_len}; + + MKDEBUG && _d('Appending data to buff; expecting', + $session->{buff_left}, 'more bytes'); + } + else { + eval { + remove_mysql_header($packet); + }; + if ( $EVAL_ERROR ) { + MKDEBUG && _d('remove_mysql_header() failed; failing session'); + $session->{EVAL_ERROR} = $EVAL_ERROR; + $self->fail_session($session, 'remove_mysql_header() failed'); + return; + } + } + + my $event; + if ( $packet_from eq 'server' ) { + $event = $self->_packet_from_server($packet, $session, $args{misc}); + } + elsif ( $packet_from eq 'client' ) { + if ( $session->{buff} && $session->{buff_left} <= 0 ) { + MKDEBUG && _d('Data is complete'); + } + elsif ( $packet->{mysql_data_len} > $packet->{data_len} ) { + $session->{mysql_data_len} = $packet->{mysql_data_len}; + $session->{buff} = $packet->{data}; + + $session->{buff_left} + ||= $packet->{mysql_data_len} - $packet->{data_len}; + + MKDEBUG && _d('Data not complete; expecting', + $session->{buff_left}, 'more bytes'); + return; + } + $event = $self->_packet_from_client($packet, $session, $args{misc}); + + $session->{buff} = ''; + $session->{buff_left} = 0; + $session->{mysql_data_len} = 0; + } + else { + die 'Packet origin unknown'; + } + + MKDEBUG && _d('Done parsing packet; client state:', $session->{state}); + return $event; +} + +sub _packet_from_server { + my ( $self, $packet, $session, $misc ) = @_; + die "I need a packet" unless $packet; + die "I need a session" unless $session; + + MKDEBUG && _d('Packet is from server; client state:', $session->{state}); + + if ( ($session->{server_seq} || '') eq $packet->{seq} ) { + push @{ $session->{server_retransmissions} }, $packet->{seq}; + MKDEBUG && _d('TCP retransmission'); + return; + } + $session->{server_seq} = $packet->{seq}; + + my $data = $packet->{data}; + + + my ( $first_byte ) = substr($data, 0, 2, ''); + MKDEBUG && _d('First byte of packet:', $first_byte); + if ( !$first_byte ) { + $self->fail_session($session, 'no first byte'); + return; + } + + if ( !$session->{state} ) { + if ( $first_byte eq '0a' && length $data >= 33 && $data =~ m/00{13}/ ) { + my $handshake = parse_server_handshake_packet($data); + if ( !$handshake ) { + $self->fail_session($session, 'failed to parse server handshake'); + return; + } + $session->{state} = 'server_handshake'; + $session->{thread_id} = $handshake->{thread_id}; + } + else { + MKDEBUG && _d('Ignoring mid-stream server response'); + return; + } + } + else { + if ( $first_byte eq '00' ) { + if ( ($session->{state} || '') eq 'client_auth' ) { + + $session->{compress} = $session->{will_compress}; + delete $session->{will_compress}; + MKDEBUG && $session->{compress} && _d('Packets will be compressed'); + + MKDEBUG && _d('Admin command: Connect'); + return $self->_make_event( + { cmd => 'Admin', + arg => 'administrator command: Connect', + ts => $packet->{ts}, # Events are timestamped when they end + }, + $packet, $session + ); + } + elsif ( $session->{cmd} ) { + my $ok = parse_ok_packet($data); + if ( !$ok ) { + $self->fail_session($session, 'failed to parse OK packet'); + return; + } + my $com = $session->{cmd}->{cmd}; + my $arg; + + if ( $com eq COM_QUERY ) { + $com = 'Query'; + $arg = $session->{cmd}->{arg}; + } + else { + $arg = 'administrator command: ' + . ucfirst(lc(substr($com_for{$com}, 4))); + $com = 'Admin'; + } + + return $self->_make_event( + { cmd => $com, + arg => $arg, + ts => $packet->{ts}, + Insert_id => $ok->{insert_id}, + Warning_count => $ok->{warnings}, + Rows_affected => $ok->{affected_rows}, + }, + $packet, $session + ); + } + else { + MKDEBUG && _d('Looks like an OK packet but session has no cmd'); + } + } + elsif ( $first_byte eq 'ff' ) { + my $error = parse_error_packet($data); + if ( !$error ) { + $self->fail_session($session, 'failed to parse error packet'); + return; + } + my $event; + + if ( $session->{state} eq 'client_auth' ) { + MKDEBUG && _d('Connection failed'); + $event = { + cmd => 'Admin', + arg => 'administrator command: Connect', + ts => $packet->{ts}, + Error_no => $error->{errno} ? "#$error->{errno}" : 'none', + }; + return $self->_make_event($event, $packet, $session); + $session->{state} = 'closing'; + } + elsif ( $session->{cmd} ) { + my $com = $session->{cmd}->{cmd}; + my $arg; + + if ( $com eq COM_QUERY ) { + $com = 'Query'; + $arg = $session->{cmd}->{arg}; + } + else { + $arg = 'administrator command: ' + . ucfirst(lc(substr($com_for{$com}, 4))); + $com = 'Admin'; + } + + $event = { + cmd => $com, + arg => $arg, + ts => $packet->{ts}, + Error_no => $error->{errno} ? "#$error->{errno}" : 'none', + }; + return $self->_make_event($event, $packet, $session); + } + else { + MKDEBUG && _d('Looks like an error packet but client is not ' + . 'authenticating and session has no cmd'); + } + } + elsif ( $first_byte eq 'fe' && $packet->{mysql_data_len} < 9 ) { + if ( $packet->{mysql_data_len} == 1 + && $session->{state} eq 'client_auth' + && $packet->{number} == 2 ) + { + MKDEBUG && _d('Server has old password table;', + 'client will resend password using old algorithm'); + $session->{state} = 'client_auth_resend'; + } + else { + MKDEBUG && _d('Got an EOF packet'); + $self->fail_session($session, 'got an unexpected EOF packet'); + } + } + else { + if ( $session->{cmd} ) { + MKDEBUG && _d('Got a row/field/result packet'); + my $com = $session->{cmd}->{cmd}; + MKDEBUG && _d('Responding to client', $com_for{$com}); + my $event = { ts => $packet->{ts} }; + if ( $com eq COM_QUERY ) { + $event->{cmd} = 'Query'; + $event->{arg} = $session->{cmd}->{arg}; + } + else { + $event->{arg} = 'administrator command: ' + . ucfirst(lc(substr($com_for{$com}, 4))); + $event->{cmd} = 'Admin'; + } + + if ( $packet->{complete} ) { + my ( $warning_count, $status_flags ) + = $data =~ m/fe(.{4})(.{4})\Z/; + if ( $warning_count ) { + $event->{Warnings} = to_num($warning_count); + my $flags = to_num($status_flags); # TODO set all flags? + $event->{No_good_index_used} + = $flags & SERVER_QUERY_NO_GOOD_INDEX_USED ? 1 : 0; + $event->{No_index_used} + = $flags & SERVER_QUERY_NO_INDEX_USED ? 1 : 0; + } + } + + return $self->_make_event($event, $packet, $session); + } + else { + MKDEBUG && _d('Unknown in-stream server response'); + } + } + } + + return; +} + +sub _packet_from_client { + my ( $self, $packet, $session, $misc ) = @_; + die "I need a packet" unless $packet; + die "I need a session" unless $session; + + MKDEBUG && _d('Packet is from client; state:', $session->{state}); + + if ( ($session->{client_seq} || '') eq $packet->{seq} ) { + push @{ $session->{client_retransmissions} }, $packet->{seq}; + MKDEBUG && _d('TCP retransmission'); + return; + } + $session->{client_seq} = $packet->{seq}; + + my $data = $packet->{data}; + my $ts = $packet->{ts}; + + if ( ($session->{state} || '') eq 'server_handshake' ) { + MKDEBUG && _d('Expecting client authentication packet'); + my $handshake = parse_client_handshake_packet($data); + if ( !$handshake ) { + $self->fail_session($session, 'failed to parse client handshake'); + return; + } + $session->{state} = 'client_auth'; + $session->{pos_in_log} = $packet->{pos_in_log}; + $session->{user} = $handshake->{user}; + $session->{db} = $handshake->{db}; + + $session->{will_compress} = $handshake->{flags}->{CLIENT_COMPRESS}; + } + elsif ( ($session->{state} || '') eq 'client_auth_resend' ) { + MKDEBUG && _d('Client resending password using old algorithm'); + $session->{state} = 'client_auth'; + } + elsif ( ($session->{state} || '') eq 'awaiting_reply' ) { + my $arg = $session->{cmd}->{arg} ? substr($session->{cmd}->{arg}, 0, 50) + : 'unknown'; + MKDEBUG && _d('More data for previous command:', $arg, '...'); + return; + } + else { + + if ( !defined $session->{compress} ) { + return unless $self->detect_compression($packet, $session); + $data = $packet->{data}; + } + + my $com = parse_com_packet($data, $packet->{mysql_data_len}); + if ( !$com ) { + $self->fail_session($session, 'failed to parse COM packet'); + return; + } + $session->{state} = 'awaiting_reply'; + $session->{pos_in_log} = $packet->{pos_in_log}; + $session->{ts} = $ts; + $session->{cmd} = { + cmd => $com->{code}, + arg => $com->{data}, + }; + + if ( $com->{code} eq COM_QUIT ) { # Fire right away; will cleanup later. + MKDEBUG && _d('Got a COM_QUIT'); + return $self->_make_event( + { cmd => 'Admin', + arg => 'administrator command: Quit', + ts => $ts, + }, + $packet, $session + ); + $session->{state} = 'closing'; + } + } + + return; +} + +sub _make_event { + my ( $self, $event, $packet, $session ) = @_; + MKDEBUG && _d('Making event'); + + $session->{raw_packets} = []; + + if ( !$session->{thread_id} ) { + MKDEBUG && _d('Giving session fake thread id', $self->{fake_thread_id}); + $session->{thread_id} = $self->{fake_thread_id}++; + } + + my ($host, $port) = $session->{client} =~ m/((?:\d+\.){3}\d+)\:(\w+)/; + my $new_event = { + cmd => $event->{cmd}, + arg => $event->{arg}, + bytes => length( $event->{arg} ), + ts => tcp_timestamp( $event->{ts} ), + host => $host, + ip => $host, + port => $port, + db => $session->{db}, + user => $session->{user}, + Thread_id => $session->{thread_id}, + pos_in_log => $session->{pos_in_log}, + Query_time => timestamp_diff($session->{ts}, $packet->{ts}), + Error_no => $event->{Error_no} || 'none', + Rows_affected => ($event->{Rows_affected} || 0), + Warning_count => ($event->{Warning_count} || 0), + No_good_index_used => ($event->{No_good_index_used} ? 'Yes' : 'No'), + No_index_used => ($event->{No_index_used} ? 'Yes' : 'No'), + }; + MKDEBUG && _d('Properties of event:', Dumper($new_event)); + + delete $session->{cmd}; + + $session->{state} = undef; + + return $new_event; +} + +sub tcp_timestamp { + my ( $ts ) = @_; + $ts =~ s/^\d\d(\d\d)-(\d\d)-(\d\d)/$1$2$3/; + return $ts; +} + +sub timestamp_diff { + my ( $start, $end ) = @_; + my $sd = substr($start, 0, 11, ''); + my $ed = substr($end, 0, 11, ''); + my ( $sh, $sm, $ss ) = split(/:/, $start); + my ( $eh, $em, $es ) = split(/:/, $end); + my $esecs = ($eh * 3600 + $em * 60 + $es); + my $ssecs = ($sh * 3600 + $sm * 60 + $ss); + if ( $sd eq $ed ) { + return sprintf '%.6f', $esecs - $ssecs; + } + else { # Assume only one day boundary has been crossed, no DST, etc + return sprintf '%.6f', ( 86_400 - $ssecs ) + $esecs; + } +} + +sub to_string { + my ( $data ) = @_; + $data = pack('H*', $data); + return $data; +} + +sub to_num { + my ( $str ) = @_; + my @bytes = $str =~ m/(..)/g; + my $result = 0; + foreach my $i ( 0 .. $#bytes ) { + $result += hex($bytes[$i]) * (16 ** ($i * 2)); + } + return $result; +} + +sub get_lcb { + my ( $string ) = @_; + my $first_byte = hex(substr($$string, 0, 2, '')); + if ( $first_byte < 251 ) { + return $first_byte; + } + elsif ( $first_byte == 252 ) { + return to_num(substr($$string, 0, 4, '')); + } + elsif ( $first_byte == 253 ) { + return to_num(substr($$string, 0, 6, '')); + } + elsif ( $first_byte == 254 ) { + return to_num(substr($$string, 0, 16, '')); + } +} + +sub parse_error_packet { + my ( $data ) = @_; + return unless $data; + MKDEBUG && _d('ERROR data:', $data); + if ( length $data < 16 ) { + MKDEBUG && _d('Error packet is too short:', $data); + return; + } + my $errno = to_num(substr($data, 0, 4)); + my $marker = to_string(substr($data, 4, 2)); + return unless $marker eq '#'; + my $sqlstate = to_string(substr($data, 6, 10)); + my $message = to_string(substr($data, 16)); + my $pkt = { + errno => $errno, + sqlstate => $marker . $sqlstate, + message => $message, + }; + MKDEBUG && _d('Error packet:', Dumper($pkt)); + return $pkt; +} + +sub parse_ok_packet { + my ( $data ) = @_; + return unless $data; + MKDEBUG && _d('OK data:', $data); + if ( length $data < 12 ) { + MKDEBUG && _d('OK packet is too short:', $data); + return; + } + my $affected_rows = get_lcb(\$data); + my $insert_id = get_lcb(\$data); + my $status = to_num(substr($data, 0, 4, '')); + my $warnings = to_num(substr($data, 0, 4, '')); + my $message = to_string($data); + my $pkt = { + affected_rows => $affected_rows, + insert_id => $insert_id, + status => $status, + warnings => $warnings, + message => $message, + }; + MKDEBUG && _d('OK packet:', Dumper($pkt)); + return $pkt; +} + +sub parse_server_handshake_packet { + my ( $data ) = @_; + return unless $data; + MKDEBUG && _d('Server handshake data:', $data); + my $handshake_pattern = qr{ + ^ # ----- ---- + (.+?)00 # n Null-Term String server_version + (.{8}) # 4 thread_id + .{16} # 8 scramble_buff + .{2} # 1 filler: always 0x00 + (.{4}) # 2 server_capabilities + .{2} # 1 server_language + .{4} # 2 server_status + .{26} # 13 filler: always 0x00 + }x; + my ( $server_version, $thread_id, $flags ) = $data =~ m/$handshake_pattern/; + my $pkt = { + server_version => to_string($server_version), + thread_id => to_num($thread_id), + flags => parse_flags($flags), + }; + MKDEBUG && _d('Server handshake packet:', Dumper($pkt)); + return $pkt; +} + +sub parse_client_handshake_packet { + my ( $data ) = @_; + return unless $data; + MKDEBUG && _d('Client handshake data:', $data); + my ( $flags, $user, $buff_len ) = $data =~ m{ + ^ + (.{8}) # Client flags + .{10} # Max packet size, charset + (?:00){23} # Filler + ((?:..)+?)00 # Null-terminated user name + (..) # Length-coding byte for scramble buff + }x; + + if ( !$buff_len ) { + MKDEBUG && _d('Did not match client handshake packet'); + return; + } + + my $code_len = hex($buff_len); + my ( $db ) = $data =~ m! + ^.{64}${user}00.. # Everything matched before + (?:..){$code_len} # The scramble buffer + (.*)00\Z # The database name + !x; + my $pkt = { + user => to_string($user), + db => $db ? to_string($db) : '', + flags => parse_flags($flags), + }; + MKDEBUG && _d('Client handshake packet:', Dumper($pkt)); + return $pkt; +} + +sub parse_com_packet { + my ( $data, $len ) = @_; + return unless $data && $len; + MKDEBUG && _d('COM data:', + (substr($data, 0, 100).(length $data > 100 ? '...' : '')), + 'len:', $len); + my $code = substr($data, 0, 2); + my $com = $com_for{$code}; + if ( !$com ) { + MKDEBUG && _d('Did not match COM packet'); + return; + } + $data = to_string(substr($data, 2, ($len - 1) * 2)); + my $pkt = { + code => $code, + com => $com, + data => $data, + }; + MKDEBUG && _d('COM packet:', Dumper($pkt)); + return $pkt; +} + +sub parse_flags { + my ( $flags ) = @_; + die "I need flags" unless $flags; + MKDEBUG && _d('Flag data:', $flags); + my %flags = %flag_for; + my $flags_dec = to_num($flags); + foreach my $flag ( keys %flag_for ) { + my $flagno = $flag_for{$flag}; + $flags{$flag} = ($flags_dec & $flagno ? 1 : 0); + } + return \%flags; +} + +sub uncompress_data { + my ( $data, $len ) = @_; + die "I need data" unless $data; + die "I need a len argument" unless $len; + die "I need a scalar reference to data" unless ref $data eq 'SCALAR'; + MKDEBUG && _d('Uncompressing data'); + our $InflateError; + + my $comp_bin_data = pack('H*', $$data); + + my $uncomp_bin_data = ''; + my $z = new IO::Uncompress::Inflate( + \$comp_bin_data + ) or die "IO::Uncompress::Inflate failed: $InflateError"; + my $status = $z->read(\$uncomp_bin_data, $len) + or die "IO::Uncompress::Inflate failed: $InflateError"; + + my $uncomp_data = unpack('H*', $uncomp_bin_data); + + return \$uncomp_data; +} + +sub detect_compression { + my ( $self, $packet, $session ) = @_; + MKDEBUG && _d('Checking for client compression'); + my $com = parse_com_packet($packet->{data}, $packet->{data_len}); + if ( $com && $com->{code} eq COM_SLEEP ) { + MKDEBUG && _d('Client is using compression'); + $session->{compress} = 1; + + $packet->{data} = $packet->{mysql_hdr} . $packet->{data}; + return 0 unless $self->uncompress_packet($packet, $session); + remove_mysql_header($packet); + } + else { + MKDEBUG && _d('Client is NOT using compression'); + $session->{compress} = 0; + } + return 1; +} + +sub uncompress_packet { + my ( $self, $packet, $session ) = @_; + die "I need a packet" unless $packet; + die "I need a session" unless $session; + + + my $data; + my $comp_hdr; + my $comp_data_len; + my $pkt_num; + my $uncomp_data_len; + eval { + $data = \$packet->{data}; + $comp_hdr = substr($$data, 0, 14, ''); + $comp_data_len = to_num(substr($comp_hdr, 0, 6)); + $pkt_num = to_num(substr($comp_hdr, 6, 2)); + $uncomp_data_len = to_num(substr($comp_hdr, 8, 6)); + MKDEBUG && _d('Compression header data:', $comp_hdr, + 'compressed data len (bytes)', $comp_data_len, + 'number', $pkt_num, + 'uncompressed data len (bytes)', $uncomp_data_len); + }; + if ( $EVAL_ERROR ) { + $session->{EVAL_ERROR} = $EVAL_ERROR; + $self->fail_session($session, 'failed to parse compression header'); + return 0; + } + + if ( $uncomp_data_len ) { + eval { + $data = uncompress_data($data, $uncomp_data_len); + $packet->{data} = $$data; + }; + if ( $EVAL_ERROR ) { + $session->{EVAL_ERROR} = $EVAL_ERROR; + $self->fail_session($session, 'failed to uncompress data'); + die "Cannot uncompress packet. Check that IO::Uncompress::Inflate " + . "is installed.\nError: $EVAL_ERROR"; + } + } + else { + MKDEBUG && _d('Packet is not really compressed'); + $packet->{data} = $$data; + } + + return 1; +} + +sub remove_mysql_header { + my ( $packet ) = @_; + die "I need a packet" unless $packet; + + my $mysql_hdr = substr($packet->{data}, 0, 8, ''); + my $mysql_data_len = to_num(substr($mysql_hdr, 0, 6)); + my $pkt_num = to_num(substr($mysql_hdr, 6, 2)); + MKDEBUG && _d('MySQL packet: header data', $mysql_hdr, + 'data len (bytes)', $mysql_data_len, 'number', $pkt_num); + + $packet->{mysql_hdr} = $mysql_hdr; + $packet->{mysql_data_len} = $mysql_data_len; + $packet->{number} = $pkt_num; + + return; +} + +sub _get_errors_fh { + my ( $self ) = @_; + my $errors_fh = $self->{errors_fh}; + return $errors_fh if $errors_fh; + + my $o = $self->{o}; + if ( $o && $o->has('tcpdump-errors') && $o->got('tcpdump-errors') ) { + my $errors_file = $o->get('tcpdump-errors'); + MKDEBUG && _d('tcpdump-errors file:', $errors_file); + open $errors_fh, '>>', $errors_file + or die "Cannot open tcpdump-errors file $errors_file: $OS_ERROR"; + } + + $self->{errors_fh} = $errors_fh; + return $errors_fh; +} + +sub fail_session { + my ( $self, $session, $reason ) = @_; + my $errors_fh = $self->_get_errors_fh(); + if ( $errors_fh ) { + my $raw_packets = $session->{raw_packets}; + delete $session->{raw_packets}; # Don't dump, it's printed below. + $session->{reason_for_failure} = $reason; + my $session_dump = '# ' . Dumper($session); + chomp $session_dump; + $session_dump =~ s/\n/\n# /g; + print $errors_fh "$session_dump\n"; + { + local $LIST_SEPARATOR = "\n"; + print $errors_fh "@$raw_packets"; + print $errors_fh "\n"; + } + } + MKDEBUG && _d('Failed session', $session->{client}, 'because', $reason); + delete $self->{sessions}->{$session->{client}}; + return; +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +1; + +# ########################################################################### +# End MySQLProtocolParser package +# ########################################################################### + +# ########################################################################### +# SlowLogParser package 5133 +# ########################################################################### +package SlowLogParser; + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); +use Data::Dumper; + +use constant MKDEBUG => $ENV{MKDEBUG}; + +sub new { + my ( $class ) = @_; + my $self = { + pending => [], + }; + return bless $self, $class; +} + +my $slow_log_ts_line = qr/^# Time: ([0-9: ]{15})/; +my $slow_log_uh_line = qr/# User\@Host: ([^\[]+|\[[^[]+\]).*?@ (\S*) \[(.*)\]/; +my $slow_log_hd_line = qr{ + ^(?: + T[cC][pP]\s[pP]ort:\s+\d+ # case differs on windows/unix + | + [/A-Z].*mysqld,\sVersion.*(?:started\swith:|embedded\slibrary) + | + Time\s+Id\s+Command + ).*\n + }xm; + +sub parse_event { + my ( $self, %args ) = @_; + my @required_args = qw(fh); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my $fh = @args{@required_args}; + + my $pending = $self->{pending}; + local $INPUT_RECORD_SEPARATOR = ";\n#"; + my $trimlen = length($INPUT_RECORD_SEPARATOR); + my $pos_in_log = tell($fh); + my $stmt; + + EVENT: + while ( (defined($stmt = shift @$pending) or defined($stmt = <$fh>)) ) { + my @properties = ('cmd', 'Query', 'pos_in_log', $pos_in_log); + $pos_in_log = tell($fh); + + if ( $stmt =~ s/$slow_log_hd_line//go ){ # Throw away header lines in log + my @chunks = split(/$INPUT_RECORD_SEPARATOR/o, $stmt); + if ( @chunks > 1 ) { + MKDEBUG && _d("Found multiple chunks"); + $stmt = shift @chunks; + unshift @$pending, @chunks; + } + } + + $stmt = '#' . $stmt unless $stmt =~ m/\A#/; + $stmt =~ s/;\n#?\Z//; + + + my ($got_ts, $got_uh, $got_ac, $got_db, $got_set, $got_embed); + my $pos = 0; + my $len = length($stmt); + my $found_arg = 0; + LINE: + while ( $stmt =~ m/^(.*)$/mg ) { # /g is important, requires scalar match. + $pos = pos($stmt); # Be careful not to mess this up! + my $line = $1; # Necessary for /g and pos() to work. + MKDEBUG && _d($line); + + if ($line =~ m/^(?:#|use |SET (?:last_insert_id|insert_id|timestamp))/o) { + + if ( !$got_ts && (my ( $time ) = $line =~ m/$slow_log_ts_line/o)) { + MKDEBUG && _d("Got ts", $time); + push @properties, 'ts', $time; + ++$got_ts; + if ( !$got_uh + && ( my ( $user, $host, $ip ) = $line =~ m/$slow_log_uh_line/o ) + ) { + MKDEBUG && _d("Got user, host, ip", $user, $host, $ip); + push @properties, 'user', $user, 'host', $host, 'ip', $ip; + ++$got_uh; + } + } + + elsif ( !$got_uh + && ( my ( $user, $host, $ip ) = $line =~ m/$slow_log_uh_line/o ) + ) { + MKDEBUG && _d("Got user, host, ip", $user, $host, $ip); + push @properties, 'user', $user, 'host', $host, 'ip', $ip; + ++$got_uh; + } + + elsif (!$got_ac && $line =~ m/^# (?:administrator command:.*)$/) { + MKDEBUG && _d("Got admin command"); + push @properties, 'cmd', 'Admin', 'arg', $line; + push @properties, 'bytes', length($properties[-1]); + ++$found_arg; + ++$got_ac; + } + + elsif ( $line =~ m/^# +[A-Z][A-Za-z_]+: \S+/ ) { # Make the test cheap! + MKDEBUG && _d("Got some line with properties"); + my @temp = $line =~ m/(\w+):\s+(\S+|\Z)/g; + push @properties, @temp; + } + + elsif ( !$got_db && (my ( $db ) = $line =~ m/^use ([^;]+)/ ) ) { + MKDEBUG && _d("Got a default database:", $db); + push @properties, 'db', $db; + ++$got_db; + } + + elsif (!$got_set && (my ($setting) = $line =~ m/^SET\s+([^;]*)/)) { + MKDEBUG && _d("Got some setting:", $setting); + push @properties, split(/,|\s*=\s*/, $setting); + ++$got_set; + } + + if ( !$found_arg && $pos == $len ) { + MKDEBUG && _d("Did not find arg, looking for special cases"); + local $INPUT_RECORD_SEPARATOR = ";\n"; + if ( defined(my $l = <$fh>) ) { + chomp $l; + MKDEBUG && _d("Found admin statement", $l); + push @properties, 'cmd', 'Admin', 'arg', '#' . $l; + push @properties, 'bytes', length($properties[-1]); + $found_arg++; + } + else { + MKDEBUG && _d("I can't figure out what to do with this line"); + next EVENT; + } + } + } + else { + MKDEBUG && _d("Got the query/arg line"); + my $arg = substr($stmt, $pos - length($line)); + push @properties, 'arg', $arg, 'bytes', length($arg); + if ( $args{misc} && $args{misc}->{embed} + && ( my ($e) = $arg =~ m/($args{misc}->{embed})/) + ) { + push @properties, $e =~ m/$args{misc}->{capture}/g; + } + last LINE; + } + } + + MKDEBUG && _d('Properties of event:', Dumper(\@properties)); + my $event = { @properties }; + return $event; + } + + @$pending = (); + $args{oktorun}->(0) if $args{oktorun}; + return; +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +1; + +# ########################################################################### +# End SlowLogParser package +# ########################################################################### + +# ########################################################################### +# SlowLogWriter package 5191 +# ########################################################################### +package SlowLogWriter; + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); + +use constant MKDEBUG => $ENV{MKDEBUG}; + +sub new { + my ( $class ) = @_; + bless {}, $class; +} + +sub write { + my ( $self, $fh, $event ) = @_; + if ( $event->{ts} ) { + print $fh "# Time: $event->{ts}\n"; + } + if ( $event->{user} ) { + printf $fh "# User\@Host: %s[%s] \@ %s []\n", + $event->{user}, $event->{user}, $event->{host}; + } + if ( $event->{ip} && $event->{port} ) { + printf $fh "# Client: $event->{ip}:$event->{port}\n"; + } + if ( $event->{Thread_id} ) { + printf $fh "# Thread_id: $event->{Thread_id}\n"; + } + + my $percona_patched = exists $event->{QC_Hit} ? 1 : 0; + + printf $fh + "# Query_time: %.6f Lock_time: %.6f Rows_sent: %d Rows_examined: %d\n", + map { $_ || 0 } + @{$event}{qw(Query_time Lock_time Rows_sent Rows_examined)}; + + if ( $percona_patched ) { + printf $fh + "# QC_Hit: %s Full_scan: %s Full_join: %s Tmp_table: %s Disk_tmp_table: %s\n# Filesort: %s Disk_filesort: %s Merge_passes: %d\n", + map { $_ || 0 } + @{$event}{qw(QC_Hit Full_scan Full_join Tmp_table Disk_tmp_table Filesort Disk_filesort Merge_passes)}; + + if ( exists $event->{InnoDB_IO_r_ops} ) { + printf $fh + "# InnoDB_IO_r_ops: %d InnoDB_IO_r_bytes: %d InnoDB_IO_r_wait: %s\n# InnoDB_rec_lock_wait: %s InnoDB_queue_wait: %s\n# InnoDB_pages_distinct: %d\n", + map { $_ || 0 } + @{$event}{qw(InnoDB_IO_r_ops InnoDB_IO_r_bytes InnoDB_IO_r_wait InnoDB_rec_lock_wait InnoDB_queue_wait InnoDB_pages_distinct)}; + + } + else { + printf $fh "# No InnoDB statistics available for this query\n"; + } + } + + if ( $event->{db} ) { + printf $fh "use %s;\n", $event->{db}; + } + if ( $event->{arg} =~ m/^administrator command/ ) { + print $fh '# '; + } + print $fh $event->{arg}, ";\n"; + + return; +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +1; + +# ########################################################################### +# End SlowLogWriter package +# ########################################################################### + +# ########################################################################### +# EventAggregator package 4916 +# ########################################################################### +package EventAggregator; + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); + +use constant MKDEBUG => $ENV{MKDEBUG}; +use constant BUCK_SIZE => 1.05; +use constant BASE_LOG => log(BUCK_SIZE); +use constant BASE_OFFSET => abs(1 - log(0.000001) / BASE_LOG); # 284.1617969 +use constant NUM_BUCK => 1000; +use constant MIN_BUCK => .000001; + +our @buckets = map { 0 } (0..NUM_BUCK-1); + +my @buck_vals = map { bucket_value($_); } (0..NUM_BUCK-1); + +sub new { + my ( $class, %args ) = @_; + foreach my $arg ( qw(groupby worst) ) { + die "I need a $arg argument" unless $args{$arg}; + } + my $attributes = $args{attributes} || {}; + my $self = { + groupby => $args{groupby}, + detect_attribs => scalar keys %$attributes == 0 ? 1 : 0, + all_attribs => [ keys %$attributes ], + ignore_attribs => { + map { $_ => $args{attributes}->{$_} } + grep { $_ ne $args{groupby} } + @{$args{ignore_attributes}} + }, + attributes => { + map { $_ => $args{attributes}->{$_} } + grep { $_ ne $args{groupby} } + keys %$attributes + }, + alt_attribs => { + map { $_ => make_alt_attrib(@{$args{attributes}->{$_}}) } + grep { $_ ne $args{groupby} } + keys %$attributes + }, + worst => $args{worst}, + unroll_limit => $args{unroll_limit} || 1000, + attrib_limit => $args{attrib_limit}, + result_classes => {}, + result_globals => {}, + result_samples => {}, + n_events => 0, + unrolled_loops => undef, + type_for => { %{$args{type_for} || { Query_time => 'num' }} }, + }; + return bless $self, $class; +} + +sub reset_aggregated_data { + my ( $self ) = @_; + foreach my $class ( values %{$self->{result_classes}} ) { + foreach my $attrib ( values %$class ) { + delete @{$attrib}{keys %$attrib}; + } + } + foreach my $class ( values %{$self->{result_globals}} ) { + delete @{$class}{keys %$class}; + } + delete @{$self->{result_samples}}{keys %{$self->{result_samples}}}; + $self->{n_events} = 0; +} + +sub aggregate { + my ( $self, $event ) = @_; + + my $group_by = $event->{$self->{groupby}}; + return unless defined $group_by; + + $self->{n_events}++; + MKDEBUG && _d('event', $self->{n_events}); + + return $self->{unrolled_loops}->($self, $event, $group_by) + if $self->{unrolled_loops}; + + if ( $self->{n_events} <= $self->{unroll_limit} ) { + + $self->add_new_attributes($event) if $self->{detect_attribs}; + + ATTRIB: + foreach my $attrib ( keys %{$self->{attributes}} ) { + + if ( !exists $event->{$attrib} ) { + MKDEBUG && _d("attrib doesn't exist in event:", $attrib); + my $alt_attrib = $self->{alt_attribs}->{$attrib}->($event); + MKDEBUG && _d('alt attrib:', $alt_attrib); + next ATTRIB unless $alt_attrib; + } + + GROUPBY: + foreach my $val ( ref $group_by ? @$group_by : ($group_by) ) { + my $class_attrib = $self->{result_classes}->{$val}->{$attrib} ||= {}; + my $global_attrib = $self->{result_globals}->{$attrib} ||= {}; + my $samples = $self->{result_samples}; + my $handler = $self->{handlers}->{ $attrib }; + if ( !$handler ) { + $handler = $self->make_handler( + $attrib, + $event, + wor => $self->{worst} eq $attrib, + alt => $self->{attributes}->{$attrib}, + ); + $self->{handlers}->{$attrib} = $handler; + } + next GROUPBY unless $handler; + $samples->{$val} ||= $event; # Initialize to the first event. + $handler->($event, $class_attrib, $global_attrib, $samples, $group_by); + } + } + } + else { + $self->_make_unrolled_loops($event); + $self->{unrolled_loops}->($self, $event, $group_by); + } + + return; +} + +sub _make_unrolled_loops { + my ( $self, $event ) = @_; + + my $group_by = $event->{$self->{groupby}}; + + my @attrs = grep { $self->{handlers}->{$_} } keys %{$self->{attributes}}; + my $globs = $self->{result_globals}; # Global stats for each + my $samples = $self->{result_samples}; + + my @lines = ( + 'my ( $self, $event, $group_by ) = @_;', + 'my ($val, $class, $global, $idx);', + (ref $group_by ? ('foreach my $group_by ( @$group_by ) {') : ()), + 'my $temp = $self->{result_classes}->{ $group_by } + ||= { map { $_ => { } } @attrs };', + '$samples->{$group_by} ||= $event;', # Always start with the first. + ); + foreach my $i ( 0 .. $#attrs ) { + push @lines, ( + '$class = $temp->{\'' . $attrs[$i] . '\'};', + '$global = $globs->{\'' . $attrs[$i] . '\'};', + $self->{unrolled_for}->{$attrs[$i]}, + ); + } + if ( ref $group_by ) { + push @lines, '}'; # Close the loop opened above + } + @lines = map { s/^/ /gm; $_ } @lines; # Indent for debugging + unshift @lines, 'sub {'; + push @lines, '}'; + + my $code = join("\n", @lines); + MKDEBUG && _d('Unrolled subroutine:', @lines); + my $sub = eval $code; + die $EVAL_ERROR if $EVAL_ERROR; + $self->{unrolled_loops} = $sub; + + return; +} + +sub results { + my ( $self ) = @_; + return { + classes => $self->{result_classes}, + globals => $self->{result_globals}, + samples => $self->{result_samples}, + }; +} + +sub attributes { + my ( $self ) = @_; + return $self->{type_for}; +} + +sub type_for { + my ( $self, $attrib ) = @_; + return $self->{type_for}->{$attrib}; +} + +sub make_handler { + my ( $self, $attrib, $event, %args ) = @_; + die "I need an attrib" unless defined $attrib; + my ($val) = grep { defined $_ } map { $event->{$_} } @{ $args{alt} }; + my $is_array = 0; + if (ref $val eq 'ARRAY') { + $is_array = 1; + $val = $val->[0]; + } + return unless defined $val; # Can't decide type if it's undef. + + my $float_re = qr{[+-]?(?:(?=\d|[.])\d+(?:[.])\d{0,})(?:E[+-]?\d+)?}i; + my $type = $self->type_for($attrib) ? $self->type_for($attrib) + : $val =~ m/^(?:\d+|$float_re)$/o ? 'num' + : $val =~ m/^(?:Yes|No)$/ ? 'bool' + : 'string'; + MKDEBUG && _d('Type for', $attrib, 'is', $type, + '(sample:', $val, '), is array:', $is_array); + $self->{type_for}->{$attrib} = $type; + + %args = ( # Set up defaults + min => 1, + max => 1, + sum => $type =~ m/num|bool/ ? 1 : 0, + cnt => 1, + unq => $type =~ m/bool|string/ ? 1 : 0, + all => $type eq 'num' ? 1 : 0, + glo => 1, + trf => ($type eq 'bool') ? q{(($val || '') eq 'Yes') ? 1 : 0} : undef, + wor => 0, + alt => [], + %args, + ); + + my @lines = ("# type: $type"); # Lines of code for the subroutine + if ( $args{trf} ) { + push @lines, q{$val = } . $args{trf} . ';'; + } + + foreach my $place ( qw($class $global) ) { + my @tmp; + if ( $args{min} ) { + my $op = $type eq 'num' ? '<' : 'lt'; + push @tmp, ( + 'PLACE->{min} = $val if !defined PLACE->{min} || $val ' + . $op . ' PLACE->{min};', + ); + } + if ( $args{max} ) { + my $op = ($type eq 'num') ? '>' : 'gt'; + push @tmp, ( + 'PLACE->{max} = $val if !defined PLACE->{max} || $val ' + . $op . ' PLACE->{max};', + ); + } + if ( $args{sum} ) { + push @tmp, 'PLACE->{sum} += $val;'; + } + if ( $args{cnt} ) { + push @tmp, '++PLACE->{cnt};'; + } + if ( $args{all} ) { + push @tmp, ( + 'exists PLACE->{all} or PLACE->{all} = [ @buckets ];', + '++PLACE->{all}->[ EventAggregator::bucket_idx($val) ];', + ); + } + push @lines, map { s/PLACE/$place/g; $_ } @tmp; + } + + if ( $args{unq} ) { + push @lines, '++$class->{unq}->{$val};'; + } + if ( $args{wor} ) { + my $op = $type eq 'num' ? '>=' : 'ge'; + push @lines, ( + 'if ( $val ' . $op . ' ($class->{max} || 0) ) {', + ' $samples->{$group_by} = $event;', + '}', + ); + } + + my @broken_query_time; + if ( $attrib eq 'Query_time' ) { + push @broken_query_time, ( + '$val =~ s/^(\d+(?:\.\d+)?).*/$1/;', + '$event->{\''.$attrib.'\'} = $val;', + ); + } + + my @limit; + if ( $args{all} && $type eq 'num' && $self->{attrib_limit} ) { + push @limit, ( + "if ( \$val > $self->{attrib_limit} ) {", + ' $val = $class->{last} ||= 0;', + '}', + '$class->{last} = $val;', + ); + } + + my @unrolled = ( + "\$val = \$event->{'$attrib'};", + ($is_array ? ('foreach my $val ( @$val ) {') : ()), + (map { "\$val = \$event->{'$_'} unless defined \$val;" } + grep { $_ ne $attrib } @{$args{alt}}), + 'defined $val && do {', + ( map { s/^/ /gm; $_ } (@broken_query_time, @limit, @lines) ), # Indent for debugging + '};', + ($is_array ? ('}') : ()), + ); + $self->{unrolled_for}->{$attrib} = join("\n", @unrolled); + + unshift @lines, ( + 'sub {', + 'my ( $event, $class, $global, $samples, $group_by ) = @_;', + 'my ($val, $idx);', # NOTE: define all variables here + "\$val = \$event->{'$attrib'};", + (map { "\$val = \$event->{'$_'} unless defined \$val;" } + grep { $_ ne $attrib } @{$args{alt}}), + 'return unless defined $val;', + ($is_array ? ('foreach my $val ( @$val ) {') : ()), + @broken_query_time, + @limit, + ($is_array ? ('}') : ()), + ); + push @lines, '}'; + my $code = join("\n", @lines); + $self->{code_for}->{$attrib} = $code; + + MKDEBUG && _d('Metric handler for', $attrib, ':', @lines); + my $sub = eval join("\n", @lines); + die if $EVAL_ERROR; + return $sub; +} + +sub bucket_idx { + my ( $val ) = @_; + return 0 if $val < MIN_BUCK; + my $idx = int(BASE_OFFSET + log($val)/BASE_LOG); + return $idx > (NUM_BUCK-1) ? (NUM_BUCK-1) : $idx; +} + +sub bucket_value { + my ( $bucket ) = @_; + return 0 if $bucket == 0; + die "Invalid bucket: $bucket" if $bucket < 0 || $bucket > (NUM_BUCK-1); + return (BUCK_SIZE**($bucket-1)) * MIN_BUCK; +} + +{ + my @buck_tens; + sub buckets_of { + return @buck_tens if @buck_tens; + + my $start_bucket = 0; + my @base10_starts = (0); + map { push @base10_starts, (10**$_)*MIN_BUCK } (1..7); + + for my $base10_bucket ( 0..($#base10_starts-1) ) { + my $next_bucket = bucket_idx( $base10_starts[$base10_bucket+1] ); + MKDEBUG && _d('Base 10 bucket', $base10_bucket, 'maps to', + 'base 1.05 buckets', $start_bucket, '..', $next_bucket-1); + for my $base1_05_bucket ($start_bucket..($next_bucket-1)) { + $buck_tens[$base1_05_bucket] = $base10_bucket; + } + $start_bucket = $next_bucket; + } + + map { $buck_tens[$_] = 7 } ($start_bucket..(NUM_BUCK-1)); + + return @buck_tens; + } +} + +sub calculate_statistical_metrics { + my ( $self, $vals, $args ) = @_; + my $statistical_metrics = { + pct_95 => 0, + stddev => 0, + median => 0, + cutoff => undef, + }; + + return $statistical_metrics + unless defined $vals && @$vals && $args->{cnt}; + + my $n_vals = $args->{cnt}; + if ( $n_vals == 1 || $args->{max} == $args->{min} ) { + my $v = $args->{max} || 0; + my $bucket = int(6 + ( log($v > 0 ? $v : MIN_BUCK) / log(10))); + $bucket = $bucket > 7 ? 7 : $bucket < 0 ? 0 : $bucket; + return { + pct_95 => $v, + stddev => 0, + median => $v, + cutoff => $n_vals, + }; + } + elsif ( $n_vals == 2 ) { + foreach my $v ( $args->{min}, $args->{max} ) { + my $bucket = int(6 + ( log($v && $v > 0 ? $v : MIN_BUCK) / log(10))); + $bucket = $bucket > 7 ? 7 : $bucket < 0 ? 0 : $bucket; + } + my $v = $args->{max} || 0; + my $mean = (($args->{min} || 0) + $v) / 2; + return { + pct_95 => $v, + stddev => sqrt((($v - $mean) ** 2) *2), + median => $mean, + cutoff => $n_vals, + }; + } + + my $cutoff = $n_vals >= 10 ? int ( $n_vals * 0.95 ) : $n_vals; + $statistical_metrics->{cutoff} = $cutoff; + + my $total_left = $n_vals; + my $top_vals = $n_vals - $cutoff; # vals > 95th + my $sum_excl = 0; + my $sum = 0; + my $sumsq = 0; + my $mid = int($n_vals / 2); + my $median = 0; + my $prev = NUM_BUCK-1; # Used for getting median when $cutoff is odd + my $bucket_95 = 0; # top bucket in 95th + + MKDEBUG && _d('total vals:', $total_left, 'top vals:', $top_vals, 'mid:', $mid); + + BUCKET: + for my $bucket ( reverse 0..(NUM_BUCK-1) ) { + my $val = $vals->[$bucket]; + next BUCKET unless $val; + + $total_left -= $val; + $sum_excl += $val; + $bucket_95 = $bucket if !$bucket_95 && $sum_excl > $top_vals; + + if ( !$median && $total_left <= $mid ) { + $median = (($cutoff % 2) || ($val > 1)) ? $buck_vals[$bucket] + : ($buck_vals[$bucket] + $buck_vals[$prev]) / 2; + } + + $sum += $val * $buck_vals[$bucket]; + $sumsq += $val * ($buck_vals[$bucket]**2); + $prev = $bucket; + } + + my $var = $sumsq/$n_vals - ( ($sum/$n_vals) ** 2 ); + my $stddev = $var > 0 ? sqrt($var) : 0; + my $maxstdev = (($args->{max} || 0) - ($args->{min} || 0)) / 2; + $stddev = $stddev > $maxstdev ? $maxstdev : $stddev; + + MKDEBUG && _d('sum:', $sum, 'sumsq:', $sumsq, 'stddev:', $stddev, + 'median:', $median, 'prev bucket:', $prev, + 'total left:', $total_left, 'sum excl', $sum_excl, + 'bucket 95:', $bucket_95, $buck_vals[$bucket_95]); + + $statistical_metrics->{stddev} = $stddev; + $statistical_metrics->{pct_95} = $buck_vals[$bucket_95]; + $statistical_metrics->{median} = $median; + + return $statistical_metrics; +} + +sub metrics { + my ( $self, %args ) = @_; + foreach my $arg ( qw(attrib where) ) { + die "I need a $arg argument" unless $args{$arg}; + } + my $stats = $self->results; + my $store = $stats->{classes}->{$args{where}}->{$args{attrib}}; + + my $global_cnt = $stats->{globals}->{$args{attrib}}->{cnt}; + my $metrics = $self->calculate_statistical_metrics($store->{all}, $store); + + return { + cnt => $store->{cnt}, + pct => $global_cnt && $store->{cnt} ? $store->{cnt} / $global_cnt : 0, + sum => $store->{sum}, + min => $store->{min}, + max => $store->{max}, + avg => $store->{sum} && $store->{cnt} ? $store->{sum} / $store->{cnt} : 0, + median => $metrics->{median}, + pct_95 => $metrics->{pct_95}, + stddev => $metrics->{stddev}, + }; +} + +sub top_events { + my ( $self, %args ) = @_; + my $classes = $self->{result_classes}; + my @sorted = reverse sort { # Sorted list of $groupby values + $classes->{$a}->{$args{attrib}}->{$args{orderby}} + <=> $classes->{$b}->{$args{attrib}}->{$args{orderby}} + } grep { + defined $classes->{$_}->{$args{attrib}}->{$args{orderby}} + } keys %$classes; + my @chosen; + my ($total, $count) = (0, 0); + foreach my $groupby ( @sorted ) { + if ( + (!$args{total} || $total < $args{total} ) + && ( !$args{count} || $count < $args{count} ) + ) { + push @chosen, [$groupby, 'top']; + } + + elsif ( $args{ol_attrib} && (!$args{ol_freq} + || $classes->{$groupby}->{$args{ol_attrib}}->{cnt} >= $args{ol_freq}) + ) { + MKDEBUG && _d('Calculating statistical_metrics'); + my $stats = $self->calculate_statistical_metrics( + $classes->{$groupby}->{$args{ol_attrib}}->{all}, + $classes->{$groupby}->{$args{ol_attrib}} + ); + if ( $stats->{pct_95} >= $args{ol_limit} ) { + push @chosen, [$groupby, 'outlier']; + } + } + + $total += $classes->{$groupby}->{$args{attrib}}->{$args{orderby}}; + $count++; + } + return @chosen; +} + +sub add_new_attributes { + my ( $self, $event ) = @_; + return unless $event; + + map { + my $attrib = $_; + $self->{attributes}->{$attrib} = [$attrib]; + $self->{alt_attribs}->{$attrib} = make_alt_attrib($attrib); + push @{$self->{all_attribs}}, $attrib; + MKDEBUG && _d('Added new attribute:', $attrib); + } + grep { + $_ ne $self->{groupby} + && !exists $self->{attributes}->{$_} + && !exists $self->{ignore_attribs}->{$_} + } + keys %$event; + + return; +} + +sub get_attributes { + my ( $self ) = @_; + return @{$self->{all_attribs}}; +} + +sub events_processed { + my ( $self ) = @_; + return $self->{n_events}; +} + +sub make_alt_attrib { + my ( @attribs ) = @_; + + my $attrib = shift @attribs; # Primary attribute. + return sub {} unless @attribs; # No alternates. + + my @lines; + push @lines, 'sub { my ( $event ) = @_; my $alt_attrib;'; + push @lines, map { + "\$alt_attrib = '$_' if !defined \$alt_attrib " + . "&& exists \$event->{'$_'};" + } @attribs; + push @lines, 'return $alt_attrib; }'; + MKDEBUG && _d('alt attrib sub for', $attrib, ':', @lines); + my $sub = eval join("\n", @lines); + die if $EVAL_ERROR; + return $sub; +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +1; + +# ########################################################################### +# End EventAggregator package +# ########################################################################### + +# ########################################################################### +# ReportFormatter package 5113 +# ########################################################################### +package ReportFormatter; + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); +use List::Util qw(min max); + +use constant MKDEBUG => $ENV{MKDEBUG}; + +use Data::Dumper; +$Data::Dumper::Indent = 1; +$Data::Dumper::Sortkeys = 1; +$Data::Dumper::Quotekeys = 0; + +sub new { + my ( $class, %args ) = @_; + my @required_args = qw(); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my $self = { + underline_header => 1, + line_prefix => '# ', + line_width => 78, + truncate_underline => 1, + %args, + }; + return bless $self, $class; +} + +sub set_title { + my ( $self, $title ) = @_; + $self->{title} = $title; + return; +} + +sub set_columns { + my ( $self, @cols ) = @_; + push @{$self->{cols}}, map { + my $col = $_; + die "Column does not have a name" unless defined $col->{name}; + if ( $col->{fixed_wdith} && $col->{fixed_width} < length $col->{name} ) { + die "Fixed width is less than the column name"; + } + $col->{min_val_width} = length $col->{name}; + $col->{max_val_width} = length $col->{name}; + $col; + } @cols; + return; +} + +sub add_line { + my ( $self, @vals ) = @_; + + my $n_cols = scalar @{$self->{cols}}; + my $n_vals = scalar @vals; + die "Number of columns ($n_cols) and values ($n_vals) do not match" + unless $n_cols == $n_vals; + + my @line; + for my $i ( 0..$#vals ) { + my $col = $self->{cols}->[$i]; + my $val = $vals[$i]; + my $width = length $val; + if ( $col->{fixed_width} && $width > $col->{fixed_width} ) { + if ( $col->{truncate} ) { + $val = substr($val, 0, $col->{fixed_width} - 3); + $val .= '...'; + MKDEBUG && _d('Truncated', $vals[$i], 'to', $val); + } + else { + die "Value '$val' is too wide for column $col->{name}"; + } + } + $col->{max_val_width} = max($width, $col->{max_val_width}); + push @line, $val; + } + push @{$self->{lines}}, \@line; + + return; +} + +sub get_report { + my ( $self ) = @_; + my @lines; + my $p = $self->{line_prefix} || ''; + + my $n_cols = scalar @{$self->{cols}} + - ($self->{long_last_column} ? 2 : 1); + + my $fmt = $p; + my @col_fmts; + for my $i ( 0..$n_cols ) { + my $col = $self->{cols}->[$i]; + my $col_fmt = '%' + . ($col->{right_justify} ? '' : '-') + . "$col->{max_val_width}" + . 's'; + push @col_fmts, $col_fmt; + } + if ( $self->{long_last_column} ) { + push @col_fmts, '%s'; + } + $fmt .= join(' ', @col_fmts); + MKDEBUG && _d('Format:', $fmt); + + push @lines, sprintf "${p}$self->{title}" if $self->{title}; + + (my $hdr_fmt = $fmt) =~ s/%([^-])/%-$1/g; + push @lines, sprintf $hdr_fmt, map { $_->{name} } @{$self->{cols}}; + + if ( $self->{underline_header} ) { + my $underline_len = 0; + my @underlines = map { + my $underline = '=' x $_->{max_val_width}; + $underline_len += length $underline; + $underline; + } @{$self->{cols}}; + $underline_len += (scalar @underlines) - 1; + if ( $self->{truncate_underline} + && (2 + $underline_len) > $self->{line_width} ) { + my $over = $self->{line_width} - (2 + $underline_len); + $underlines[-1] = substr($underlines[-1], 0, $over); + } + + push @lines, sprintf $fmt, @underlines; + } + + foreach my $line ( @{$self->{lines}} ) { + push @lines, sprintf $fmt, @$line; + } + + return join("\n", @lines) . "\n"; +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +1; + +# ########################################################################### +# End ReportFormatter package +# ########################################################################### + +# ########################################################################### +# QueryReportFormatter package 5180 +# ########################################################################### + + +package QueryReportFormatter; + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); +Transformers->import( + qw(shorten micro_t parse_timestamp unix_timestamp + make_checksum percentage_of)); + +use constant MKDEBUG => $ENV{MKDEBUG}; +use constant LINE_LENGTH => 74; +use constant MAX_STRING_LENGTH => 10; + +my %formatting_function = ( + ts => sub { + my ( $stats ) = @_; + my $min = parse_timestamp($stats->{min} || ''); + my $max = parse_timestamp($stats->{max} || ''); + return $min && $max ? "$min to $max" : ''; + }, +); + +my $bool_format = '# %3s%% %-6s %s'; + +sub new { + my ( $class, %args ) = @_; + return bless { }, $class; +} + +sub header { + my ($self) = @_; + + my ( $rss, $vsz, $user, $system ) = ( 0, 0, 0, 0 ); + my $result = ''; + eval { + my $mem = `ps -o rss,vsz -p $PID 2>&1`; + ( $rss, $vsz ) = $mem =~ m/(\d+)/g; + ( $user, $system ) = times(); + $result = sprintf "# %s user time, %s system time, %s rss, %s vsz\n", + micro_t( $user, p_s => 1, p_ms => 1 ), + micro_t( $system, p_s => 1, p_ms => 1 ), + shorten( ($rss || 0) * 1_024 ), + shorten( ($vsz || 0) * 1_024 ); + }; + if ( $EVAL_ERROR ) { + MKDEBUG && _d($EVAL_ERROR); + } + return $result; +} + +sub global_report { + my ( $self, $ea, %opts ) = @_; + my $stats = $ea->results; + my @result; + + my $global_cnt = $stats->{globals}->{$opts{worst}}->{cnt} || 0; + + my ($qps, $conc) = (0, 0); + if ( $global_cnt && $stats->{globals}->{ts} + && ($stats->{globals}->{ts}->{max} || '') + gt ($stats->{globals}->{ts}->{min} || '') + ) { + eval { + my $min = parse_timestamp($stats->{globals}->{ts}->{min}); + my $max = parse_timestamp($stats->{globals}->{ts}->{max}); + my $diff = unix_timestamp($max) - unix_timestamp($min); + $qps = $global_cnt / $diff; + $conc = $stats->{globals}->{$opts{worst}}->{sum} / $diff; + }; + } + + MKDEBUG && _d('global_cnt:', $global_cnt, 'unique:', + scalar keys %{$stats->{classes}}, 'qps:', $qps, 'conc:', $conc); + my $line = sprintf( + '# Overall: %s total, %s unique, %s QPS, %sx concurrency ', + shorten($global_cnt, d=>1_000), + shorten(scalar keys %{$stats->{classes}}, d=>1_000), + shorten($qps || 0, d=>1_000), + shorten($conc || 0, d=>1_000)); + $line .= ('_' x (LINE_LENGTH - length($line))); + push @result, $line; + + my ($format, @headers) = make_header('global'); + push @result, sprintf($format, '', @headers); + + foreach my $attrib ( sort_attribs($ea, @{$opts{select}}) ) { + my $attrib_type = $ea->type_for($attrib); + next unless $attrib_type; + next unless exists $stats->{globals}->{$attrib}; + if ( $formatting_function{$attrib} ) { # Handle special cases + push @result, sprintf $format, make_label($attrib), + $formatting_function{$attrib}->($stats->{globals}->{$attrib}), + (map { '' } 0..9); # just for good measure + } + else { + my $store = $stats->{globals}->{$attrib}; + my @values; + if ( $attrib_type eq 'num' ) { + my $func = $attrib =~ m/time$/ ? \µ_t : \&shorten; + MKDEBUG && _d('Calculating global statistical_metrics for', $attrib); + my $metrics = $ea->calculate_statistical_metrics($store->{all}, $store); + @values = ( + @{$store}{qw(sum min max)}, + $store->{sum} / $store->{cnt}, + @{$metrics}{qw(pct_95 stddev median)}, + ); + @values = map { defined $_ ? $func->($_) : '' } @values; + } + elsif ( $attrib_type eq 'string' ) { + MKDEBUG && _d('Ignoring string attrib', $attrib); + next; + } + elsif ( $attrib_type eq 'bool' ) { + if ( $store->{sum} > 0 || !$opts{no_zero_bool} ) { + push @result, + sprintf $bool_format, format_bool_attrib($store), $attrib; + } + } + else { + @values = ('', $store->{min}, $store->{max}, '', '', '', ''); + } + + push @result, sprintf $format, make_label($attrib), @values + unless $attrib_type eq 'bool'; # bool does its own thing. + } + } + + return join("\n", map { s/\s+$//; $_ } @result) . "\n"; +} + +sub event_report { + my ( $self, $ea, %opts ) = @_; + my $stats = $ea->results; + my @result; + + my $store = $stats->{classes}->{$opts{where}}; + return "# No such event $opts{where}\n" unless $store; + my $sample = $stats->{samples}->{$opts{where}}; + + my $global_cnt = $stats->{globals}->{$opts{worst}}->{cnt}; + my $class_cnt = $store->{$opts{worst}}->{cnt}; + + my ($qps, $conc) = (0, 0); + if ( $global_cnt && $store->{ts} + && ($store->{ts}->{max} || '') + gt ($store->{ts}->{min} || '') + ) { + eval { + my $min = parse_timestamp($store->{ts}->{min}); + my $max = parse_timestamp($store->{ts}->{max}); + my $diff = unix_timestamp($max) - unix_timestamp($min); + $qps = $class_cnt / $diff; + $conc = $store->{$opts{worst}}->{sum} / $diff; + }; + } + + my $line = sprintf( + '# %s %d: %s QPS, %sx concurrency, ID 0x%s at byte %d ', + ($ea->{groupby} eq 'fingerprint' ? 'Query' : 'Item'), + $opts{rank} || 0, + shorten($qps || 0, d=>1_000), + shorten($conc || 0, d=>1_000), + make_checksum($opts{where}), + $sample->{pos_in_log} || 0); + $line .= ('_' x (LINE_LENGTH - length($line))); + push @result, $line; + + if ( $opts{reason} ) { + push @result, "# This item is included in the report because it matches " + . ($opts{reason} eq 'top' ? '--limit.' : '--outliers.'); + } + + my ($format, @headers) = make_header(); + push @result, sprintf($format, '', @headers); + + push @result, sprintf + $format, 'Count', percentage_of($class_cnt, $global_cnt), $class_cnt, + map { '' } (1 ..9); + + foreach my $attrib ( sort_attribs($ea, @{$opts{select}}) ) { + my $attrib_type = $ea->type_for($attrib); + next unless $attrib_type; + next unless exists $store->{$attrib}; + my $vals = $store->{$attrib}; + next unless scalar %$vals; + if ( $formatting_function{$attrib} ) { # Handle special cases + push @result, sprintf $format, make_label($attrib), + $formatting_function{$attrib}->($vals), + (map { '' } 0..9); # just for good measure + } + else { + my @values; + my $pct; + if ( $attrib_type eq 'num' ) { + my $func = $attrib =~ m/time$/ ? \µ_t : \&shorten; + my $metrics = $ea->calculate_statistical_metrics($vals->{all}, $vals); + @values = ( + @{$vals}{qw(sum min max)}, + $vals->{sum} / $vals->{cnt}, + @{$metrics}{qw(pct_95 stddev median)}, + ); + @values = map { defined $_ ? $func->($_) : '' } @values; + $pct = percentage_of($vals->{sum}, + $stats->{globals}->{$attrib}->{sum}); + } + elsif ( $attrib_type eq 'string' ) { + push @values, + format_string_list($vals), + (map { '' } 0..9); # just for good measure + $pct = ''; + } + elsif ( $attrib_type eq 'bool' ) { + if ( $vals->{sum} > 0 || !$opts{no_zero_bool} ) { + push @result, + sprintf $bool_format, format_bool_attrib($vals), $attrib; + } + } + else { + @values = ('', $vals->{min}, $vals->{max}, '', '', '', ''); + $pct = 0; + } + + push @result, sprintf $format, make_label($attrib), $pct, @values + unless $attrib_type eq 'bool'; # bool does its own thing. + } + } + + return join("\n", map { s/\s+$//; $_ } @result) . "\n"; +} + +sub chart_distro { + my ( $self, $ea, %opts ) = @_; + my $stats = $ea->results; + my $store = $stats->{classes}->{$opts{where}}->{$opts{attribute}}; + my $vals = $store->{all}; + return "" unless defined $vals && scalar @$vals; + my @buck_tens = $ea->buckets_of(10); + my @distro = map { 0 } (0 .. 7); + map { $distro[$buck_tens[$_]] += $vals->[$_] } (1 .. @$vals - 1); + + my $max_val = 0; + my $vals_per_mark; # number of vals represented by 1 #-mark + my $max_disp_width = 64; + my $bar_fmt = "# %5s%s"; + my @distro_labels = qw(1us 10us 100us 1ms 10ms 100ms 1s 10s+); + my @results = "# $opts{attribute} distribution"; + + foreach my $n_vals ( @distro ) { + $max_val = $n_vals if $n_vals > $max_val; + } + $vals_per_mark = $max_val / $max_disp_width; + + foreach my $i ( 0 .. $#distro ) { + my $n_vals = $distro[$i]; + my $n_marks = $n_vals / ($vals_per_mark || 1); + $n_marks = 1 if $n_marks < 1 && $n_vals > 0; + my $bar = ($n_marks ? ' ' : '') . '#' x $n_marks; + push @results, sprintf $bar_fmt, $distro_labels[$i], $bar; + } + + return join("\n", @results) . "\n"; +} + +sub make_header { + my ( $global ) = @_; + my $format = "# %-9s %6s %7s %7s %7s %7s %7s %7s %7s"; + my @headers = qw(pct total min max avg 95% stddev median); + if ( $global ) { + $format =~ s/%(\d+)s/' ' x $1/e; + shift @headers; + } + return $format, @headers; +} + +sub make_label { + my ( $val ) = @_; + + if ( $val =~ m/^InnoDB/ ) { + $val =~ s/^InnoDB_(\w+)/IDB_$1/; + $val =~ s/r_(\w+)/r$1/; + } + + return $val eq 'ts' ? 'Time range' + : $val eq 'user' ? 'Users' + : $val eq 'db' ? 'Databases' + : $val eq 'Query_time' ? 'Exec time' + : $val eq 'host' ? 'Hosts' + : $val eq 'Error_no' ? 'Errors' + : do { $val =~ s/_/ /g; $val = substr($val, 0, 9); $val }; +} + +sub format_bool_attrib { + my ( $stats ) = @_; + my $p_true = percentage_of($stats->{sum}, $stats->{cnt}); + my $n_true = '(' . shorten($stats->{sum} || 0, d=>1_000, p=>0) . ')'; + return $p_true, $n_true; +} + +sub format_string_list { + my ( $stats ) = @_; + if ( exists $stats->{unq} ) { + my $cnt_for = $stats->{unq}; + if ( 1 == keys %$cnt_for ) { + my ($str) = keys %$cnt_for; + $str = substr($str, 0, LINE_LENGTH - 30) . '...' + if length $str > LINE_LENGTH - 30; + return (1, $str); + } + my $line = ''; + my @top = sort { $cnt_for->{$b} <=> $cnt_for->{$a} || $a cmp $b } + keys %$cnt_for; + my $i = 0; + foreach my $str ( @top ) { + my $print_str; + if ( length $str > MAX_STRING_LENGTH ) { + $print_str = substr($str, 0, MAX_STRING_LENGTH) . '...'; + } + else { + $print_str = $str; + } + last if (length $line) + (length $print_str) > LINE_LENGTH - 27; + $line .= "$print_str ($cnt_for->{$str}), "; + $i++; + } + $line =~ s/, $//; + if ( $i < @top ) { + $line .= "... " . (@top - $i) . " more"; + } + return (scalar keys %$cnt_for, $line); + } + else { + return ($stats->{cnt}); + } +} + +sub sort_attribs { + my ( $ea, @attribs ) = @_; + my %basic_attrib = ( + Query_time => 0, + Lock_time => 1, + Rows_sent => 2, + Rows_examined => 3, + user => 4, + host => 5, + db => 6, + ts => 7, + ); + my @basic_attribs; + my @non_bool_attribs; + my @bool_attribs; + + ATTRIB: + foreach my $attrib ( @attribs ) { + if ( exists $basic_attrib{$attrib} ) { + push @basic_attribs, $attrib; + } + else { + if ( ($ea->type_for($attrib) || '') ne 'bool' ) { + push @non_bool_attribs, $attrib; + } + else { + push @bool_attribs, $attrib; + } + } + } + + @non_bool_attribs = sort { uc $a cmp uc $b } @non_bool_attribs; + @bool_attribs = sort { uc $a cmp uc $b } @bool_attribs; + @basic_attribs = sort { + $basic_attrib{$a} <=> $basic_attrib{$b} } @basic_attribs; + + return @basic_attribs, @non_bool_attribs, @bool_attribs; +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +1; + +# ########################################################################### +# End QueryReportFormatter package +# ########################################################################### + +# ########################################################################### +# EventTimeline package 3539 +# ########################################################################### + + +package EventTimeline; + + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); +Transformers->import(qw(parse_timestamp secs_to_time unix_timestamp)); + +use constant MKDEBUG => $ENV{MKDEBUG}; +use constant KEY => 0; +use constant CNT => 1; +use constant ATT => 2; + +sub new { + my ( $class, %args ) = @_; + foreach my $arg ( qw(groupby attributes) ) { + die "I need a $arg argument" unless $args{$arg}; + } + + my %is_groupby = map { $_ => 1 } @{$args{groupby}}; + + return bless { + groupby => $args{groupby}, + attributes => [ grep { !$is_groupby{$_} } @{$args{attributes}} ], + results => [], + }, $class; +} + +sub reset_aggregated_data { + my ( $self ) = @_; + $self->{results} = []; +} + +sub aggregate { + my ( $self, $event ) = @_; + my $handler = $self->{handler}; + if ( !$handler ) { + $handler = $self->make_handler($event); + $self->{handler} = $handler; + } + return unless $handler; + $handler->($event); +} + +sub results { + my ( $self ) = @_; + return $self->{results}; +} + +sub make_handler { + my ( $self, $event ) = @_; + + my $float_re = qr{[+-]?(?:(?=\d|[.])\d*(?:[.])\d{0,})?(?:[E](?:[+-]?\d+)|)}i; + my @lines; # lines of code for the subroutine + + foreach my $attrib ( @{$self->{attributes}} ) { + my ($val) = $event->{$attrib}; + next unless defined $val; # Can't decide type if it's undef. + + my $type = $val =~ m/^(?:\d+|$float_re)$/o ? 'num' + : $val =~ m/^(?:Yes|No)$/ ? 'bool' + : 'string'; + MKDEBUG && _d('Type for', $attrib, 'is', $type, '(sample:', $val, ')'); + $self->{type_for}->{$attrib} = $type; + + push @lines, ( + "\$val = \$event->{$attrib};", + 'defined $val && do {', + "# type: $type", + "\$store = \$last->[ATT]->{$attrib} ||= {};", + ); + + if ( $type eq 'bool' ) { + push @lines, q{$val = $val eq 'Yes' ? 1 : 0;}; + $type = 'num'; + } + my $op = $type eq 'num' ? '<' : 'lt'; + push @lines, ( + '$store->{min} = $val if !defined $store->{min} || $val ' + . $op . ' $store->{min};', + ); + $op = ($type eq 'num') ? '>' : 'gt'; + push @lines, ( + '$store->{max} = $val if !defined $store->{max} || $val ' + . $op . ' $store->{max};', + ); + if ( $type eq 'num' ) { + push @lines, '$store->{sum} += $val;'; + } + push @lines, '};'; + } + + unshift @lines, ( + 'sub {', + 'my ( $event ) = @_;', + 'my ($val, $last, $store);', # NOTE: define all variables here + '$last = $results->[-1];', + 'if ( !$last || ' + . join(' || ', + map { "\$last->[KEY]->[$_] ne (\$event->{$self->{groupby}->[$_]} || 0)" } + (0 .. @{$self->{groupby}} -1)) + . ' ) {', + ' $last = [[' + . join(', ', + map { "(\$event->{$self->{groupby}->[$_]} || 0)" } + (0 .. @{$self->{groupby}} -1)) + . '], 0, {} ];', + ' push @$results, $last;', + '}', + '++$last->[CNT];', + ); + push @lines, '}'; + my $results = $self->{results}; # Referred to by the eval + my $code = join("\n", @lines); + $self->{code} = $code; + + MKDEBUG && _d('Timeline handler:', $code); + my $sub = eval $code; + die if $EVAL_ERROR; + return $sub; +} + +sub report { + my ( $self, $results, $callback ) = @_; + $callback->("# " . ('#' x 72) . "\n"); + $callback->("# " . join(',', @{$self->{groupby}}) . " report\n"); + $callback->("# " . ('#' x 72) . "\n"); + foreach my $res ( @$results ) { + my $t; + my @vals; + if ( ($t = $res->[ATT]->{ts}) && $t->{min} ) { + my $min = parse_timestamp($t->{min}); + push @vals, $min; + if ( $t->{max} && $t->{max} gt $t->{min} ) { + my $max = parse_timestamp($t->{max}); + my $diff = secs_to_time(unix_timestamp($max) - unix_timestamp($min)); + push @vals, $diff; + } + else { + push @vals, '0:00'; + } + } + else { + push @vals, ('', ''); + } + $callback->(sprintf("# %19s %7s %3d %s\n", @vals, $res->[CNT], $res->[KEY]->[0])); + } +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +1; + +# ########################################################################### +# End EventTimeline package +# ########################################################################### + +# ########################################################################### +# QueryParser package 4977 +# ########################################################################### +package QueryParser; + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); + +use constant MKDEBUG => $ENV{MKDEBUG}; +our $tbl_ident = qr/(?:`[^`]+`|\w+)(?:\.(?:`[^`]+`|\w+))?/; +our $tbl_regex = qr{ + \b(?:FROM|JOIN|(?get_tables($select); + } + my ($tbl) = $query =~ m/TABLE\s+($tbl_ident)(\s+.*)?/i; + MKDEBUG && _d('Matches table:', $tbl); + return ($tbl); + } + + $query =~ s/ (?:LOW_PRIORITY|IGNORE|STRAIGHT_JOIN)//ig; + + if ( $query =~ /^\s*LOCK TABLES/i ) { + MKDEBUG && _d('Special table type: LOCK TABLES'); + $query =~ s/^(\s*LOCK TABLES\s+)//; + $query =~ s/\s+(?:READ|WRITE|LOCAL)+\s*//g; + MKDEBUG && _d('Locked tables:', $query); + $query = "FROM $query"; + } + + $query =~ s/\\["']//g; # quoted strings + $query =~ s/".*?"/?/sg; # quoted strings + $query =~ s/'.*?'/?/sg; # quoted strings + + my @tables; + foreach my $tbls ( $query =~ m/$tbl_regex/gio ) { + MKDEBUG && _d('Match tables:', $tbls); + foreach my $tbl ( split(',', $tbls) ) { + $tbl =~ s/\s*($tbl_ident)(\s+.*)?/$1/gio; + + if ( $tbl !~ m/[a-zA-Z]/ ) { + MKDEBUG && _d('Skipping suspicious table name:', $tbl); + next; + } + + push @tables, $tbl; + } + } + return @tables; +} + +sub has_derived_table { + my ( $self, $query ) = @_; + my $match = $query =~ m/$has_derived/; + MKDEBUG && _d($query, 'has ' . ($match ? 'a' : 'no') . ' derived table'); + return $match; +} + +sub get_aliases { + my ( $self, $query ) = @_; + return unless $query; + my $aliases; + + $query =~ s/ (?:LOW_PRIORITY|IGNORE|STRAIGHT_JOIN)//ig; + + $query =~ s/ (?:INNER|OUTER|CROSS|LEFT|RIGHT|NATURAL)//ig; + + my ($tbl_refs, $from) = $query =~ m{ + ( + (FROM|INTO|UPDATE)\b\s* # Keyword before table refs + .+? # Table refs + ) + (?:\s+|\z) # If the query does not end with the table + (?:WHERE|ORDER|LIMIT|HAVING|SET|VALUES|\z) # Keyword after table refs + }ix; + + die "Failed to parse table references from $query" + unless $tbl_refs && $from; + + MKDEBUG && _d('tbl refs:', $tbl_refs); + + my $before_tbl = qr/(?:,|JOIN|\s|$from)+/i; + + my $after_tbl = qr/(?:,|JOIN|ON|USING|\z)/i; + + $tbl_refs =~ s/ = /=/g; + + while ( + $tbl_refs =~ m{ + $before_tbl\b\s* + ( ($tbl_ident) (?:\s+ (?:AS\s+)? (\w+))? ) + \s*$after_tbl + }xgio ) + { + my ( $tbl_ref, $db_tbl, $alias ) = ($1, $2, $3); + MKDEBUG && _d('Match table:', $tbl_ref); + + if ( $tbl_ref =~ m/^AS\s+\w+/i ) { + MKDEBUG && _d('Subquery', $tbl_ref); + $aliases->{$alias} = undef; + next; + } + + my ( $db, $tbl ) = $db_tbl =~ m/^(?:(.*?)\.)?(.*)/; + $aliases->{$alias || $tbl} = $tbl; + $aliases->{DATABASE}->{$tbl} = $db if $db; + } + return $aliases; +} + +sub split { + my ( $self, $query ) = @_; + return unless $query; + $query = $self->clean_query($query); + MKDEBUG && _d('Splitting', $query); + + my $verbs = qr{SELECT|INSERT|UPDATE|DELETE|REPLACE|UNION|CREATE}i; + + my @split_statements = grep { $_ } split(m/\b($verbs\b(?!(?:\s*\()))/io, $query); + + my @statements; + if ( @split_statements == 1 ) { + push @statements, $query; + } + else { + for ( my $i = 0; $i <= $#split_statements; $i += 2 ) { + push @statements, $split_statements[$i].$split_statements[$i+1]; + + if ( $statements[-2] && $statements[-2] =~ m/on duplicate key\s+$/i ) { + $statements[-2] .= pop @statements; + } + } + } + + MKDEBUG && _d('statements:', map { $_ ? "<$_>" : 'none' } @statements); + return @statements; +} + +sub clean_query { + my ( $self, $query ) = @_; + return unless $query; + $query =~ s!/\*.*?\*/! !g; # Remove /* comment blocks */ + $query =~ s/^\s+//; # Remove leading spaces + $query =~ s/\s+$//; # Remove trailing spaces + $query =~ s/\s{2,}/ /g; # Remove extra spaces + return $query; +} + +sub split_subquery { + my ( $self, $query ) = @_; + return unless $query; + $query = $self->clean_query($query); + $query =~ s/;$//; + + my @subqueries; + my $sqno = 0; # subquery number + my $pos = 0; + while ( $query =~ m/(\S+)(?:\s+|\Z)/g ) { + $pos = pos($query); + my $word = $1; + MKDEBUG && _d($word, $sqno); + if ( $word =~ m/^\(?SELECT\b/i ) { + my $start_pos = $pos - length($word) - 1; + if ( $start_pos ) { + $sqno++; + MKDEBUG && _d('Subquery', $sqno, 'starts at', $start_pos); + $subqueries[$sqno] = { + start_pos => $start_pos, + end_pos => 0, + len => 0, + words => [$word], + lp => 1, # left parentheses + rp => 0, # right parentheses + done => 0, + }; + } + else { + MKDEBUG && _d('Main SELECT at pos 0'); + } + } + else { + next unless $sqno; # next unless we're in a subquery + MKDEBUG && _d('In subquery', $sqno); + my $sq = $subqueries[$sqno]; + if ( $sq->{done} ) { + MKDEBUG && _d('This subquery is done; SQL is for', + ($sqno - 1 ? "subquery $sqno" : "the main SELECT")); + next; + } + push @{$sq->{words}}, $word; + my $lp = ($word =~ tr/\(//) || 0; + my $rp = ($word =~ tr/\)//) || 0; + MKDEBUG && _d('parentheses left', $lp, 'right', $rp); + if ( ($sq->{lp} + $lp) - ($sq->{rp} + $rp) == 0 ) { + my $end_pos = $pos - 1; + MKDEBUG && _d('Subquery', $sqno, 'ends at', $end_pos); + $sq->{end_pos} = $end_pos; + $sq->{len} = $end_pos - $sq->{start_pos}; + } + } + } + + for my $i ( 1..$#subqueries ) { + my $sq = $subqueries[$i]; + next unless $sq; + $sq->{sql} = join(' ', @{$sq->{words}}); + substr $query, + $sq->{start_pos} + 1, # +1 for ( + $sq->{len} - 1, # -1 for ) + "__subquery_$i"; + } + + return $query, map { $_->{sql} } grep { defined $_ } @subqueries; +} + +sub query_type { + my ( $self, $query, $qr ) = @_; + my ($type, undef) = $qr->_distill_verbs($query); + my $rw; + if ( $type =~ m/^SELECT\b/ ) { + $rw = 'read'; + } + elsif ( $type =~ m/^$data_manip_stmts\b/ + || $type =~ m/^$data_def_stmts\b/ ) { + $rw = 'write' + } + + return { + type => $type, + rw => $rw, + } +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +1; + +# ########################################################################### +# End QueryParser package +# ########################################################################### + +# ########################################################################### +# MySQLDump package 4160 +# ########################################################################### +package MySQLDump; + +use strict; +use warnings FATAL => 'all'; + +use English qw(-no_match_vars); + +use constant MKDEBUG => $ENV{MKDEBUG}; + +( our $before = <<'EOF') =~ s/^ //gm; + /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; + /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; + /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; + /*!40101 SET NAMES utf8 */; + /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; + /*!40103 SET TIME_ZONE='+00:00' */; + /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; + /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; + /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; + /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +EOF + +( our $after = <<'EOF') =~ s/^ //gm; + /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; + /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; + /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; + /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; + /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; + /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; + /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +EOF + +sub new { + my ( $class, %args ) = @_; + $args{cache} = 1 unless defined $args{cache}; + my $self = bless \%args, $class; + return $self; +} + +sub dump { + my ( $self, $dbh, $quoter, $db, $tbl, $what ) = @_; + + if ( $what eq 'table' ) { + my $ddl = $self->get_create_table($dbh, $quoter, $db, $tbl); + return unless $ddl; + if ( $ddl->[0] eq 'table' ) { + return $before + . 'DROP TABLE IF EXISTS ' . $quoter->quote($tbl) . ";\n" + . $ddl->[1] . ";\n"; + } + else { + return 'DROP TABLE IF EXISTS ' . $quoter->quote($tbl) . ";\n" + . '/*!50001 DROP VIEW IF EXISTS ' + . $quoter->quote($tbl) . "*/;\n/*!50001 " + . $self->get_tmp_table($dbh, $quoter, $db, $tbl) . "*/;\n"; + } + } + elsif ( $what eq 'triggers' ) { + my $trgs = $self->get_triggers($dbh, $quoter, $db, $tbl); + if ( $trgs && @$trgs ) { + my $result = $before . "\nDELIMITER ;;\n"; + foreach my $trg ( @$trgs ) { + if ( $trg->{sql_mode} ) { + $result .= qq{/*!50003 SET SESSION SQL_MODE='$trg->{sql_mode}' */;;\n}; + } + $result .= "/*!50003 CREATE */ "; + if ( $trg->{definer} ) { + my ( $user, $host ) + = map { s/'/''/g; "'$_'"; } + split('@', $trg->{definer}, 2); + $result .= "/*!50017 DEFINER=$user\@$host */ "; + } + $result .= sprintf("/*!50003 TRIGGER %s %s %s ON %s\nFOR EACH ROW %s */;;\n\n", + $quoter->quote($trg->{trigger}), + @{$trg}{qw(timing event)}, + $quoter->quote($trg->{table}), + $trg->{statement}); + } + $result .= "DELIMITER ;\n\n/*!50003 SET SESSION SQL_MODE=\@OLD_SQL_MODE */;\n\n"; + return $result; + } + else { + return undef; + } + } + elsif ( $what eq 'view' ) { + my $ddl = $self->get_create_table($dbh, $quoter, $db, $tbl); + return '/*!50001 DROP TABLE IF EXISTS ' . $quoter->quote($tbl) . "*/;\n" + . '/*!50001 DROP VIEW IF EXISTS ' . $quoter->quote($tbl) . "*/;\n" + . '/*!50001 ' . $ddl->[1] . "*/;\n"; + } + else { + die "You didn't say what to dump."; + } +} + +sub _use_db { + my ( $self, $dbh, $quoter, $new ) = @_; + if ( !$new ) { + MKDEBUG && _d('No new DB to use'); + return; + } + my $sql = 'SELECT DATABASE()'; + MKDEBUG && _d($sql); + my $curr = $dbh->selectrow_array($sql); + if ( $curr && $new && $curr eq $new ) { + MKDEBUG && _d('Current and new DB are the same'); + return $curr; + } + $sql = 'USE ' . $quoter->quote($new); + MKDEBUG && _d($sql); + $dbh->do($sql); + return $curr; +} + +sub get_create_table { + my ( $self, $dbh, $quoter, $db, $tbl ) = @_; + if ( !$self->{cache} || !$self->{tables}->{$db}->{$tbl} ) { + my $sql = '/*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, ' + . q{@@SQL_MODE := REPLACE(REPLACE(@@SQL_MODE, 'ANSI_QUOTES', ''), ',,', ','), } + . '@OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, ' + . '@@SQL_QUOTE_SHOW_CREATE := 1 */'; + MKDEBUG && _d($sql); + eval { $dbh->do($sql); }; + MKDEBUG && $EVAL_ERROR && _d($EVAL_ERROR); + my $curr_db = $self->_use_db($dbh, $quoter, $db); + $sql = "SHOW CREATE TABLE " . $quoter->quote($db, $tbl); + MKDEBUG && _d($sql); + my $href; + eval { $href = $dbh->selectrow_hashref($sql); }; + if ( $EVAL_ERROR ) { + warn "Failed to $sql. The table may be damaged.\nError: $EVAL_ERROR"; + return; + } + $self->_use_db($dbh, $quoter, $curr_db); + $sql = '/*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, ' + . '@@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */'; + MKDEBUG && _d($sql); + $dbh->do($sql); + my ($key) = grep { m/create table/i } keys %$href; + if ( $key ) { + MKDEBUG && _d('This table is a base table'); + $self->{tables}->{$db}->{$tbl} = [ 'table', $href->{$key} ]; + } + else { + MKDEBUG && _d('This table is a view'); + ($key) = grep { m/create view/i } keys %$href; + $self->{tables}->{$db}->{$tbl} = [ 'view', $href->{$key} ]; + } + } + return $self->{tables}->{$db}->{$tbl}; +} + +sub get_columns { + my ( $self, $dbh, $quoter, $db, $tbl ) = @_; + MKDEBUG && _d('Get columns for', $db, $tbl); + if ( !$self->{cache} || !$self->{columns}->{$db}->{$tbl} ) { + my $curr_db = $self->_use_db($dbh, $quoter, $db); + my $sql = "SHOW COLUMNS FROM " . $quoter->quote($db, $tbl); + MKDEBUG && _d($sql); + my $cols = $dbh->selectall_arrayref($sql, { Slice => {} }); + $self->_use_db($dbh, $quoter, $curr_db); + $self->{columns}->{$db}->{$tbl} = [ + map { + my %row; + @row{ map { lc $_ } keys %$_ } = values %$_; + \%row; + } @$cols + ]; + } + return $self->{columns}->{$db}->{$tbl}; +} + +sub get_tmp_table { + my ( $self, $dbh, $quoter, $db, $tbl ) = @_; + my $result = 'CREATE TABLE ' . $quoter->quote($tbl) . " (\n"; + $result .= join(",\n", + map { ' ' . $quoter->quote($_->{field}) . ' ' . $_->{type} } + @{$self->get_columns($dbh, $quoter, $db, $tbl)}); + $result .= "\n)"; + MKDEBUG && _d($result); + return $result; +} + +sub get_triggers { + my ( $self, $dbh, $quoter, $db, $tbl ) = @_; + if ( !$self->{cache} || !$self->{triggers}->{$db} ) { + $self->{triggers}->{$db} = {}; + my $sql = '/*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, ' + . q{@@SQL_MODE := REPLACE(REPLACE(@@SQL_MODE, 'ANSI_QUOTES', ''), ',,', ','), } + . '@OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, ' + . '@@SQL_QUOTE_SHOW_CREATE := 1 */'; + MKDEBUG && _d($sql); + eval { $dbh->do($sql); }; + MKDEBUG && $EVAL_ERROR && _d($EVAL_ERROR); + $sql = "SHOW TRIGGERS FROM " . $quoter->quote($db); + MKDEBUG && _d($sql); + my $sth = $dbh->prepare($sql); + $sth->execute(); + if ( $sth->rows ) { + my $trgs = $sth->fetchall_arrayref({}); + foreach my $trg (@$trgs) { + my %trg; + @trg{ map { lc $_ } keys %$trg } = values %$trg; + push @{ $self->{triggers}->{$db}->{ $trg{table} } }, \%trg; + } + } + $sql = '/*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, ' + . '@@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */'; + MKDEBUG && _d($sql); + $dbh->do($sql); + } + if ( $tbl ) { + return $self->{triggers}->{$db}->{$tbl}; + } + return values %{$self->{triggers}->{$db}}; +} + +sub get_databases { + my ( $self, $dbh, $quoter, $like ) = @_; + if ( !$self->{cache} || !$self->{databases} || $like ) { + my $sql = 'SHOW DATABASES'; + my @params; + if ( $like ) { + $sql .= ' LIKE ?'; + push @params, $like; + } + my $sth = $dbh->prepare($sql); + MKDEBUG && _d($sql, @params); + $sth->execute( @params ); + my @dbs = map { $_->[0] } @{$sth->fetchall_arrayref()}; + $self->{databases} = \@dbs unless $like; + return @dbs; + } + return @{$self->{databases}}; +} + +sub get_table_status { + my ( $self, $dbh, $quoter, $db, $like ) = @_; + if ( !$self->{cache} || !$self->{table_status}->{$db} || $like ) { + my $sql = "SHOW TABLE STATUS FROM " . $quoter->quote($db); + my @params; + if ( $like ) { + $sql .= ' LIKE ?'; + push @params, $like; + } + MKDEBUG && _d($sql, @params); + my $sth = $dbh->prepare($sql); + $sth->execute(@params); + my @tables = @{$sth->fetchall_arrayref({})}; + @tables = map { + my %tbl; # Make a copy with lowercased keys + @tbl{ map { lc $_ } keys %$_ } = values %$_; + $tbl{engine} ||= $tbl{type} || $tbl{comment}; + delete $tbl{type}; + \%tbl; + } @tables; + $self->{table_status}->{$db} = \@tables unless $like; + return @tables; + } + return @{$self->{table_status}->{$db}}; +} + +sub get_table_list { + my ( $self, $dbh, $quoter, $db, $like ) = @_; + if ( !$self->{cache} || !$self->{table_list}->{$db} || $like ) { + my $sql = "SHOW /*!50002 FULL*/ TABLES FROM " . $quoter->quote($db); + my @params; + if ( $like ) { + $sql .= ' LIKE ?'; + push @params, $like; + } + MKDEBUG && _d($sql, @params); + my $sth = $dbh->prepare($sql); + $sth->execute(@params); + my @tables = @{$sth->fetchall_arrayref()}; + @tables = map { + my %tbl = ( + name => $_->[0], + engine => ($_->[1] || '') eq 'VIEW' ? 'VIEW' : '', + ); + \%tbl; + } @tables; + $self->{table_list}->{$db} = \@tables unless $like; + return @tables; + } + return @{$self->{table_list}->{$db}}; +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +1; + +# ########################################################################### +# End MySQLDump package +# ########################################################################### + +# ########################################################################### +# TableParser package 5216 +# ########################################################################### +package TableParser; + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); +use Data::Dumper; +$Data::Dumper::Indent = 1; +$Data::Dumper::Sortkeys = 1; +$Data::Dumper::Quotekeys = 0; + +use constant MKDEBUG => $ENV{MKDEBUG}; + + +sub new { + my ( $class, %args ) = @_; + my @required_args = qw(Quoter); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my $self = { %args }; + return bless $self, $class; +} + + +sub parse { + my ( $self, $ddl, $opts ) = @_; + return unless $ddl; + if ( ref $ddl eq 'ARRAY' ) { + if ( lc $ddl->[0] eq 'table' ) { + $ddl = $ddl->[1]; + } + else { + return { + engine => 'VIEW', + }; + } + } + + if ( $ddl !~ m/CREATE (?:TEMPORARY )?TABLE `/ ) { + die "Cannot parse table definition; is ANSI quoting " + . "enabled or SQL_QUOTE_SHOW_CREATE disabled?"; + } + + my ($name) = $ddl =~ m/CREATE (?:TEMPORARY )?TABLE\s+(`.+?`)/; + (undef, $name) = $self->{Quoter}->split_unquote($name) if $name; + + $ddl =~ s/(`[^`]+`)/\L$1/g; + + my $engine = $self->get_engine($ddl); + + my @defs = $ddl =~ m/^(\s+`.*?),?$/gm; + my @cols = map { $_ =~ m/`([^`]+)`/ } @defs; + MKDEBUG && _d('Columns:', join(', ', @cols)); + + my %def_for; + @def_for{@cols} = @defs; + + my (@nums, @null); + my (%type_for, %is_nullable, %is_numeric, %is_autoinc); + foreach my $col ( @cols ) { + my $def = $def_for{$col}; + my ( $type ) = $def =~ m/`[^`]+`\s([a-z]+)/; + die "Can't determine column type for $def" unless $type; + $type_for{$col} = $type; + if ( $type =~ m/(?:(?:tiny|big|medium|small)?int|float|double|decimal|year)/ ) { + push @nums, $col; + $is_numeric{$col} = 1; + } + if ( $def !~ m/NOT NULL/ ) { + push @null, $col; + $is_nullable{$col} = 1; + } + $is_autoinc{$col} = $def =~ m/AUTO_INCREMENT/i ? 1 : 0; + } + + my ($keys, $clustered_key) = $self->get_keys($ddl, $opts, \%is_nullable); + + return { + name => $name, + cols => \@cols, + col_posn => { map { $cols[$_] => $_ } 0..$#cols }, + is_col => { map { $_ => 1 } @cols }, + null_cols => \@null, + is_nullable => \%is_nullable, + is_autoinc => \%is_autoinc, + clustered_key => $clustered_key, + keys => $keys, + defs => \%def_for, + numeric_cols => \@nums, + is_numeric => \%is_numeric, + engine => $engine, + type_for => \%type_for, + }; +} + +sub sort_indexes { + my ( $self, $tbl ) = @_; + + my @indexes + = sort { + (($a ne 'PRIMARY') <=> ($b ne 'PRIMARY')) + || ( !$tbl->{keys}->{$a}->{is_unique} <=> !$tbl->{keys}->{$b}->{is_unique} ) + || ( $tbl->{keys}->{$a}->{is_nullable} <=> $tbl->{keys}->{$b}->{is_nullable} ) + || ( scalar(@{$tbl->{keys}->{$a}->{cols}}) <=> scalar(@{$tbl->{keys}->{$b}->{cols}}) ) + } + grep { + $tbl->{keys}->{$_}->{type} eq 'BTREE' + } + sort keys %{$tbl->{keys}}; + + MKDEBUG && _d('Indexes sorted best-first:', join(', ', @indexes)); + return @indexes; +} + +sub find_best_index { + my ( $self, $tbl, $index ) = @_; + my $best; + if ( $index ) { + ($best) = grep { uc $_ eq uc $index } keys %{$tbl->{keys}}; + } + if ( !$best ) { + if ( $index ) { + die "Index '$index' does not exist in table"; + } + else { + ($best) = $self->sort_indexes($tbl); + } + } + MKDEBUG && _d('Best index found is', $best); + return $best; +} + +sub find_possible_keys { + my ( $self, $dbh, $database, $table, $quoter, $where ) = @_; + return () unless $where; + my $sql = 'EXPLAIN SELECT * FROM ' . $quoter->quote($database, $table) + . ' WHERE ' . $where; + MKDEBUG && _d($sql); + my $expl = $dbh->selectrow_hashref($sql); + $expl = { map { lc($_) => $expl->{$_} } keys %$expl }; + if ( $expl->{possible_keys} ) { + MKDEBUG && _d('possible_keys =', $expl->{possible_keys}); + my @candidates = split(',', $expl->{possible_keys}); + my %possible = map { $_ => 1 } @candidates; + if ( $expl->{key} ) { + MKDEBUG && _d('MySQL chose', $expl->{key}); + unshift @candidates, grep { $possible{$_} } split(',', $expl->{key}); + MKDEBUG && _d('Before deduping:', join(', ', @candidates)); + my %seen; + @candidates = grep { !$seen{$_}++ } @candidates; + } + MKDEBUG && _d('Final list:', join(', ', @candidates)); + return @candidates; + } + else { + MKDEBUG && _d('No keys in possible_keys'); + return (); + } +} + +sub check_table { + my ( $self, %args ) = @_; + my @required_args = qw(dbh db tbl); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my ($dbh, $db, $tbl) = @args{@required_args}; + my $q = $self->{Quoter}; + my $db_tbl = $q->quote($db, $tbl); + MKDEBUG && _d('Checking', $db_tbl); + + my $sql = "SHOW TABLES FROM " . $q->quote($db) + . ' LIKE ' . $q->literal_like($tbl); + MKDEBUG && _d($sql); + my $row; + eval { + $row = $dbh->selectrow_arrayref($sql); + }; + if ( $EVAL_ERROR ) { + MKDEBUG && _d($EVAL_ERROR); + return 0; + } + if ( !$row->[0] || $row->[0] ne $tbl ) { + MKDEBUG && _d('Table does not exist'); + return 0; + } + + MKDEBUG && _d('Table exists; no privs to check'); + return 1 unless $args{all_privs}; + + $sql = "SHOW FULL COLUMNS FROM $db_tbl"; + MKDEBUG && _d($sql); + eval { + $row = $dbh->selectrow_hashref($sql); + }; + if ( $EVAL_ERROR ) { + MKDEBUG && _d($EVAL_ERROR); + return 0; + } + if ( !scalar keys %$row ) { + MKDEBUG && _d('Table has no columns:', Dumper($row)); + return 0; + } + my $privs = $row->{privileges} || $row->{Privileges}; + + $sql = "DELETE FROM $db_tbl LIMIT 0"; + MKDEBUG && _d($sql); + eval { + $dbh->do($sql); + }; + my $can_delete = $EVAL_ERROR ? 0 : 1; + + MKDEBUG && _d('User privs on', $db_tbl, ':', $privs, + ($can_delete ? 'delete' : '')); + + if ( !($privs =~ m/select/ && $privs =~ m/insert/ && $privs =~ m/update/ + && $can_delete) ) { + MKDEBUG && _d('User does not have all privs'); + return 0; + } + + MKDEBUG && _d('User has all privs'); + return 1; +} + +sub get_engine { + my ( $self, $ddl, $opts ) = @_; + my ( $engine ) = $ddl =~ m/\).*?(?:ENGINE|TYPE)=(\w+)/; + MKDEBUG && _d('Storage engine:', $engine); + return $engine || undef; +} + +sub get_keys { + my ( $self, $ddl, $opts, $is_nullable ) = @_; + my $engine = $self->get_engine($ddl); + my $keys = {}; + my $clustered_key = undef; + + KEY: + foreach my $key ( $ddl =~ m/^ ((?:[A-Z]+ )?KEY .*)$/gm ) { + + next KEY if $key =~ m/FOREIGN/; + + my $key_ddl = $key; + MKDEBUG && _d('Parsed key:', $key_ddl); + + if ( $engine !~ m/MEMORY|HEAP/ ) { + $key =~ s/USING HASH/USING BTREE/; + } + + my ( $type, $cols ) = $key =~ m/(?:USING (\w+))? \((.+)\)/; + my ( $special ) = $key =~ m/(FULLTEXT|SPATIAL)/; + $type = $type || $special || 'BTREE'; + if ( $opts->{mysql_version} && $opts->{mysql_version} lt '004001000' + && $engine =~ m/HEAP|MEMORY/i ) + { + $type = 'HASH'; # MySQL pre-4.1 supports only HASH indexes on HEAP + } + + my ($name) = $key =~ m/(PRIMARY|`[^`]*`)/; + my $unique = $key =~ m/PRIMARY|UNIQUE/ ? 1 : 0; + my @cols; + my @col_prefixes; + foreach my $col_def ( split(',', $cols) ) { + my ($name, $prefix) = $col_def =~ m/`([^`]+)`(?:\((\d+)\))?/; + push @cols, $name; + push @col_prefixes, $prefix; + } + $name =~ s/`//g; + + MKDEBUG && _d('Key', $name, 'cols:', join(', ', @cols)); + + $keys->{$name} = { + name => $name, + type => $type, + colnames => $cols, + cols => \@cols, + col_prefixes => \@col_prefixes, + is_unique => $unique, + is_nullable => scalar(grep { $is_nullable->{$_} } @cols), + is_col => { map { $_ => 1 } @cols }, + ddl => $key_ddl, + }; + + if ( $engine =~ m/InnoDB/i && !$clustered_key ) { + my $this_key = $keys->{$name}; + if ( $this_key->{name} eq 'PRIMARY' ) { + $clustered_key = 'PRIMARY'; + } + elsif ( $this_key->{is_unique} && !$this_key->{is_nullable} ) { + $clustered_key = $this_key->{name}; + } + MKDEBUG && $clustered_key && _d('This key is the clustered key'); + } + } + + return $keys, $clustered_key; +} + +sub get_fks { + my ( $self, $ddl, $opts ) = @_; + my $fks = {}; + + foreach my $fk ( + $ddl =~ m/CONSTRAINT .* FOREIGN KEY .* REFERENCES [^\)]*\)/mg ) + { + my ( $name ) = $fk =~ m/CONSTRAINT `(.*?)`/; + my ( $cols ) = $fk =~ m/FOREIGN KEY \(([^\)]+)\)/; + my ( $parent, $parent_cols ) = $fk =~ m/REFERENCES (\S+) \(([^\)]+)\)/; + + if ( $parent !~ m/\./ && $opts->{database} ) { + $parent = "`$opts->{database}`.$parent"; + } + + $fks->{$name} = { + name => $name, + colnames => $cols, + cols => [ map { s/[ `]+//g; $_; } split(',', $cols) ], + parent_tbl => $parent, + parent_colnames=> $parent_cols, + parent_cols => [ map { s/[ `]+//g; $_; } split(',', $parent_cols) ], + ddl => $fk, + }; + } + + return $fks; +} + +sub remove_auto_increment { + my ( $self, $ddl ) = @_; + $ddl =~ s/(^\).*?) AUTO_INCREMENT=\d+\b/$1/m; + return $ddl; +} + +sub remove_secondary_indexes { + my ( $self, $ddl ) = @_; + my $sec_indexes_ddl; + my $tbl_struct = $self->parse($ddl); + + if ( ($tbl_struct->{engine} || '') =~ m/InnoDB/i ) { + my $clustered_key = $tbl_struct->{clustered_key}; + $clustered_key ||= ''; + + my @sec_indexes = map { + my $key_def = $_->{ddl}; + $key_def =~ s/([\(\)])/\\$1/g; + $ddl =~ s/\s+$key_def//; + "ADD $_->{ddl}"; + } + grep { $_->{name} ne $clustered_key } + values %{$tbl_struct->{keys}}; + MKDEBUG && _d('Secondary indexes:', Dumper(\@sec_indexes)); + + if ( @sec_indexes ) { + $sec_indexes_ddl = join(' ', @sec_indexes); + $sec_indexes_ddl =~ s/,$//; + } + + $ddl =~ s/,(\n\) )/$1/s; + } + else { + MKDEBUG && _d('Not removing secondary indexes from', + $tbl_struct->{engine}, 'table'); + } + + return $ddl, $sec_indexes_ddl, $tbl_struct; +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +1; + +# ########################################################################### +# End TableParser package +# ########################################################################### + +# ########################################################################### +# QueryReview package 3277 +# ########################################################################### + +package QueryReview; + + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); +Transformers->import(qw(make_checksum parse_timestamp)); + +use Data::Dumper; + +use constant MKDEBUG => $ENV{MKDEBUG}; + +my %basic_cols = map { $_ => 1 } + qw(checksum fingerprint sample first_seen last_seen reviewed_by + reviewed_on comments); +my %skip_cols = map { $_ => 1 } qw(fingerprint sample checksum); + +sub new { + my ( $class, %args ) = @_; + foreach my $arg ( qw(dbh db_tbl tbl_struct quoter) ) { + die "I need a $arg argument" unless $args{$arg}; + } + + foreach my $col ( keys %basic_cols ) { + die "Query review table $args{db_tbl} does not have a $col column" + unless $args{tbl_struct}->{is_col}->{$col}; + } + + my $now = defined $args{ts_default} ? $args{ts_default} : 'NOW()'; + + my $sql = <<" SQL"; + INSERT INTO $args{db_tbl} + (checksum, fingerprint, sample, first_seen, last_seen) + VALUES(CONV(?, 16, 10), ?, ?, COALESCE(?, $now), COALESCE(?, $now)) + ON DUPLICATE KEY UPDATE + first_seen = IF( + first_seen IS NULL, + COALESCE(?, $now), + LEAST(first_seen, COALESCE(?, $now))), + last_seen = IF( + last_seen IS NULL, + COALESCE(?, $now), + GREATEST(last_seen, COALESCE(?, $now))) + SQL + MKDEBUG && _d('SQL to insert into review table:', $sql); + my $insert_sth = $args{dbh}->prepare($sql); + + my @review_cols = grep { !$skip_cols{$_} } @{$args{tbl_struct}->{cols}}; + $sql = "SELECT " + . join(', ', map { $args{quoter}->quote($_) } @review_cols) + . ", CONV(checksum, 10, 16) AS checksum_conv FROM $args{db_tbl}" + . " WHERE checksum=CONV(?, 16, 10)"; + MKDEBUG && _d('SQL to select from review table:', $sql); + my $select_sth = $args{dbh}->prepare($sql); + + my $self = { + dbh => $args{dbh}, + db_tbl => $args{db_tbl}, + insert_sth => $insert_sth, + select_sth => $select_sth, + tbl_struct => $args{tbl_struct}, + quoter => $args{quoter}, + ts_default => $now, + }; + return bless $self, $class; +} + +sub set_history_options { + my ( $self, %args ) = @_; + foreach my $arg ( qw(table dbh tbl_struct col_pat) ) { + die "I need a $arg argument" unless $args{$arg}; + } + + my @cols; + my @metrics; + foreach my $col ( @{$args{tbl_struct}->{cols}} ) { + my ( $attr, $metric ) = $col =~ m/$args{col_pat}/; + next unless $attr && $metric; + $attr = ucfirst $attr if $attr =~ m/_/; # TableParser lowercases + push @cols, $col; + push @metrics, [$attr, $metric]; + } + + my $sql = "REPLACE INTO $args{table}(" + . join(', ', + map { $self->{quoter}->quote($_) } ('checksum', 'sample', @cols)) + . ') VALUES (CONV(?, 16, 10), ?, ' + . join(', ', map { + $_ eq 'ts_min' || $_ eq 'ts_max' + ? "COALESCE(?, $self->{ts_default})" + : '?' + } @cols) . ')'; + MKDEBUG && _d($sql); + + $self->{history_sth} = $args{dbh}->prepare($sql); + $self->{history_cols} = \@cols; + $self->{history_metrics} = \@metrics; +} + +sub set_review_history { + my ( $self, $id, $sample, %data ) = @_; + foreach my $thing ( qw(min max) ) { + next unless defined $data{ts} && defined $data{ts}->{$thing}; + $data{ts}->{$thing} = parse_timestamp($data{ts}->{$thing}); + } + $self->{history_sth}->execute( + make_checksum($id), + $sample, + map { $data{$_->[0]}->{$_->[1]} } @{$self->{history_metrics}}); +} + +sub get_review_info { + my ( $self, $id ) = @_; + $self->{select_sth}->execute(make_checksum($id)); + my $review_vals = $self->{select_sth}->fetchall_arrayref({}); + if ( $review_vals && @$review_vals == 1 ) { + return $review_vals->[0]; + } + return undef; +} + +sub set_review_info { + my ( $self, %args ) = @_; + $self->{insert_sth}->execute( + make_checksum($args{fingerprint}), + @args{qw(fingerprint sample)}, + map { $args{$_} ? parse_timestamp($args{$_}) : undef } + qw(first_seen last_seen first_seen first_seen last_seen last_seen)); +} + +sub review_cols { + my ( $self ) = @_; + return grep { !$skip_cols{$_} } @{$self->{tbl_struct}->{cols}}; +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +1; +# ########################################################################### +# End QueryReview package +# ########################################################################### + +# ########################################################################### +# Daemon package 4565 +# ########################################################################### + +package Daemon; + +use strict; +use warnings FATAL => 'all'; + +use POSIX qw(setsid); +use English qw(-no_match_vars); + +use constant MKDEBUG => $ENV{MKDEBUG}; + +sub new { + my ( $class, %args ) = @_; + foreach my $arg ( qw(o) ) { + die "I need a $arg argument" unless $args{$arg}; + } + my $o = $args{o}; + my $self = { + o => $o, + log_file => $o->has('log') ? $o->get('log') : undef, + PID_file => $o->has('pid') ? $o->get('pid') : undef, + }; + + check_PID_file(undef, $self->{PID_file}); + + MKDEBUG && _d('Daemonized child will log to', $self->{log_file}); + return bless $self, $class; +} + +sub daemonize { + my ( $self ) = @_; + + MKDEBUG && _d('About to fork and daemonize'); + defined (my $pid = fork()) or die "Cannot fork: $OS_ERROR"; + if ( $pid ) { + MKDEBUG && _d('I am the parent and now I die'); + exit; + } + + $self->{child} = 1; + + POSIX::setsid() or die "Cannot start a new session: $OS_ERROR"; + chdir '/' or die "Cannot chdir to /: $OS_ERROR"; + + $self->_make_PID_file(); + + $OUTPUT_AUTOFLUSH = 1; + + if ( -t STDIN ) { + close STDIN; + open STDIN, '/dev/null' + or die "Cannot reopen STDIN to /dev/null: $OS_ERROR"; + } + + if ( $self->{log_file} ) { + close STDOUT; + open STDOUT, '>>', $self->{log_file} + or die "Cannot open log file $self->{log_file}: $OS_ERROR"; + + close STDERR; + open STDERR, ">&STDOUT" + or die "Cannot dupe STDERR to STDOUT: $OS_ERROR"; + } + else { + if ( -t STDOUT ) { + close STDOUT; + open STDOUT, '>', '/dev/null' + or die "Cannot reopen STDOUT to /dev/null: $OS_ERROR"; + } + if ( -t STDERR ) { + close STDERR; + open STDERR, '>', '/dev/null' + or die "Cannot reopen STDERR to /dev/null: $OS_ERROR"; + } + } + + MKDEBUG && _d('I am the child and now I live daemonized'); + return; +} + +sub check_PID_file { + my ( $self, $file ) = @_; + my $PID_file = $self ? $self->{PID_file} : $file; + MKDEBUG && _d('Checking PID file', $PID_file); + if ( $PID_file && -f $PID_file ) { + my $pid; + eval { chomp($pid = `cat $PID_file`); }; + die "Cannot cat $PID_file: $OS_ERROR" if $EVAL_ERROR; + MKDEBUG && _d('PID file exists; it contains PID', $pid); + if ( $pid ) { + my $pid_is_alive = kill 0, $pid; + if ( $pid_is_alive ) { + die "The PID file $PID_file already exists " + . " and the PID that it contains, $pid, is running"; + } + else { + warn "Overwriting PID file $PID_file because the PID that it " + . "contains, $pid, is not running"; + } + } + else { + die "The PID file $PID_file already exists but it does not " + . "contain a PID"; + } + } + else { + MKDEBUG && _d('No PID file'); + } + return; +} + +sub make_PID_file { + my ( $self ) = @_; + if ( exists $self->{child} ) { + die "Do not call Daemon::make_PID_file() for daemonized scripts"; + } + $self->_make_PID_file(); + $self->{rm_PID_file} = 1; + return; +} + +sub _make_PID_file { + my ( $self ) = @_; + + my $PID_file = $self->{PID_file}; + if ( !$PID_file ) { + MKDEBUG && _d('No PID file to create'); + return; + } + + $self->check_PID_file(); + + open my $PID_FH, '>', $PID_file + or die "Cannot open PID file $PID_file: $OS_ERROR"; + print $PID_FH $PID + or die "Cannot print to PID file $PID_file: $OS_ERROR"; + close $PID_FH + or die "Cannot close PID file $PID_file: $OS_ERROR"; + + MKDEBUG && _d('Created PID file:', $self->{PID_file}); + return; +} + +sub _remove_PID_file { + my ( $self ) = @_; + if ( $self->{PID_file} && -f $self->{PID_file} ) { + unlink $self->{PID_file} + or warn "Cannot remove PID file $self->{PID_file}: $OS_ERROR"; + MKDEBUG && _d('Removed PID file'); + } + else { + MKDEBUG && _d('No PID to remove'); + } + return; +} + +sub DESTROY { + my ( $self ) = @_; + $self->_remove_PID_file() if $self->{child} || $self->{rm_PID_file}; + return; +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +1; + +# ########################################################################### +# End Daemon package +# ########################################################################### + +# ########################################################################### +# MemcachedProtocolParser package 5130 +# ########################################################################### +package MemcachedProtocolParser; + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); + +use Data::Dumper; +$Data::Dumper::Indent = 1; +$Data::Dumper::Sortkeys = 1; +$Data::Dumper::Quotekeys = 0; + +use constant MKDEBUG => $ENV{MKDEBUG}; + +sub new { + my ( $class, %args ) = @_; + + my ( $server_port ) + = $args{server} ? $args{server} =~ m/:(\w+)/ : ('11211'); + $server_port ||= '11211'; # In case $args{server} doesn't have a port. + + my $self = { + server => $args{server}, + server_port => $server_port, + sessions => {}, + o => $args{o}, + }; + return bless $self, $class; +} + +sub parse_event { + my ( $self, %args ) = @_; + my @required_args = qw(event); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my $packet = @args{@required_args}; + + my $src_host = "$packet->{src_host}:$packet->{src_port}"; + my $dst_host = "$packet->{dst_host}:$packet->{dst_port}"; + + if ( my $server = $self->{server} ) { # Watch only the given server. + if ( $src_host ne $server && $dst_host ne $server ) { + MKDEBUG && _d('Packet is not to or from', $server); + return; + } + } + + my $packet_from; + my $client; + if ( $src_host =~ m/:$self->{server_port}$/ ) { + $packet_from = 'server'; + $client = $dst_host; + } + elsif ( $dst_host =~ m/:$self->{server_port}$/ ) { + $packet_from = 'client'; + $client = $src_host; + } + else { + warn 'Packet is not to or from memcached server: ', Dumper($packet); + return; + } + MKDEBUG && _d('Client:', $client); + + if ( !exists $self->{sessions}->{$client} ) { + MKDEBUG && _d('New session'); + $self->{sessions}->{$client} = { + client => $client, + state => undef, + raw_packets => [], + }; + }; + my $session = $self->{sessions}->{$client}; + + if ( $packet->{data_len} == 0 ) { + MKDEBUG && _d('No TCP data'); + return; + } + + push @{$session->{raw_packets}}, $packet->{raw_packet}; + + $packet->{data} = pack('H*', $packet->{data}); + my $event; + if ( $packet_from eq 'server' ) { + $event = $self->_packet_from_server($packet, $session, $args{misc}); + } + elsif ( $packet_from eq 'client' ) { + $event = $self->_packet_from_client($packet, $session, $args{misc}); + } + else { + die 'Packet origin unknown'; + } + + MKDEBUG && _d('Done with packet; event:', Dumper($event)); + return $event; +} + +sub _packet_from_server { + my ( $self, $packet, $session, $misc ) = @_; + die "I need a packet" unless $packet; + die "I need a session" unless $session; + + MKDEBUG && _d('Packet is from server; client state:', $session->{state}); + + my $data = $packet->{data}; + + if ( !$session->{state} ) { + MKDEBUG && _d('Ignoring mid-stream server response'); + return; + } + + if ( $session->{state} eq 'awaiting reply' ) { + MKDEBUG && _d('State is awaiting reply'); + my ($line1, $rest) = $packet->{data} =~ m/\A(.*?)\r\n(.*)?/s; + + my @vals = $line1 =~ m/(\S+)/g; + $session->{res} = shift @vals; + MKDEBUG && _d('Result of last', $session->{cmd}, 'cmd:', $session->{res}); + + if ( $session->{cmd} eq 'incr' || $session->{cmd} eq 'decr' ) { + MKDEBUG && _d('It is an incr or decr'); + if ( $session->{res} !~ m/\D/ ) { # It's an integer, not an error + MKDEBUG && _d('Got a value for the incr/decr'); + $session->{val} = $session->{res}; + $session->{res} = ''; + } + } + elsif ( $session->{res} eq 'VALUE' ) { + MKDEBUG && _d('It is the result of a "get"'); + my ($key, $flags, $bytes) = @vals; + defined $session->{flags} or $session->{flags} = $flags; + defined $session->{bytes} or $session->{bytes} = $bytes; + if ( $rest && $bytes ) { + MKDEBUG && _d('There is a value'); + if ( length($rest) > $bytes ) { + MKDEBUG && _d('Looks like we got the whole response'); + $session->{val} = substr($rest, 0, $bytes); # Got the whole response. + } + else { + MKDEBUG && _d('Got partial response, saving for later'); + push @{$session->{partial}}, [ $packet->{seq}, $rest ]; + $session->{gathered} += length($rest); + $session->{state} = 'partial recv'; + return; # Prevent firing an event. + } + } + } + elsif ( $session->{res} eq 'END' ) { + MKDEBUG && _d('Got an END without any data, firing NOT_FOUND'); + $session->{res} = 'NOT_FOUND'; + } + elsif ( $session->{res} !~ m/STORED|DELETED|NOT_FOUND/ ) { + MKDEBUG && _d('Unknown result'); + } + } + else { # Should be 'partial recv' + MKDEBUG && _d('Session state: ', $session->{state}); + push @{$session->{partial}}, [ $packet->{seq}, $data ]; + $session->{gathered} += length($data); + MKDEBUG && _d('Gathered', $session->{gathered}, 'bytes in', + scalar(@{$session->{partial}}), 'packets from server'); + if ( $session->{gathered} >= $session->{bytes} + 2 ) { # Done. + MKDEBUG && _d('End of partial response, preparing event'); + my $val = join('', + map { $_->[1] } + sort { $a->[0] <=> $b->[0] } + @{$session->{partial}}); + $session->{val} = substr($val, 0, $session->{bytes}); + } + else { + MKDEBUG && _d('Partial response continues, no action'); + return; # Prevent firing event. + } + } + + MKDEBUG && _d('Creating event, deleting session'); + my $event = make_event($session, $packet); + delete $self->{sessions}->{$session->{client}}; # memcached is stateless! + $session->{raw_packets} = []; # Avoid keeping forever + return $event; +} + +sub _packet_from_client { + my ( $self, $packet, $session, $misc ) = @_; + die "I need a packet" unless $packet; + die "I need a session" unless $session; + + MKDEBUG && _d('Packet is from client; state:', $session->{state}); + + my $event; + if ( ($session->{state} || '') =~m/awaiting reply|partial recv/ ) { + MKDEBUG && _d("Expected data from the client, looks like interrupted"); + $session->{res} = 'INTERRUPTED'; + $event = make_event($session, $packet); + my $client = $session->{client}; + delete @{$session}{keys %$session}; + $session->{client} = $client; + } + + my ($line1, $val); + my ($cmd, $key, $flags, $exptime, $bytes); + + if ( !$session->{state} ) { + MKDEBUG && _d('Session state: ', $session->{state}); + ($line1, $val) = $packet->{data} =~ m/\A(.*?)\r\n(.+)?/s; + my @vals = $line1 =~ m/(\S+)/g; + $cmd = lc shift @vals; + MKDEBUG && _d('$cmd is a ', $cmd); + if ( $cmd eq 'set' || $cmd eq 'add' ) { + ($key, $flags, $exptime, $bytes) = @vals; + $session->{bytes} = $bytes; + } + elsif ( $cmd eq 'get' ) { + ($key) = @vals; + if ( $val ) { + MKDEBUG && _d('Multiple cmds:', $val); + $val = undef; + } + } + elsif ( $cmd eq 'delete' ) { + ($key) = @vals; # TODO: handle the + if ( $val ) { + MKDEBUG && _d('Multiple cmds:', $val); + $val = undef; + } + } + elsif ( $cmd eq 'incr' || $cmd eq 'decr' ) { + ($key) = @vals; + } + else { + MKDEBUG && _d("Don't know how to handle", $cmd, "command"); + } + @{$session}{qw(cmd key flags exptime)} + = ($cmd, $key, $flags, $exptime); + $session->{host} = $packet->{src_host}; + $session->{pos_in_log} = $packet->{pos_in_log}; + $session->{ts} = $packet->{ts}; + } + else { + MKDEBUG && _d('Session state: ', $session->{state}); + $val = $packet->{data}; + } + + $session->{state} = 'awaiting reply'; # Assume we got the whole packet + if ( $val ) { + if ( $session->{bytes} + 2 == length($val) ) { # +2 for the \r\n + MKDEBUG && _d('Got the whole thing'); + $val =~ s/\r\n\Z//; # We got the whole thing. + $session->{val} = $val; + } + else { # We apparently did NOT get the whole thing. + MKDEBUG && _d('Partial send, saving for later'); + push @{$session->{partial}}, + [ $packet->{seq}, $val ]; + $session->{gathered} += length($val); + MKDEBUG && _d('Gathered', $session->{gathered}, 'bytes in', + scalar(@{$session->{partial}}), 'packets from client'); + if ( $session->{gathered} >= $session->{bytes} + 2 ) { # Done. + MKDEBUG && _d('Message looks complete now, saving value'); + $val = join('', + map { $_->[1] } + sort { $a->[0] <=> $b->[0] } + @{$session->{partial}}); + $val =~ s/\r\n\Z//; + $session->{val} = $val; + } + else { + MKDEBUG && _d('Message not complete'); + $val = '[INCOMPLETE]'; + $session->{state} = 'partial send'; + } + } + } + + return $event; +} + +sub make_event { + my ( $session, $packet ) = @_; + my $event = { + cmd => $session->{cmd}, + key => $session->{key}, + val => $session->{val} || '', + res => $session->{res}, + ts => $session->{ts}, + host => $session->{host}, + flags => $session->{flags} || 0, + exptime => $session->{exptime} || 0, + bytes => $session->{bytes} || 0, + Query_time => timestamp_diff($session->{ts}, $packet->{ts}), + pos_in_log => $session->{pos_in_log}, + }; + return $event; +} + +sub _get_errors_fh { + my ( $self ) = @_; + my $errors_fh = $self->{errors_fh}; + return $errors_fh if $errors_fh; + + my $o = $self->{o}; + if ( $o && $o->has('tcpdump-errors') && $o->got('tcpdump-errors') ) { + my $errors_file = $o->get('tcpdump-errors'); + MKDEBUG && _d('tcpdump-errors file:', $errors_file); + open $errors_fh, '>>', $errors_file + or die "Cannot open tcpdump-errors file $errors_file: $OS_ERROR"; + } + + $self->{errors_fh} = $errors_fh; + return $errors_fh; +} + +sub fail_session { + my ( $self, $session, $reason ) = @_; + my $errors_fh = $self->_get_errors_fh(); + if ( $errors_fh ) { + $session->{reason_for_failure} = $reason; + my $session_dump = '# ' . Dumper($session); + chomp $session_dump; + $session_dump =~ s/\n/\n# /g; + print $errors_fh "$session_dump\n"; + { + local $LIST_SEPARATOR = "\n"; + print $errors_fh "@{$session->{raw_packets}}"; + print $errors_fh "\n"; + } + } + MKDEBUG && _d('Failed session', $session->{client}, 'because', $reason); + delete $self->{sessions}->{$session->{client}}; + return; +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +sub timestamp_diff { + my ( $start, $end ) = @_; + my $sd = substr($start, 0, 11, ''); + my $ed = substr($end, 0, 11, ''); + my ( $sh, $sm, $ss ) = split(/:/, $start); + my ( $eh, $em, $es ) = split(/:/, $end); + my $esecs = ($eh * 3600 + $em * 60 + $es); + my $ssecs = ($sh * 3600 + $sm * 60 + $ss); + if ( $sd eq $ed ) { + return sprintf '%.6f', $esecs - $ssecs; + } + else { # Assume only one day boundary has been crossed, no DST, etc + return sprintf '%.6f', ( 86_400 - $ssecs ) + $esecs; + } +} + +1; + +# ########################################################################### +# End MemcachedProtocolParser package +# ########################################################################### + +# ########################################################################### +# MemcachedEvent package 5139 +# ########################################################################### +package MemcachedEvent; + + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); + +use Data::Dumper; +$Data::Dumper::Indent = 1; +$Data::Dumper::Sortkeys = 1; +$Data::Dumper::Quotekeys = 0; + +use constant MKDEBUG => $ENV{MKDEBUG}; + +my %cmds = map { $_ => 1 } qw( + set + add + replace + append + prepend + cas + get + gets + delete + incr + decr +); + +my %cmd_handler_for = ( + set => \&handle_storage_cmd, + add => \&handle_storage_cmd, + replace => \&handle_storage_cmd, + append => \&handle_storage_cmd, + prepend => \&handle_storage_cmd, + cas => \&handle_storage_cmd, + get => \&handle_retr_cmd, + gets => \&handle_retr_cmd, +); + +sub new { + my ( $class, %args ) = @_; + my $self = {}; + return bless $self, $class; +} + +sub parse_event { + my ( $self, %args ) = @_; + my $event = $args{event}; + return unless $event; + + if ( !$event->{cmd} || !$event->{key} ) { + MKDEBUG && _d('Event has no cmd or key:', Dumper($event)); + return; + } + + if ( !$cmds{$event->{cmd}} ) { + MKDEBUG && _d("Don't know how to handle cmd:", $event->{cmd}); + return; + } + + $event->{arg} = "$event->{cmd} $event->{key}"; + $event->{fingerprint} = $self->fingerprint($event->{arg}); + $event->{key_print} = $self->fingerprint($event->{key}); + + map { $event->{"Memc_$_"} = 'No' } keys %cmds; + $event->{"Memc_$event->{cmd}"} = 'Yes'; # Got this cmd. + $event->{Memc_error} = 'No'; # A handler may change this. + $event->{Memc_miss} = 'No'; + if ( $event->{res} ) { + $event->{Memc_miss} = 'Yes' if $event->{res} eq 'NOT_FOUND'; + } + else { + MKDEBUG && _d('Event has no res:', Dumper($event)); + } + + if ( $cmd_handler_for{$event->{cmd}} ) { + return $cmd_handler_for{$event->{cmd}}->($event); + } + + return $event; +} + +sub fingerprint { + my ( $self, $val ) = @_; + $val =~ s/[0-9A-Fa-f]{16,}|\d+/?/g; + return $val; +} + +sub handle_storage_cmd { + my ( $event ) = @_; + + if ( !$event->{res} ) { + MKDEBUG && _d('No result for event:', Dumper($event)); + return; + } + + $event->{'Memc_Not_Stored'} = $event->{res} eq 'NOT_STORED' ? 'Yes' : 'No'; + $event->{'Memc_Exists'} = $event->{res} eq 'EXISTS' ? 'Yes' : 'No'; + + return $event; +} + +sub handle_retr_cmd { + my ( $event ) = @_; + + if ( !$event->{res} ) { + MKDEBUG && _d('No result for event:', Dumper($event)); + return; + } + + $event->{'Memc_error'} = $event->{res} eq 'INTERRUPTED' ? 'Yes' : 'No'; + + return $event; +} + + +sub handle_delete { + my ( $event ) = @_; + return $event; +} + +sub handle_incr_decr_cmd { + my ( $event ) = @_; + return $event; +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +1; + +# ########################################################################### +# End MemcachedEvent package +# ########################################################################### + +# ########################################################################### +# BinaryLogParser package 5134 +# ########################################################################### +package BinaryLogParser; + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); + +use Data::Dumper; +$Data::Dumper::Indent = 1; +$Data::Dumper::Sortkeys = 1; +$Data::Dumper::Quotekeys = 0; + +use constant MKDEBUG => $ENV{MKDEBUG}; + +sub new { + my ( $class, %args ) = @_; + my $self = { + delim => undef, + delim_len => 0, + }; + return bless {}, $class; +} + +my $binlog_line_1 = qr/at (\d+)$/m; +my $binlog_line_2 = qr/^#(\d{6}\s+\d{1,2}:\d\d:\d\d)\s+server\s+id\s+(\d+)\s+end_log_pos\s+(\d+)\s+(\S+)\s*([^\n]*)$/m; +my $binlog_line_2_rest = qr/thread_id=(\d+)\s+exec_time=(\d+)\s+error_code=(\d+)/m; + +sub parse_event { + my ( $self, %args ) = @_; + my @required_args = qw(fh); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my $fh = @args{@required_args}; + + local $INPUT_RECORD_SEPARATOR = ";\n#"; + my $pos_in_log = tell($fh); + my $stmt; + my ($delim, $delim_len) = ($self->{delim}, $self->{delim_len}); + + EVENT: + while ( defined($stmt = <$fh>) ) { + my @properties = ('pos_in_log', $pos_in_log); + my ($ts, $sid, $end, $type, $rest); + $pos_in_log = tell($fh); + $stmt =~ s/;\n#?\Z//; + + my ( $got_offset, $got_hdr ); + my $pos = 0; + my $len = length($stmt); + my $found_arg = 0; + LINE: + while ( $stmt =~ m/^(.*)$/mg ) { # /g requires scalar match. + $pos = pos($stmt); # Be careful not to mess this up! + my $line = $1; # Necessary for /g and pos() to work. + $line =~ s/$delim// if $delim; + MKDEBUG && _d($line); + + if ( $line =~ m/^\/\*.+\*\/;/ ) { + MKDEBUG && _d('Comment line'); + next LINE; + } + + if ( $line =~ m/^DELIMITER/m ) { + my ( $del ) = $line =~ m/^DELIMITER (\S*)$/m; + if ( $del ) { + $self->{delim_len} = $delim_len = length $del; + $self->{delim} = $delim = quotemeta $del; + MKDEBUG && _d('delimiter:', $delim); + } + else { + MKDEBUG && _d('Delimiter reset to ;'); + $self->{delim} = $delim = undef; + $self->{delim_len} = $delim_len = 0; + } + next LINE; + } + + next LINE if $line =~ m/End of log file/; + + if ( !$got_offset && (my ( $offset ) = $line =~ m/$binlog_line_1/m) ) { + MKDEBUG && _d('Got the at offset line'); + push @properties, 'offset', $offset; + $got_offset++; + } + + elsif ( !$got_hdr && $line =~ m/^#(\d{6}\s+\d{1,2}:\d\d:\d\d)/ ) { + ($ts, $sid, $end, $type, $rest) = $line =~ m/$binlog_line_2/m; + MKDEBUG && _d('Got the header line; type:', $type, 'rest:', $rest); + push @properties, 'cmd', 'Query', 'ts', $ts, 'server_id', $sid, + 'end_log_pos', $end; + $got_hdr++; + } + + elsif ( $line =~ m/^(?:#|use |SET)/i ) { + + if ( my ( $db ) = $line =~ m/^use ([^;]+)/ ) { + MKDEBUG && _d("Got a default database:", $db); + push @properties, 'db', $db; + } + + elsif ( my ($setting) = $line =~ m/^SET\s+([^;]*)/ ) { + MKDEBUG && _d("Got some setting:", $setting); + push @properties, map { s/\s+//; lc } split(/,|\s*=\s*/, $setting); + } + + } + else { + MKDEBUG && _d("Got the query/arg line at pos", $pos); + $found_arg++; + if ( $got_offset && $got_hdr ) { + if ( $type eq 'Xid' ) { + my ($xid) = $rest =~ m/(\d+)/; + push @properties, 'Xid', $xid; + } + elsif ( $type eq 'Query' ) { + my ($i, $t, $c) = $rest =~ m/$binlog_line_2_rest/m; + push @properties, 'Thread_id', $i, 'Query_time', $t, + 'error_code', $c; + } + elsif ( $type eq 'Start:' ) { + MKDEBUG && _d("Binlog start"); + } + else { + MKDEBUG && _d('Unknown event type:', $type); + next EVENT; + } + } + else { + MKDEBUG && _d("It's not a query/arg, it's just some SQL fluff"); + push @properties, 'cmd', 'Query', 'ts', undef; + } + + my $delim_len = ($pos == length($stmt) ? $delim_len : 0); + my $arg = substr($stmt, $pos - length($line) - $delim_len); + + $arg =~ s/$delim// if $delim; # Remove the delimiter. + + if ( $arg =~ m/^DELIMITER/m ) { + my ( $del ) = $arg =~ m/^DELIMITER (\S*)$/m; + if ( $del ) { + $self->{delim_len} = $delim_len = length $del; + $self->{delim} = $delim = quotemeta $del; + MKDEBUG && _d('delimiter:', $delim); + } + else { + MKDEBUG && _d('Delimiter reset to ;'); + $del = ';'; + $self->{delim} = $delim = undef; + $self->{delim_len} = $delim_len = 0; + } + + $arg =~ s/^DELIMITER.*$//m; # Remove DELIMITER from arg. + } + + $arg =~ s/;$//gm; # Ensure ending ; are gone. + $arg =~ s/\s+$//; # Remove trailing spaces and newlines. + + push @properties, 'arg', $arg, 'bytes', length($arg); + last LINE; + } + } # LINE + + if ( $found_arg ) { + MKDEBUG && _d('Properties of event:', Dumper(\@properties)); + my $event = { @properties }; + return $event; + } + else { + MKDEBUG && _d('Event had no arg'); + } + } # EVENT + + $args{oktorun}->(0) if $args{oktorun}; + return; +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +1; + +# ########################################################################### +# End BinaryLogParser package +# ########################################################################### + +# ########################################################################### +# GeneralLogParser package 5135 +# ########################################################################### +package GeneralLogParser; + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); + +use Data::Dumper; +$Data::Dumper::Indent = 1; +$Data::Dumper::Sortkeys = 1; +$Data::Dumper::Quotekeys = 0; + +use constant MKDEBUG => $ENV{MKDEBUG}; + +sub new { + my ( $class ) = @_; + my $self = { + pending => [], + db_for => {}, + }; + return bless $self, $class; +} + +my $genlog_line_1= qr{ + \A + (?:(\d{6}\s\d{1,2}:\d\d:\d\d))? # Timestamp + \s+ + (?:\s*(\d+)) # Thread ID + \s + (\w+) # Command + \s+ + (.*) # Argument + \Z +}xs; + +sub parse_event { + my ( $self, %args ) = @_; + my @required_args = qw(fh); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my $fh = @args{@required_args}; + + my $pending = $self->{pending}; + my $db_for = $self->{db_for}; + my $line; + my $pos_in_log = tell($fh); + LINE: + while ( (defined($line = shift @$pending) or defined($line = <$fh>)) ) { + MKDEBUG && _d($line); + my ($ts, $thread_id, $cmd, $arg) = $line =~ m/$genlog_line_1/; + if ( !($thread_id && $cmd) ) { + MKDEBUG && _d('Not start of general log event'); + next; + } + my @properties = ('pos_in_log', $pos_in_log, 'ts', $ts, + 'Thread_id', $thread_id); + + $pos_in_log = tell($fh); + + @$pending = (); + if ( $cmd eq 'Query' ) { + my $done = 0; + do { + $line = <$fh>; + if ( $line ) { + ($ts, $thread_id, $cmd, undef) = $line =~ m/$genlog_line_1/; + if ( $thread_id && $cmd ) { + MKDEBUG && _d('Event done'); + $done = 1; + push @$pending, $line; + } + else { + MKDEBUG && _d('More arg:', $line); + $arg .= $line; + } + } + else { + MKDEBUG && _d('No more lines'); + $done = 1; + } + } until ( $done ); + + chomp $arg; + push @properties, 'cmd', 'Query', 'arg', $arg; + push @properties, 'bytes', length($properties[-1]); + push @properties, 'db', $db_for->{$thread_id} if $db_for->{$thread_id}; + } + else { + push @properties, 'cmd', 'Admin'; + + if ( $cmd eq 'Connect' ) { + if ( $arg =~ m/^Access denied/ ) { + $cmd = $arg; + } + else { + my ($user, undef, $db) = $arg =~ /(\S+)/g; + my $host; + ($user, $host) = split(/@/, $user); + MKDEBUG && _d('Connect', $user, '@', $host, 'on', $db); + + push @properties, 'user', $user if $user; + push @properties, 'host', $host if $host; + push @properties, 'db', $db if $db; + $db_for->{$thread_id} = $db; + } + } + elsif ( $cmd eq 'Init' ) { + $cmd = 'Init DB'; + $arg =~ s/^DB\s+//; + my ($db) = $arg =~ /(\S+)/; + MKDEBUG && _d('Init DB:', $db); + push @properties, 'db', $db if $db; + $db_for->{$thread_id} = $db; + } + + push @properties, 'arg', "administrator command: $cmd"; + push @properties, 'bytes', length($properties[-1]); + } + + push @properties, 'Query_time', 0; + + MKDEBUG && _d('Properties of event:', Dumper(\@properties)); + my $event = { @properties }; + return $event; + } # LINE + + @{$self->{pending}} = (); + $args{oktorun}->(0) if $args{oktorun}; + return; +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +1; + +# ########################################################################### +# End GeneralLogParser package +# ########################################################################### + +# ########################################################################### +# ProtocolParser package 5129 +# ########################################################################### +package ProtocolParser; + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); + +eval { + require IO::Uncompress::Inflate; + IO::Uncompress::Inflate->import(qw(inflate $InflateError)); +}; + +use Data::Dumper; +$Data::Dumper::Indent = 1; +$Data::Dumper::Sortkeys = 1; +$Data::Dumper::Quotekeys = 0; + +use constant MKDEBUG => $ENV{MKDEBUG}; + +sub new { + my ( $class, %args ) = @_; + + my ($server_port) = $args{server} =~ m/:(\w+)/ if $args{server}; + $server_port = $args{server_port} if !$server_port && $args{server_port}; + + my $self = { + server => $args{server}, + server_port => $server_port, + sessions => {}, + o => $args{o}, + }; + + return bless $self, $class; +} + +sub parse_event { + my ( $self, %args ) = @_; + my @required_args = qw(event); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my $packet = @args{@required_args}; + + if ( $self->{buffer} ) { + my ($packet_from, $session) = $self->_get_session($packet); + if ( $packet->{data_len} ) { + if ( $packet_from eq 'client' ) { + push @{$session->{client_packets}}, $packet; + MKDEBUG && _d('Saved client packet'); + } + else { + push @{$session->{server_packets}}, $packet; + MKDEBUG && _d('Saved server packet'); + } + } + + return unless ($packet_from eq 'client') + && ($packet->{fin} || $packet->{rst}); + + my $event; + map { + $event = $self->_parse_packet($_, $args{misc}); + } sort { $a->{seq} <=> $b->{seq} } + @{$session->{client_packets}}; + + map { + $event = $self->_parse_packet($_, $args{misc}); + } sort { $a->{seq} <=> $b->{seq} } + @{$session->{server_packets}}; + + return $event; + } + + if ( $packet->{data_len} == 0 ) { + MKDEBUG && _d('No TCP data'); + return; + } + + return $self->_parse_packet($packet, $args{misc}); +} + +sub _parse_packet { + my ( $self, $packet, $misc ) = @_; + + my ($packet_from, $session) = $self->_get_session($packet); + MKDEBUG && _d('State:', $session->{state}); + + push @{$session->{raw_packets}}, $packet->{raw_packet} + unless $misc->{recurse}; + + if ( $session->{buff} ) { + $session->{buff_left} -= $packet->{data_len}; + if ( $session->{buff_left} > 0 ) { + MKDEBUG && _d('Added data to buff; expecting', $session->{buff_left}, + 'more bytes'); + return; + } + + MKDEBUG && _d('Got all data; buff left:', $session->{buff_left}); + $packet->{data} = $session->{buff} . $packet->{data}; + $packet->{data_len} += length $session->{buff}; + $session->{buff} = ''; + $session->{buff_left} = 0; + } + + $packet->{data} = pack('H*', $packet->{data}) unless $misc->{recurse}; + my $event; + if ( $packet_from eq 'server' ) { + $event = $self->_packet_from_server($packet, $session, $misc); + } + elsif ( $packet_from eq 'client' ) { + $event = $self->_packet_from_client($packet, $session, $misc); + } + else { + die 'Packet origin unknown'; + } + MKDEBUG && _d('State:', $session->{state}); + + if ( $session->{out_of_order} ) { + MKDEBUG && _d('Session packets are out of order'); + push @{$session->{packets}}, $packet; + $session->{ts_min} + = $packet->{ts} if $packet->{ts} lt ($session->{ts_min} || ''); + $session->{ts_max} + = $packet->{ts} if $packet->{ts} gt ($session->{ts_max} || ''); + if ( $session->{have_all_packets} ) { + MKDEBUG && _d('Have all packets; ordering and processing'); + delete $session->{out_of_order}; + delete $session->{have_all_packets}; + map { + $event = $self->_parse_packet($_, { recurse => 1 }); + } sort { $a->{seq} <=> $b->{seq} } @{$session->{packets}}; + } + } + + MKDEBUG && _d('Done with packet; event:', Dumper($event)); + return $event; +} + +sub _get_session { + my ( $self, $packet ) = @_; + + my $src_host = "$packet->{src_host}:$packet->{src_port}"; + my $dst_host = "$packet->{dst_host}:$packet->{dst_port}"; + + if ( my $server = $self->{server} ) { # Watch only the given server. + if ( $src_host ne $server && $dst_host ne $server ) { + MKDEBUG && _d('Packet is not to or from', $server); + return; + } + } + + my $packet_from; + my $client; + if ( $src_host =~ m/:$self->{server_port}$/ ) { + $packet_from = 'server'; + $client = $dst_host; + } + elsif ( $dst_host =~ m/:$self->{server_port}$/ ) { + $packet_from = 'client'; + $client = $src_host; + } + else { + warn 'Packet is not to or from server: ', Dumper($packet); + return; + } + MKDEBUG && _d('Client:', $client); + + if ( !exists $self->{sessions}->{$client} ) { + MKDEBUG && _d('New session'); + $self->{sessions}->{$client} = { + client => $client, + state => undef, + raw_packets => [], + }; + }; + my $session = $self->{sessions}->{$client}; + + return $packet_from, $session; +} + +sub _packet_from_server { + die "Don't call parent class _packet_from_server()"; +} + +sub _packet_from_client { + die "Don't call parent class _packet_from_client()"; +} + +sub make_event { + my ( $self, $session, $packet ) = @_; + die "Event has no attributes" unless scalar keys %{$session->{attribs}}; + die "Query has no arg attribute" unless $session->{attribs}->{arg}; + my $start_request = $session->{start_request} || 0; + my $start_reply = $session->{start_reply} || 0; + my $end_reply = $session->{end_reply} || 0; + MKDEBUG && _d('Request start:', $start_request, + 'reply start:', $start_reply, 'reply end:', $end_reply); + my $event = { + Query_time => $self->timestamp_diff($start_request, $start_reply), + Transmit_time => $self->timestamp_diff($start_reply, $end_reply), + }; + @{$event}{keys %{$session->{attribs}}} = values %{$session->{attribs}}; + return $event; +} + +sub _get_errors_fh { + my ( $self ) = @_; + my $errors_fh = $self->{errors_fh}; + return $errors_fh if $errors_fh; + + my $o = $self->{o}; + if ( $o && $o->has('tcpdump-errors') && $o->got('tcpdump-errors') ) { + my $errors_file = $o->get('tcpdump-errors'); + MKDEBUG && _d('tcpdump-errors file:', $errors_file); + open $errors_fh, '>>', $errors_file + or die "Cannot open tcpdump-errors file $errors_file: $OS_ERROR"; + } + + $self->{errors_fh} = $errors_fh; + return $errors_fh; +} + +sub fail_session { + my ( $self, $session, $reason ) = @_; + my $errors_fh = $self->_get_errors_fh(); + if ( $errors_fh ) { + $session->{reason_for_failure} = $reason; + my $session_dump = '# ' . Dumper($session); + chomp $session_dump; + $session_dump =~ s/\n/\n# /g; + print $errors_fh "$session_dump\n"; + { + local $LIST_SEPARATOR = "\n"; + print $errors_fh "@{$session->{raw_packets}}"; + print $errors_fh "\n"; + } + } + MKDEBUG && _d('Failed session', $session->{client}, 'because', $reason); + delete $self->{sessions}->{$session->{client}}; + return; +} + +sub timestamp_diff { + my ( $self, $start, $end ) = @_; + return 0 unless $start && $end; + my $sd = substr($start, 0, 11, ''); + my $ed = substr($end, 0, 11, ''); + my ( $sh, $sm, $ss ) = split(/:/, $start); + my ( $eh, $em, $es ) = split(/:/, $end); + my $esecs = ($eh * 3600 + $em * 60 + $es); + my $ssecs = ($sh * 3600 + $sm * 60 + $ss); + if ( $sd eq $ed ) { + return sprintf '%.6f', $esecs - $ssecs; + } + else { # Assume only one day boundary has been crossed, no DST, etc + return sprintf '%.6f', ( 86_400 - $ssecs ) + $esecs; + } +} + +sub uncompress_data { + my ( $self, $data, $len ) = @_; + die "I need data" unless $data; + die "I need a len argument" unless $len; + die "I need a scalar reference to data" unless ref $data eq 'SCALAR'; + MKDEBUG && _d('Uncompressing data'); + our $InflateError; + + my $comp_bin_data = pack('H*', $$data); + + my $uncomp_bin_data = ''; + my $z = new IO::Uncompress::Inflate( + \$comp_bin_data + ) or die "IO::Uncompress::Inflate failed: $InflateError"; + my $status = $z->read(\$uncomp_bin_data, $len) + or die "IO::Uncompress::Inflate failed: $InflateError"; + + my $uncomp_data = unpack('H*', $uncomp_bin_data); + + return \$uncomp_data; +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +1; + +# ########################################################################### +# End ProtocolParser package +# ########################################################################### + +# ########################################################################### +# HTTPProtocolParser package 5121 +# ########################################################################### +package HTTPProtocolParser; +use base 'ProtocolParser'; + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); + +use Data::Dumper; +$Data::Dumper::Indent = 1; +$Data::Dumper::Sortkeys = 1; +$Data::Dumper::Quotekeys = 0; + +use constant MKDEBUG => $ENV{MKDEBUG}; + +sub new { + my ( $class, %args ) = @_; + my $self = $class->SUPER::new( + %args, + server_port => 80, + ); + return $self; +} + +sub _packet_from_server { + my ( $self, $packet, $session, $misc ) = @_; + die "I need a packet" unless $packet; + die "I need a session" unless $session; + + MKDEBUG && _d('Packet is from server; client state:', $session->{state}); + + if ( !$session->{state} ) { + MKDEBUG && _d('Ignoring mid-stream server response'); + return; + } + + if ( $session->{out_of_order} ) { + my ($line1, $content); + if ( !$session->{have_header} ) { + ($line1, $content) = $self->_parse_header( + $session, $packet->{data}, $packet->{data_len}); + } + if ( $line1 ) { + $session->{have_header} = 1; + $packet->{content_len} = length $content; + MKDEBUG && _d('Got out of order header with', + $packet->{content_len}, 'bytes of content'); + } + my $have_len = $packet->{content_len} || $packet->{data_len}; + map { $have_len += $_->{data_len} } + @{$session->{packets}}; + $session->{have_all_packets} + = 1 if $session->{attribs}->{bytes} + && $have_len >= $session->{attribs}->{bytes}; + MKDEBUG && _d('Have', $have_len, 'of', $session->{attribs}->{bytes}); + return; + } + + if ( $session->{state} eq 'awaiting reply' ) { + + $session->{start_reply} = $packet->{ts} unless $session->{start_reply}; + + my ($line1, $content) = $self->_parse_header($session, $packet->{data}, + $packet->{data_len}); + + if ( !$line1 ) { + $session->{out_of_order} = 1; # alert parent + $session->{have_all_packets} = 0; + return; + } + + my ($version, $code, $phrase) = $line1 =~ m/(\S+)/g; + $session->{attribs}->{Status_code} = $code; + MKDEBUG && _d('Status code for last', $session->{attribs}->{arg}, + 'request:', $session->{attribs}->{Status_code}); + + my $content_len = $content ? length $content : 0; + MKDEBUG && _d('Got', $content_len, 'bytes of content'); + if ( $session->{attribs}->{bytes} + && $content_len < $session->{attribs}->{bytes} ) { + $session->{data_len} = $session->{attribs}->{bytes}; + $session->{buff} = $content; + $session->{buff_left} = $session->{attribs}->{bytes} - $content_len; + MKDEBUG && _d('Contents not complete,', $session->{buff_left}, + 'bytes left'); + $session->{state} = 'recving content'; + return; + } + } + elsif ( $session->{state} eq 'recving content' ) { + if ( $session->{buff} ) { + MKDEBUG && _d('Receiving content,', $session->{buff_left}, + 'bytes left'); + return; + } + MKDEBUG && _d('Contents received'); + } + else { + warn "Server response in unknown state"; + return; + } + + MKDEBUG && _d('Creating event, deleting session'); + $session->{end_reply} = $session->{ts_max} || $packet->{ts}; + my $event = $self->make_event($session, $packet); + delete $self->{sessions}->{$session->{client}}; # http is stateless! + return $event; +} + +sub _packet_from_client { + my ( $self, $packet, $session, $misc ) = @_; + die "I need a packet" unless $packet; + die "I need a session" unless $session; + + MKDEBUG && _d('Packet is from client; state:', $session->{state}); + + my $event; + if ( ($session->{state} || '') =~ m/awaiting / ) { + MKDEBUG && _d('More client headers:', $packet->{data}); + return; + } + + if ( !$session->{state} ) { + $session->{state} = 'awaiting reply'; + my ($line1, undef) = $self->_parse_header($session, $packet->{data}, $packet->{data_len}); + my ($request, $page, $version) = $line1 =~ m/(\S+)/g; + if ( !$request || !$page ) { + MKDEBUG && _d("Didn't get a request or page:", $request, $page); + return; + } + $request = lc $request; + my $vh = $session->{attribs}->{Virtual_host} || ''; + my $arg = "$request $vh$page"; + MKDEBUG && _d('arg:', $arg); + + if ( $request eq 'get' || $request eq 'post' ) { + @{$session->{attribs}}{qw(arg)} = ($arg); + } + else { + MKDEBUG && _d("Don't know how to handle a", $request, "request"); + return; + } + + $session->{start_request} = $packet->{ts}; + $session->{attribs}->{host} = $packet->{src_host}; + $session->{attribs}->{pos_in_log} = $packet->{pos_in_log}; + $session->{attribs}->{ts} = $packet->{ts}; + } + else { + die "Probably multiple GETs from client before a server response?"; + } + + return $event; +} + +sub _parse_header { + my ( $self, $session, $data, $len, $no_recurse ) = @_; + die "I need data" unless $data; + my ($header, $content) = split(/\r\n\r\n/, $data); + my ($line1, $header_vals) = $header =~ m/\A(\S+ \S+ .+?)\r\n(.+)?/s; + MKDEBUG && _d('HTTP header:', $line1); + return unless $line1; + + if ( !$header_vals ) { + MKDEBUG && _d('No header vals'); + return $line1, undef; + } + my @headers; + foreach my $val ( split(/\r\n/, $header_vals) ) { + last unless $val; + MKDEBUG && _d('HTTP header:', $val); + if ( $val =~ m/^Content-Length/i ) { + ($session->{attribs}->{bytes}) = $val =~ /: (\d+)/; + MKDEBUG && _d('Saved Content-Length:', $session->{attribs}->{bytes}); + } + if ( $val =~ m/Content-Encoding/i ) { + ($session->{compressed}) = $val =~ /: (\w+)/; + MKDEBUG && _d('Saved Content-Encoding:', $session->{compressed}); + } + if ( $val =~ m/^Host/i ) { + ($session->{attribs}->{Virtual_host}) = $val =~ /: (\S+)/; + MKDEBUG && _d('Saved Host:', ($session->{attribs}->{Virtual_host})); + } + } + return $line1, $content; +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +1; + +# ########################################################################### +# End HTTPProtocolParser package +# ########################################################################### + +# ########################################################################### +# ExecutionThrottler package 5204 +# ########################################################################### +package ExecutionThrottler; + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); + +use List::Util qw(sum min max); +use Time::HiRes qw(time); +use Data::Dumper; +$Data::Dumper::Indent = 1; +$Data::Dumper::Sortkeys = 1; +$Data::Dumper::Quotekeys = 0; + +use constant MKDEBUG => $ENV{MKDEBUG}; + +sub new { + my ( $class, %args ) = @_; + my @required_args = qw(rate_max get_rate check_int step); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless defined $args{$arg}; + } + my $self = { + step => 0.05, # default + %args, + rate_ok => undef, + last_check => undef, + stats => { + rate_avg => 0, + rate_samples => [], + }, + int_rates => [], + skip_prob => 0.0, + }; + + return bless $self, $class; +} + +sub throttle { + my ( $self, %args ) = @_; + my $time = $args{misc}->{time} || time; + if ( $self->_time_to_check($time) ) { + my $rate_avg = (sum(@{$self->{int_rates}}) || 0) + / (scalar @{$self->{int_rates}} || 1); + my $running_avg = $self->_save_rate_avg($rate_avg); + MKDEBUG && _d('Average rate for last interval:', $rate_avg); + + if ( $args{stats} ) { + $args{stats}->{throttle_checked_rate}++; + $args{stats}->{throttle_rate_avg} = sprintf '%.2f', $running_avg; + } + + @{$self->{int_rates}} = (); + + if ( $rate_avg > $self->{rate_max} ) { + $self->{skip_prob} += $self->{step}; + $self->{skip_prob} = 1.0 if $self->{skip_prob} > 1.0; + MKDEBUG && _d('Rate max exceeded'); + $args{stats}->{throttle_rate_max_exceeded}++ if $args{stats}; + } + else { + $self->{skip_prob} -= $self->{step}; + $self->{skip_prob} = 0.0 if $self->{skip_prob} < 0.0; + $args{stats}->{throttle_rate_ok}++ if $args{stats}; + } + + MKDEBUG && _d('Skip probability:', $self->{skip_prob}); + $self->{last_check} = $time; + } + else { + my $current_rate = $self->{get_rate}->(); + push @{$self->{int_rates}}, $current_rate; + if ( $args{stats} ) { + $args{stats}->{throttle_rate_min} = min( + ($args{stats}->{throttle_rate_min} || ()), $current_rate); + $args{stats}->{throttle_rate_max} = max( + ($args{stats}->{throttle_rate_max} || ()), $current_rate); + } + MKDEBUG && _d('Current rate:', $current_rate); + } + + if ( $args{event} ) { + $args{event}->{Skip_exec} = $self->{skip_prob} <= rand() ? 'No' : 'Yes'; + } + + return $args{event}; +} + +sub _time_to_check { + my ( $self, $time ) = @_; + if ( !$self->{last_check} ) { + $self->{last_check} = $time; + return 0; + } + return $time - $self->{last_check} >= $self->{check_int} ? 1 : 0; +} + +sub rate_avg { + my ( $self ) = @_; + return $self->{stats}->{rate_avg} || 0; +} + +sub skip_probability { + my ( $self ) = @_; + return $self->{skip_prob}; +} + +sub _save_rate_avg { + my ( $self, $rate ) = @_; + my $samples = $self->{stats}->{rate_samples}; + push @$samples, $rate; + shift @$samples if @$samples > 1_000; + $self->{stats}->{rate_avg} = sum(@$samples) / (scalar @$samples); + return $self->{stats}->{rate_avg} || 0; +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +1; + +# ########################################################################### +# End ExecutionThrottler package +# ########################################################################### + +# ########################################################################### +# This is a combination of modules and programs in one -- a runnable module. +# http://www.perl.com/pub/a/2006/07/13/lightning-articles.html?page=last +# Or, look it up in the Camel book on pages 642 and 643 in the 3rd edition. +# +# Check at the end of this package for the call to main() which actually runs +# the program. +# ########################################################################### +package mk_query_digest; + +use English qw(-no_match_vars); +use Time::Local qw(timelocal); +use Time::HiRes qw(time usleep); +use Data::Dumper; +$Data::Dumper::Indent = 1; +$OUTPUT_AUTOFLUSH = 1; + +Transformers->import(qw(shorten micro_t percentage_of ts make_checksum + any_unix_timestamp)); + +use constant MKDEBUG => $ENV{MKDEBUG}; + +use sigtrap 'handler', \&sig_int, 'normal-signals'; + +# Global variables. Only really essential variables should be here. +my $oktorun = 1; +my $dp = new DSNParser ( + { key => 'D', copy => 1, desc => 'Database that contains the query review table' }, + { key => 't', desc => 'Table to use as the query review table' } ); +my $q = new Quoter(); +my $qp = new QueryParser(); +my $qr = new QueryRewriter(QueryParser=>$qp); +my $ex_dbh; # For --execute +my $ep_dbh; # For --explain +my $ps_dbh; # For Processlist +my $aux_dbh; # For --aux-dsn (--since/--until "MySQL expression") + +sub main { + @ARGV = @_; # set global ARGV for this package + + # ########################################################################## + # Get configuration information. + # ########################################################################## + my $o = new OptionParser( + strict => 0, + dp => $dp, + prompt => '[OPTION...] [FILE]', + description => q{parses and analyzes MySQL log files. With no } + . q{FILE, or when FILE is -, read standard input.}, + ); + $o->get_specs(); + $o->get_opts(); + + $dp->prop('set-vars', $o->get('set-vars')); + + # Frequently used options. + my $review_dsn = $o->get('review'); + my @groupby = @{$o->get('group-by')}; + my @orderby; + if ( (grep { $_ eq 'genlog' || $_ eq 'GeneralLogParser' } @{$o->get('type')}) + && !$o->got('order-by') ) { + @orderby = 'Query_time:cnt'; + } + else { + @orderby = @{$o->get('order-by')}; + } + + if ( !$o->get('help') ) { + if ( $review_dsn + && (!defined $review_dsn->{D} || !defined $review_dsn->{t}) ) { + $o->save_error('The --review DSN requires a D (database) and t' + . ' (table) part specifying the query review table'); + } + if ( $o->get('mirror') + && (!$o->get('execute') || !$o->get('processlist')) ) { + $o->save_error('--mirror requires --execute and --processlist'); + } + if ( $o->get('outliers') + && grep { $_ !~ m/^\w+:[0-9.]+(?::[0-9.]+)?$/ } @{$o->get('outliers')} + ) { + $o->save_error('--outliers requires two or three colon-separated fields'); + } + if ( $o->get('execute-throttle') ) { + my ($rate_max, $int, $step) = @{$o->get('execute-throttle')}; + $o->save_error("--execute-throttle max time must be between 1 and 100") + unless $rate_max && $rate_max > 0 && $rate_max <= 100; + $o->save_error("No check interval value for --execute-throttle") + unless $int; + $o->save_error("--execute-throttle check interval must be an integer") + if $int =~ m/[^\d]/; + $o->save_error("--execute-throttle step must be between 1 and 100") + if $step && ($step < 1 || $step > 100); + } + } + + # Set an orderby for each groupby; use the default orderby if there + # are more groupby than orderby attribs. + my $default_orderby = $o->get_defaults()->{'order-by'}; + foreach my $i ( 0..$#groupby ) { + $orderby[$i] ||= $default_orderby; + } + $o->set('order-by', \@orderby); + + $o->usage_or_errors(); + + # ######################################################################## + # Set up for --explain + # ######################################################################## + if ( $o->get('explain') ) { + $ep_dbh = $dp->get_dbh( + $dp->get_cxn_params($o->get('explain')), {AutoCommit => 1}); + $ep_dbh->{InactiveDestroy} = 1; # Don't die on fork(). + } + + # ######################################################################## + # Set up for --review and --review-history. + # ######################################################################## + my $qv; # QueryReview + my $qv_dbh; # For QueryReview + my $qv_dbh2; # For QueryReview and --review-history + if ( $review_dsn ) { + my $tp = new TableParser(Quoter => $q); + my $du = new MySQLDump(); + $qv_dbh = $dp->get_dbh( + $dp->get_cxn_params($review_dsn), {AutoCommit => 1}); + $qv_dbh->{InactiveDestroy} = 1; # Don't die on fork(). + my @db_tbl = @{$review_dsn}{qw(D t)}; + my $db_tbl = $q->quote(@db_tbl); + + # Create the review table if desired + if ( $o->get('create-review-table') ) { + my $sql = $o->read_para_after( + __FILE__, qr/MAGIC_create_review/); + $sql =~ s/query_review/IF NOT EXISTS $db_tbl/; + MKDEBUG && _d($sql); + $qv_dbh->do($sql); + } + + # Check for existence and the permissions to insert into the + # table. + if ( !$tp->check_table( + dbh => $qv_dbh, + db => $db_tbl[0], + tbl => $db_tbl[1], + all_privs => 1) ) + { + die "The query review table $db_tbl " + . "does not exist or you do not have INSERT privileges"; + } + + # Set up the new QueryReview object. + my $struct = $tp->parse($du->get_create_table($qv_dbh, $q, @db_tbl)); + $qv = new QueryReview( + dbh => $qv_dbh, + db_tbl => $db_tbl, + tbl_struct => $struct, + quoter => $q, + ); + + # Set up the review-history table + if ( $o->get('review-history') ) { + $qv_dbh2 = $dp->get_dbh( + $dp->get_cxn_params($o->get('review-history')), {AutoCommit => 1}); + $qv_dbh2->{InactiveDestroy} = 1; # Don't die on fork(). + my @hdb_tbl = @{$o->get('review-history')}{qw(D t)}; + my $hdb_tbl = $q->quote(@hdb_tbl); + + # Create the review-history table if desired + if ( $o->get('create-review-history-table') ) { + my $sql = $o->read_para_after( + __FILE__, qr/MAGIC_create_review_history/); + $sql =~ s/query_review_history/IF NOT EXISTS $hdb_tbl/; + MKDEBUG && _d($sql); + $qv_dbh2->do($sql); + } + + # Check for existence and the permissions to insert into the + # table. + if ( !$tp->check_table( + dbh => $qv_dbh2, + db => $hdb_tbl[0], + tbl => $hdb_tbl[1], + all_privs => 1) ) + { + die "The query review history table $hdb_tbl " + . "does not exist or you do not have INSERT privileges"; + } + + # Inspect for MAGIC_history_cols. Add them to the --select list + # only if an explicit --select list was given. Otherwise, leave + # --select undef which will cause EventAggregator to aggregate every + # attribute available which will include the history columns. + # If no --select list was given and we make one by adding the history + # columsn to it, then EventAggregator will only aggregate the + # history columns and nothing else--we don't want this. + my $tbl = $tp->parse($du->get_create_table($qv_dbh2, $q, @hdb_tbl)); + my $pat = $o->read_para_after(__FILE__, qr/MAGIC_history_cols/); + $pat =~ s/\s+//g; + $pat = qr/^(.*?)_($pat)$/; + # Get original --select values. + my %select = map { $_ => 1 } @{$o->get('select')}; + foreach my $col ( @{$tbl->{cols}} ) { + my ( $attr, $metric ) = $col =~ m/$pat/; + next unless $attr && $metric; + $attr = ucfirst $attr if $attr =~ m/_/; # TableParser lowercases + # Add history table values to original select values. + $select{$attr}++; + } + + if ( $o->got('select') ) { + # Re-set --select with its original values plus the history + # table values. + $o->set('select', [keys %select]); + MKDEBUG && _d("--select after parsing --review-history table:", + @{$o->get('select')}); + } + + # And tell the QueryReview that it has more work to do. + $qv->set_history_options( + table => $hdb_tbl, + dbh => $qv_dbh2, + tbl_struct => $tbl, + col_pat => $pat, + ); + } + } + + # ######################################################################## + # Set up an array of callbacks to filter and transform events. The first + # one should add the fingerprint to the event (except if we're parsing + # tcpdump output; see below). After that, callbacks can do anything, as + # long as they return the event (failing to return the event terminates + # the chain). + # ######################################################################## + my @callbacks; + my %callback_names; + my %prof; # pipeline profile + my %stats; # general stats + my $misc = {}; + if ( $o->get('processlist') ) { + my $pl = new Processlist(); + my ( $sth, $cxn ); + my $cur_server = 'processlist'; + my $cur_time = 0; + + $misc = { + time => 0, + etime => 0, + code => sub { + my $time = $misc->{time} = time(); + my $err; + do { + eval { $sth->execute; }; + $err = $EVAL_ERROR; + if ( $err ) { # Try to reconnect when there's an error. + @{$misc}{qw(time etime)} = (0, 0); + eval { + ($cur_server, $ps_dbh) = find_role( + $o, $ps_dbh, $cur_server, 0, 'for --processlist'); + $cur_time = time(); + $sth = $ps_dbh->prepare('SHOW FULL PROCESSLIST'); + $cxn = $ps_dbh->{mysql_thread_id}; + $sth->execute(); + }; + $err = $EVAL_ERROR; + if ( $err ) { + print STDERR $err; + sleep 1; + } + } + } until ( $sth && !$err ); + if ( $o->get('mirror') + && time() - $cur_time > $o->get('mirror')) { + ($cur_server, $ps_dbh) = find_role($o, $ps_dbh, $cur_server, + 0, 'for --processlist'); + $cur_time = time(); + } + $misc->{etime} = time() - $time; + [ grep { $_->[0] != $cxn } @{ $sth->fetchall_arrayref(); } ]; + }, + }; + + push @callbacks, sub { + my ( $event, %args ) = @_; + return $pl->parse_event(%args); + }; + $callback_names{$callbacks[-1]} = ref $pl; + MKDEBUG && _d('Added Processlist module to callbacks'); + } + else { + my %alias_for = ( + slowlog => ['SlowLogParser'], + binlog => ['BinaryLogParser'], + genlog => ['GeneralLogParser'], + tcpdump => ['TcpdumpParser','MySQLProtocolParser'], + memcached => ['TcpdumpParser','MemcachedProtocolParser', + 'MemcachedEvent'], + http => ['TcpdumpParser','HTTPProtocolParser'], + ); + my $type = $o->get('type'); + $type = $alias_for{$type->[0]} if $alias_for{$type->[0]}; + + foreach my $module ( @$type ) { + my $parser; + eval { + $parser = $module->new( + server => $o->get('watch-server'), + o => $o, + ); + }; + if ( $EVAL_ERROR ) { + die "Failed to load $module module: $EVAL_ERROR"; + } + push @callbacks, sub { + my ( $event, %args ) = @_; + return $parser->parse_event(%args); + }; + $callback_names{$callbacks[-1]} = ref $parser; + MKDEBUG && _d('Added', $module, 'module to callbacks'); + } + } + + # Filter early for --since and --until. + my $past_since; + my $at_until; + # If --since or --until is a MySQL expression, then any_unix_timestamp() + # will need this callback to execute the expression. We don't know what + # type of time value the user gave, so we'll create the callback in any case. + if ( my $aux_dsn = $o->get('aux-dsn') ) { + $aux_dbh = $dp->get_dbh($dp->get_cxn_params($aux_dsn), {AutoCommit => 1}); + $aux_dbh->{InactiveDestroy} = 1; # Don't die on fork(). + } + $aux_dbh ||= $qv_dbh || $qv_dbh2 || $ex_dbh || $ps_dbh || $ep_dbh; + MKDEBUG && _d('aux dbh:', $aux_dbh); + my $time_callback = sub { + my ( $exp ) = @_; + return unless $aux_dbh; + my $sql = "SELECT UNIX_TIMESTAMP($exp)"; + MKDEBUG && _d($sql); + return $aux_dbh->selectall_arrayref($sql)->[0]->[0]; + }; + if ( $o->get('since') ) { + my $since = any_unix_timestamp($o->get('since'), $time_callback); + die "Invalid --since value" unless $since; + push @callbacks, sub { + my ( $event ) = @_; + MKDEBUG && _d('callback: --since'); + if ( $past_since ) { + MKDEBUG && _d('Already past --since'); + return $event; + } + if ( $event->{ts} ) { + my $ts = any_unix_timestamp($event->{ts}, $time_callback); + if ( ($ts || 0) >= $since ) { + MKDEBUG && _d('Event is at or past --since'); + $past_since = 1; + return $event; + } + else { + MKDEBUG && _d('Event is before --since'); + } + } + return; + }; + $callback_names{$callbacks[-1]} = 'since'; + } + if ( $o->get('until') ) { + my $until = any_unix_timestamp($o->get('until'), $time_callback); + die "Invalid --until value" unless $until; + push @callbacks, sub { + my ( $event ) = @_; + MKDEBUG && _d('callback: --until'); + if ( $at_until ) { + MKDEBUG && _d('Already past --until'); + return; + } + if ( $event->{ts} ) { + my $ts = any_unix_timestamp($event->{ts}, $time_callback); + if ( ($ts || 0) >= $until ) { + MKDEBUG && _d('Event at or after --until'); + $at_until = 1; + return; + } + else { + MKDEBUG && _d('Event is before --until'); + } + } + return $event; + }; + $callback_names{$callbacks[-1]} = 'until'; + } + + if ( grep { $_ eq 'fingerprint' } @groupby ) { + push @callbacks, sub { + my ( $event ) = @_; + MKDEBUG && _d('callback: fingerprint'); + # Skip events which do not have the groupby attribute. + my $groupby_val = $event->{arg}; + return unless $groupby_val; + $event->{fingerprint} = $qr->fingerprint($groupby_val); + return $event; + }; + $callback_names{$callbacks[-1]} = 'fingerprint'; + } + + # Make subs which map attrib aliases to their primary attrib. + foreach my $alt_attrib ( @{$o->get('attribute-aliases')} ) { + push @callbacks, make_alt_attrib($alt_attrib); + $callback_names{$callbacks[-1]} = 'attribute aliases'; + } + + # Carry attribs forward for --inherit-attributes. + my $prev_vals = {}; + my $inherit_attrib_sub = make_inherit_attribs( + $o->get('inherit-attributes'), + $prev_vals + ); + push @callbacks, $inherit_attrib_sub if $inherit_attrib_sub; + $callback_names{$callbacks[-1]} = 'inherit attributes'; + + if ( grep { $_ eq 'tables' } @groupby ) { + push @callbacks, sub { + my ( $event ) = @_; + MKDEBUG && _d('callback: tables'); + my $group_by_val = $event->{arg}; + return 0 unless defined $group_by_val; + $event->{tables} = [ + map { + # Canonicalize and add the db name in front + $_ =~ s/`//g; + if ($_ !~ m/\./ && (my $db = $event->{db} || $event->{Schema})) { + $_ = "$db.$_"; + } + $_; + } + $qp->get_tables($group_by_val) + ]; + return $event; + }; + $callback_names{$callbacks[-1]} = 'tables'; + } + + my %distill_args; + if ( $o->get('type') eq 'memcached' || $o->get('type') eq 'http' ) { + $distill_args{generic} = 1; + if ( $o->get('type') eq 'http' ) { + # Remove stuff after url. + $distill_args{trf} = sub { + my ( $query ) = @_; + $query =~ s/(\S+ \S+?)(?:[?;].+)/$1/; + return $query; + }; + } + } + if ( grep { $_ eq 'distill' } @groupby ) { + push @callbacks, sub { + my ( $event ) = @_; + MKDEBUG && _d('callback: distill'); + my $group_by_val = $event->{arg}; + return 0 unless defined $group_by_val; + $event->{distill} = $qr->distill($group_by_val, %distill_args); + MKDEBUG && !$event->{distill} && _d('Cannot distill', $event->{arg}); + return $event; + }; + $callback_names{$callbacks[-1]} = 'distill'; + } + + # Filter after special attributes, like fingerprint, tables, + # distill, etc., have been created. + if ( $o->get('filter') ) { + my $filter = $o->get('filter'); + if ( -f $filter && -r $filter ) { + MKDEBUG && _d('Reading file', $filter, 'for --filter code'); + open my $fh, "<", $filter or die "Cannot open $filter: $OS_ERROR"; + $filter = do { local $/ = undef; <$fh> }; + close $fh; + } + else { + $filter = "( $filter )"; # issue 565 + } + my $code = "sub { MKDEBUG && _d('callback: filter'); my(\$event) = shift; $filter && return \$event; };"; + MKDEBUG && _d('--filter code:', $code); + my $sub = eval $code + or die "Error compiling --filter code: $code\n$EVAL_ERROR"; + push @callbacks, $sub; + $callback_names{$callbacks[-1]} = 'filter'; + } + + if ( $o->get('zero-admin') ) { + push @callbacks, sub { + my ( $event ) = @_; + MKDEBUG && _d('callback: zero admin'); + if ( $event->{arg} && $event->{arg} =~ m/^# administrator/ ) { + $event->{Rows_sent} = 0; + $event->{Rows_read} = 0; + $event->{Rows_examined} = 0; + } + return $event; + }; + $callback_names{$callbacks[-1]} = 'zero admin'; + } + + if ( $o->got('sample') ) { + my $group_by_val = $groupby[0]; + my $num_samples = $o->get('sample'); + if ( $group_by_val ) { + my %seen; + push @callbacks, sub { + my ($event) = @_; + MKDEBUG && _d('callback: sample'); + if ( ++$seen{$event->{$group_by_val}} <= $num_samples ) { + MKDEBUG && _d("--sample permits event", + $event->{$group_by_val}); + return $event; + } + MKDEBUG && _d("--sample rejects event", $event->{$group_by_val}); + return; + }; + $callback_names{$callbacks[-1]} = 'sample'; + } + } + + if ( $o->get('print') ) { + my $w = new SlowLogWriter(); + push @callbacks, sub { + my ( $event ) = @_; + MKDEBUG && _d('callback: print'); + $w->write(*STDOUT, $event); + return $event; + }; + $callback_names{$callbacks[-1]} = 'print'; + } + + my $et; + if ( my $et_args = $o->get('execute-throttle') ) { + # These were check earlier; no need to check them again. + my ($rate_max, $int, $step) = @{$o->get('execute-throttle')}; + $step ||= 5; + $step /= 100; # step specified as percent but $et expect 0.1=10%, etc. + MKDEBUG && _d('Execute throttle:', $rate_max, $int, $step); + + my $get_rate = sub { + return percentage_of( + $prof{callback}->{'execute'}->{time} || 0, + $prof{total}->{time} || 0, + ); + }; + + $et = new ExecutionThrottler( + rate_max => $rate_max, + get_rate => $get_rate, + check_int => $int, + step => $step, + ); + push @callbacks, sub { + my ( $event, %args ) = @_; + MKDEBUG && _d('callback: throttle'); + return $et->throttle(%args); + }; + $callback_names{$callbacks[-1]} = 'execute throttle'; + } + + if ( $o->get('execute') ) { + my $cur_server = 'execute'; + ($cur_server, $ex_dbh) = find_role($o, $ex_dbh, $cur_server, + 1, 'for --execute'); + my $cur_time = time(); + my $curdb; + my $default_db = $o->get('execute')->{D}; + MKDEBUG && _d('Default db:', $default_db); + push @callbacks, sub { + my ( $event ) = @_; + MKDEBUG && _d('callback: execute'); + $event->{Exec_orig_time} = $event->{Query_time}; + if ( ($event->{Skip_exec} || '') eq 'Yes' ) { + MKDEBUG && _d('Not executing event because of --execute-throttle'); + # Zero Query_time to 'Exec time' will show the real time + # spent executing queries. + $event->{Query_time} = 0; + $stats{execute_skipped}++; + return $event; + } + $stats{execute_executed}++; + my $db = $event->{db} || $default_db; + eval { + if ( $db && (!$curdb || $db ne $curdb) ) { + MKDEBUG && _d('USE ', $db); + $ex_dbh->do("USE $db"); + $curdb = $db; + } + my $start = time(); + $ex_dbh->do($event->{arg}); + my $end = time(); + $event->{Query_time} = $end - $start; + $event->{Exec_diff_time} + = $event->{Query_time} - $event->{Exec_orig_time}; + if ( $o->get('mirror') && $end - $cur_time > $o->get('mirror') ) { + ($cur_server, $ex_dbh) = find_role($o, $ex_dbh, $cur_server, + 1, 'for --execute'); + $cur_time = $end; + } + }; + if ( $EVAL_ERROR ) { + MKDEBUG && _d($EVAL_ERROR); + $stats{execute_error}++; + # Don't try to re-execute the statement. Just skip it. + if ( $EVAL_ERROR =~ m/server has gone away/ ) { + print STDERR $EVAL_ERROR; + eval { + ($cur_server, $ex_dbh) = find_role($o, $ex_dbh, $cur_server, + 1, 'for --execute'); + $cur_time = time(); + }; + if ( $EVAL_ERROR ) { + print STDERR $EVAL_ERROR; + sleep 1; + } + return 0; + } + if ( $EVAL_ERROR =~ m/No database/ ) { + $stats{execute_no_database}++; + } + } + return $event; + }; + $callback_names{$callbacks[-1]} = 'execute'; + } + + # Finally, add aggregator obj for each groupby attrib to the callbacks. + # These aggregating objs should be the last callbacks. + my @ea; # EventAggregators + my @tl; # EventTimeline (aggregators) + foreach my $i ( 0..$#groupby ) { + my $groupby = $groupby[$i]; + + # This shouldn't happen. + die "No --order-by value for --group-by $groupby" unless $orderby[$i]; + + my ( $orderby_attrib, $orderby_func ) = split(/:/, $orderby[$i]); + + my %attributes = map { + my ($name, @alt) = split(/:/, $_); + $name => [$name, @alt]; + } + grep { $_ !~ m/^$groupby\b/ } + @{$o->get('select')}; + + # Create an EventAggregator for this groupby attrib and + # add it to callbacks. + my $ea = new EventAggregator( + groupby => $groupby, + attributes => { %attributes }, + worst => $orderby_attrib, + attrib_limit => $o->get('attribute-value-limit'), + ignore_attributes => $o->get('ignore-attributes'), + unroll_limit => $o->get('check-attributes-limit'), + type_for => { + val => 'string', + key_print => 'string', + Status_code => 'string', + }, + ); + push @ea, $ea; + push @callbacks, sub { + my ( $event ) = @_; + $ea->aggregate($event); + return $event; + }; + $callback_names{$callbacks[-1]} = "aggregate $groupby"; + + # If user wants a timeline report, too, then create an EventTimeline + # aggregator for this groupby attrib and add it to the callbacks, too. + if ( $o->get('timeline') ) { + my $tl = new EventTimeline( + groupby => [$groupby], + attributes => [qw(Query_time ts)], + ); + push @tl, $tl; + push @callbacks, sub { + my ( $event ) = @_; + $tl->aggregate($event); + return $event; + }; + $callback_names{$callbacks[-1]} = "timeline $groupby"; + } + } + + if ( $o->get('processlist') ) { + push @callbacks, sub { + MKDEBUG && _d('callback: interval sleep'); + usleep($o->get('interval') * 1_000_000); + return @_; + }; + $callback_names{$callbacks[-1]} = 'interval sleep'; + } + + # ######################################################################## + # Daemonize now that everything is setup and ready to work. + # ######################################################################## + my $daemon; + if ( $o->get('daemonize') ) { + $daemon = new Daemon(o=>$o); + $daemon->daemonize(); + MKDEBUG && _d('I am a daemon now'); + } + elsif ( $o->get('pid') ) { + # We're not daemoninzing, it just handles PID stuff. + $daemon = new Daemon(o=>$o); + $daemon->make_PID_file(); + } + + # ########################################################################## + # Parse the input. + # ########################################################################## + if ( my $patterns = $o->get('embedded-attributes') ) { + $misc->{embed} = qr/$patterns->[0]/o; + $misc->{capture} = qr/$patterns->[1]/o; + MKDEBUG && _d('Patterns for embedded attributes:', $misc->{embed}, + $misc->{capture}); + } + + if ( @ARGV == 0 ) { + push @ARGV, '-'; # Magical STDIN filename. + } + + my $fh; + my $start = time(); + my $end = $start + ($o->get('run-time') || 0); # When we should exit + my $now = $start; + my $iters = 0; + ITERATION: + while ( # Quit if instructed to, or if iterations are exceeded. + $oktorun + && (!$o->get('iterations') || $iters++ < $o->get('iterations') ) + ) { + + if ( $o->get('print-iterations') ) { + my $iter_start = time; + MKDEBUG && _d('Iteration', $iters, 'started at', ts($iter_start)); + print "\n# Iteration $iters started at ", ts($iter_start), "\n"; + } + + EVENT: + while ( # Quit if: + $oktorun # instructed to quit + && ($start == $end || $now < $end) ) # or time is exceeded + { + if ( !$fh ) { + my $file = shift @ARGV; + if ( !$file ) { + MKDEBUG && _d('No more files to parse'); + last EVENT; + } + + if ( $file eq '-' ) { + $fh = *STDIN; + MKDEBUG && _d('Reading STDIN'); + } + else { + if ( !open $fh, "<", $file ) { + $fh = undef; + warn "Cannot open $file: $OS_ERROR\n"; + next EVENT; + } + MKDEBUG && _d('Reading', $file); + + # Reset these var in case we read two logs out of order by time. + $past_since = 0; + $at_until = 0; + } + } + + eval { + # Run events through the pipeline. The first pipeline process + # is usually responsible for getting the next event. The pipeline + # stops if a process does not return the event. This main loop + # stops if a process sets oktorun to false; it usually does this + # when there are no more events, but it may do it for other reasons. + # Some inputs are infinite streams of events, like the proclist, + # so oktorun is never set to false and it's the user's job to tell + # us when to stop. + my $event = {}; + my $more_events = 1; + my $oktorun_sub = sub { $more_events = $_[0]; }; + foreach my $callback ( @callbacks ) { + last unless $oktorun; # the global oktorun var + my $start = time; + $event = $callback->( + $event, # for backwards compatibility + event => $event, # new interface + fh => $fh, + oktorun => $oktorun_sub, + misc => $misc, + stats => \%stats, + ); + my $end = time; + my $t = $end - $start; + my $name = $callback_names{$callback} || $callback; + $prof{callback}->{$name}->{time} += $t; + $prof{callback}->{$name}->{count}++; + $prof{total}->{time} += $t; + $prof{total}->{count}++; + last unless $event; + } + if ( !$more_events ) { + MKDEBUG && _d('No more events'); + close $fh if $fh; + $fh = undef; + } + }; + if ( $EVAL_ERROR ) { + _d($EVAL_ERROR); + $stats{pipeline_error}++; + + # Don't ignore failure to open a file, else we'll get + # "tell() on closed filehandle" errors. + last EVENT if $EVAL_ERROR =~ m/Cannot open/; + + last EVENT unless $o->get('continue-on-error'); + } + $now = time(); + } # EVENT + + # ###################################################################### + # Done parsing events, now do something with the aggregated query + # results for each class (i.e. each groupby), probably --report them, + # or maybe just save them for --review. + # ###################################################################### + my $qrf = new QueryReportFormatter(); + my @select = ( $ea[0]->get_attributes() ); + MKDEBUG && _d('attribs for reports:', @select); + + # First, and only once, print the global report analysis header. + if ( $o->get('report') && $o->get('report-format')->{header} ) { + print $qrf->header() if $o->get('report-format')->{rusage}; + + # It doesn't matter which ea we use here because they will all have + # the same attributes; they only differ in how they were grouped. + my $ea = $ea[0]; + if ( !$ea->events_processed() ) { + print "# No events processed.\n"; + } + else { + my ( $orderby_attrib, $orderby_func ) = split(/:/, $orderby[0]); + $orderby_attrib = check_orderby_attrib($orderby_attrib, $ea, $o); + print $qrf->global_report( + $ea, + select => [ grep { $_ !~ m/^(?:user|db|pos_in_log)$/ } @select ], + worst => $orderby_attrib, + no_zero_bool => !$o->get('zero-bool'), + ); + } + } + + # ##################################################################### + # Do the reports for each groupby/class. + # ##################################################################### + for my $i ( 0..$#groupby ) { + my $groupby = $groupby[$i]; + my $ea = $ea[$i]; + my ( $orderby_attrib, $orderby_func ) = split(/:/, $orderby[$i]); + $orderby_attrib = check_orderby_attrib($orderby_attrib, $ea, $o); + MKDEBUG && _d('Doing reports for groupby', $groupby, 'orderby', + $orderby_attrib, $orderby_func); + + # We don't report on all queries, just the worst, i.e. the top + # however many. + my $limit = $o->get('limit')->[$i] || '95%:20'; + my ($total, $count); + if ( $limit =~ m/^\d+$/ ) { + $count = $limit; + } + else { + # It's a percentage, so grab as many as needed to get to + # that % of the file. + ($total, $count) = $limit =~ m/(\d+)/g; + $total *= ($ea->results->{globals}->{$orderby_attrib}->{sum} || 0) + / 100; + } + my %top_spec = ( + attrib => $orderby_attrib, + orderby => $orderby_func || 'cnt', + total => $total, + count => $count, + ); + if ( $o->get('outliers')->[$i] ) { + @top_spec{qw(ol_attrib ol_limit ol_freq)} + = split(/:/, $o->get('outliers')->[$i]); + } + # The queries that will be reported. + my @worst = $ea->top_events(%top_spec); + + my $expected_range = $o->get('expected-range'); + my $explain_why + = $expected_range + && (@worst < $expected_range->[0] || @worst > $expected_range->[1]); + + my @table_access; + my @profiles; + my $total_r = 0; + + # Print a header for this groupby/class if we're doing the standard + # query report and there's more than one class or there's one class + # but it's not the normal class grouped by fingerprint. + if ( $o->get('report') + && $o->get('report-format')->{query_report} + && (@groupby > 1 || $groupby ne 'fingerprint') ) + { + print "\n# ", ( '#' x 72 ), "\n"; + print "# Report grouped by $groupby\n"; + print '# ', ( '#' x 72 ), "\n"; + } + + # ################################################################## + # Do the reports for each query in this groupby/class. + # ################################################################## + ITEM: + foreach my $rank ( 1 .. @worst ) { + my $item = $worst[$rank - 1]->[0]; + my $stats = $ea->results->{classes}->{$item}; + my $sample = $ea->results->{samples}->{$item}; + my $samp_query = $sample->{arg} || ''; + + # ############################################################### + # Save the profile for this item. It's printed later, maybe. + # ############################################################### + my %profile = ( + rank => $rank, + r => $stats->{Query_time}->{sum}, + cnt => $stats->{Query_time}->{cnt}, + sample => $groupby eq 'fingerprint' ? $qr->distill($samp_query, + %distill_args) + : $item, + id => $groupby eq 'fingerprint' ? make_checksum($item) + : '', + ); + $total_r += $profile{r}; + push @profiles, \%profile; + + # ############################################################### + # Prepare for --review and --review-history. + # ############################################################### + my $review_vals; + my %history; + if ( $qv ) { + $review_vals = $qv->get_review_info($item); + if ( $review_vals->{reviewed_by} && !$o->get('report-all') ) { + # This item has already been reviewed, skip it. But before + # doing so, save the history if necessary. + if ( $o->get('review-history') ) { + $qv->set_review_history( + $item, $sample->{arg} || '', %history); + } + next ITEM; + } + + if ( $o->get('review-history') ) { + foreach my $attrib ( @select ) { + $history{$attrib} = $ea->metrics( + attrib => $attrib, + where => $item, + ); + } + } + } + + # ############################################################### + # Get tables for either --for-explain or --table-access. + # ############################################################### + my ($default_db) = $sample->{db} ? $sample->{db} + : $stats->{db}->{unq} ? keys %{$stats->{db}->{unq}} + : undef; + my @tables; + if ( $o->get('for-explain') || $o->get('table-access') ){ + @tables = extract_tables($samp_query, $default_db); + push @table_access, $samp_query if $o->get('table-access'); + } + + # ############################################################### + # Print the standard query analysis report. + # ############################################################### + if ( $o->get('report') + && $o->get('report-format')->{query_report} ) { + print "\n"; + print $qrf->event_report( + $ea, + select => [ grep { $_ !~ m/^(?:pos_in_log)$/ } @select ], + where => $item, + rank => $rank, + worst => $orderby_attrib, + reason => $explain_why ? $worst[$rank - 1]->[1] : '', + no_zero_bool => !$o->get('zero-bool'), + ); + print $qrf->chart_distro( + $ea, + attribute => $orderby_attrib, + where => $item, + ); + + if ( $qv ) { + # Print the review information that is already in the table + # before putting anything new into the table. + print "# Review information\n"; + foreach my $col ( $qv->review_cols() ) { + my $val = $review_vals->{$col}; + if ( !$val || $val ne '0000-00-00 00:00:00' ) { # issue 202 + printf "# %13s: %-s\n", $col, ($val ? $val : ''); + } + } + } + + if ( $groupby eq 'fingerprint' ) { + # Shorten it if necessary (issue 216 and 292). + $samp_query = $qr->shorten($samp_query, $o->get('shorten')) + if $o->get('shorten'); + } + # Print the query fingerprint. + if ( $groupby eq 'fingerprint' && $o->get('fingerprints') ) { + print "# Fingerprint\n# $item\n"; + } + + if ( $groupby eq 'fingerprint' ) { + print_tables(@tables) if $o->get('for-explain'); + if ( $item =~ m/^(?:[\(\s]*select|insert|replace)/ ) { + if ( $item =~ m/^(?:insert|replace)/ ) { # No EXPLAIN + print $samp_query, "\\G\n"; + } + else { + print "# EXPLAIN\n$samp_query\\G\n"; + print_explain($ep_dbh, $samp_query, $default_db); + } + } + else { + print "$samp_query\\G\n"; + my $converted = $qr->convert_to_select($samp_query); + if ( $o->get('for-explain') + && $converted + && $converted =~ m/^[\(\s]*select/i ) { + # It converted OK to a SELECT + print "# Converted for EXPLAIN\n# EXPLAIN\n"; + print "$converted\\G\n"; + } + } + } + else { + if ( $groupby eq 'tables' ) { + my ( $db, $tbl ) = $q->split_unquote($item); + print_tables([$db, $tbl]); + } + print $item, "\n"; + } + } # Print standard query analysis report + + # ############################################################### + # Update --review and --review-history. + # ############################################################### + if ( $qv ) { + $qv->set_review_info( + fingerprint => $item, + sample => $sample->{arg} || '', + first_seen => $stats->{ts}->{min}, + last_seen => $stats->{ts}->{max} + ); + if ( $o->get('review-history') ) { + $qv->set_review_history( + $item, $sample->{arg} || '', %history); + } + } + } # Each worst ITEM + + # ################################################################## + # Print per-class reports. + # ################################################################## + + # Print timeline. + if ( $o->get('timeline') ) { + my $tl = $tl[$i]; + $tl->report($tl->results(), sub { print @_ }); + } + + # Print table access. + if ( $o->get('table-access') ) { + my @subqueries; + map { + eval { + push @subqueries, $qp->split($_); + }; + if ( $EVAL_ERROR ) { + MKDEBUG && _d($EVAL_ERROR); + warn "Cannot get table access for query $_"; + } + } @table_access; + + my %seen; + print "\n" if $o->get('report'); + foreach my $subquery ( @subqueries ) { + my $rw = $qp->query_type($subquery, $qr)->{rw}; + next unless $rw; + my @tables = $qp->get_tables($subquery); + next unless scalar @tables; + foreach my $db_tbl ( @tables ) { + next if $seen{$db_tbl}++; # Unique-ify for issue 337. + my ($db, $tbl) = $q->split_unquote($db_tbl); + $db = $db ? "`$db`." : ''; + print "$rw $db`$tbl`\n"; + } + } + } + + # Print profile (issue 381). + if ( $o->get('report') && $o->get('report-format')->{profile} ) { + my $report = new ReportFormatter( + line_width => 74, + long_last_column => 1, + ); + $report->set_columns( + { name => 'Rank', right_justify => 1, }, + { name => 'Query ID', }, + { name => 'Response time', right_justify => 1, }, + { name => 'Calls', right_justify => 1, }, + { name => 'R/Call', right_justify => 1, }, + { name => 'Item', }, + ); + + foreach my $item ( sort { $a->{rank} <=> $b->{rank} } @profiles ) { + my $rt = sprintf('%10.4f', $item->{r}); + my $rtp = sprintf('%4.1f%%', $item->{r} / ($total_r || 1) * 100); + my $rc = sprintf('%8.4f', $item->{r} / $item->{cnt}); + $report->add_line( + $item->{rank}, + "0x$item->{id}", + "$rt $rtp", + $item->{cnt}, + $rc, + $item->{sample}, + ); + } + print "\n" . $report->get_report(); + } + } # Each groupby + + + # Reset the start/end/now times so the next iteration will run for the + # same amount of time. + $start = time(); + $end = $start + ($o->get('run-time') || 0); # When we should exit + $now = $start; + + foreach my $ea ( @ea, @tl ) { + $ea->reset_aggregated_data(); + } + + if ( $o->get('pipeline-profile') ) { + my $report = new ReportFormatter( + line_width => 74, + ); + $report->set_columns( + { name => 'Process' }, + { name => 'Time', right_justify => 1 }, + { name => 'Count', right_justify => 1 }, + ); + $report->set_title('Pipeline profile'); + foreach my $callback ( @callbacks ) { + my $name = $callback_names{$callback} || $callback; + my $t = $prof{callback}->{$name}->{time} || 0; + my $tp = sprintf('%.2f %4.1f%%', $t, + $t / ($prof{total}->{time} || 1) * 100); + $report->add_line($name, $tp, + $prof{callback}->{$name}->{count} || 0); + + # Reset profile for next iteration. + map { $prof{callback}->{$name}->{$_} = 0 } + keys %{$prof{callback}->{$name}}; + } + map { $prof{total}->{$_} = 0 } keys %{$prof{total}}; + + print "\n" . $report->get_report(); + } + + if ( $o->get('statistics') ) { + if ( keys %stats ) { + my $report = new ReportFormatter( + line_width => 74, + ); + $report->set_columns( + { name => 'Statistic', }, + { name => 'Value', right_justify => 1 }, + ); + foreach my $stat ( sort keys %stats ) { + $report->add_line($stat, $stats{$stat} || 0); + + # Reset stats for next iteration. + $stats{$stat} = 0; + } + print "\n" . $report->get_report(); + } + else { + print "\n# No statistics values.\n"; + } + } + } # ITERATION + + # Disconnect all open $dbh's + map { $dp->disconnect($_) } grep { $_ } + ($qv_dbh, $qv_dbh2, $ex_dbh, $ps_dbh, $ep_dbh); + + exit; +} # End main(). + +# ############################################################################ +# Subroutines. +# ############################################################################ +sub extract_tables { + my ( $query, $default_db ) = @_; + MKDEBUG && _d('Extracting tables'); + my @tables; + my %seen; + foreach my $db_tbl ( $qp->get_tables($query) ) { + next unless $db_tbl; + next if $seen{$db_tbl}++; # Unique-ify for issue 337. + my ( $db, $tbl ) = $q->split_unquote($db_tbl); + push @tables, [ $db || $default_db, $tbl ]; + } + return @tables; +} + +# Gets a default database and a list of arrayrefs of [db, tbl] to print out +sub print_tables { + my ( @tables ) = @_; + return unless @tables; + print "# Tables\n"; + foreach my $db_tbl ( @tables ) { + my ( $db, $tbl ) = @$db_tbl; + print '# SHOW TABLE STATUS', + ($db ? " FROM `$db`" : ''), " LIKE '$tbl'\\G\n"; + print "# SHOW CREATE TABLE ", + $q->quote(grep { $_ } @$db_tbl), "\\G\n"; + } + return; +} + +sub print_explain { + my ( $dbh, $query, $db ) = @_; + return unless $dbh && $query; + eval { + if ( !$qp->has_derived_table($query) ) { + if ( $db ) { + $dbh->do("USE " . $q->quote($db)); + } + my $sth = $dbh->prepare("EXPLAIN /*!50100 PARTITIONS */ $query"); + $sth->execute(); + my $i = 1; + while ( my @row = $sth->fetchrow_array() ) { + print "# *************************** ", $i++, + ". row ***************************\n"; + foreach my $j ( 0 .. $#row ) { + printf "# %13s: %s\n", $sth->{NAME}->[$j], + defined $row[$j] ? $row[$j] : 'NULL'; + } + } + } + }; + if ( MKDEBUG && $EVAL_ERROR ) { + _d("Problem explaining", $query, $EVAL_ERROR); + } +} + +# Pass in the currently open $dbh (if any), where $current points to ('execute' +# or 'processlist') and whether you want to be connected to the read_only +# server. Get back which server you're looking at, and the $dbh. Assumes that +# one of the servers is ALWAYS read only and the other is ALWAYS not! If +# there's some transition period where this isn't true, maybe both will end up +# pointing to the same place, but that should resolve shortly. +# The magic switching functionality only works if --mirror is given! Otherwise +# it just returns the correct $dbh. $comment is some descriptive text for +# debuggin, like 'for --execute'. +sub find_role { + my ( $o, $dbh, $current, $read_only, $comment ) = @_; + if ( !$dbh || !$dbh->ping ) { + MKDEBUG && _d('Getting a dbh from', $current, $comment); + $dbh = $dp->get_dbh( + $dp->get_cxn_params($o->get($current)), {AutoCommit => 1}); + $dbh->{InactiveDestroy} = 1; # Don't die on fork(). + } + if ( $o->get('mirror') ) { + my ( $is_read_only ) = $dbh->selectrow_array('SELECT @@global.read_only'); + MKDEBUG && _d("read_only on", $current, $comment, ':', + $is_read_only, '(want', $read_only, ')'); + if ( $is_read_only != $read_only ) { + $current = $current eq 'execute' ? 'processlist' : 'execute'; + MKDEBUG && _d("read_only wrong", $comment, "getting a dbh from", $current); + $dbh = $dp->get_dbh( + $dp->get_cxn_params($o->get($current)), {AutoCommit => 1}); + $dbh->{InactiveDestroy} = 1; # Don't die on fork(). + } + } + return ($current, $dbh); +} + +# Catches signals so we can exit gracefully. +sub sig_int { + my ( $signal ) = @_; + if ( $oktorun ) { + print STDERR "# Caught SIG$signal.\n"; + $oktorun = 0; + } + else { + print STDERR "# Exiting on SIG$signal.\n"; + exit(1); + } +} + +sub make_alt_attrib { + my ( $alt_attrib ) = @_; + my @alts = split('\|', $alt_attrib); + my $attrib = shift @alts; + MKDEBUG && _d('Primary attrib:', $attrib, 'aliases:', @alts); + my @lines; + push @lines, + 'sub { my ( $event ) = @_; ', + 'MKDEBUG && _d("callback: alt attrib");', + "if ( exists \$event->{'$attrib'} ) { ", + (map { "delete \$event->{'$_'}; "; } @alts), + 'return $event; }', + # Primary attrib doesn't exist; look for alts + (map { + "if ( exists \$event->{'$_'} ) { " + . "\$event->{'$attrib'} = \$event->{'$_'}; " + . "delete \$event->{'$_'}; " + . 'return $event; }'; + } @alts), + 'return $event; }'; + MKDEBUG && _d('attrib alias sub for', $attrib, ':', @lines); + my $sub = eval join("\n", @lines); + die if $EVAL_ERROR; + return $sub; +} + +sub make_inherit_attribs { + my ( $attribs, $prev ) = @_; + my @lines; + push @lines, + 'sub { my ( $event ) = @_; ', + 'MKDEBUG && _d("callback: inherit attribs");', + (map { + "if ( defined \$event->{'$_'} ) { \$prev->{'$_'} = \$event->{'$_'} } else { \$event->{'$_'} = \$prev->{'$_'}; }" + } @$attribs), + 'return $event; }'; + MKDEBUG && _d('inherit attribs sub:', @lines); + my $sub = eval join("\n", @lines); + die if $EVAL_ERROR; + return $sub; +} + +# Checks that the orderby attrib exists in the ea, returns the default +# orderby attrib if not. +sub check_orderby_attrib { + my ( $orderby_attrib, $ea, $o ) = @_; + + if ( !$ea->type_for($orderby_attrib) && $orderby_attrib ne 'Query_time' ) { + my $default_orderby = $o->get_defaults()->{'order-by'}; + + # Print the notice only if the query report is being printed, too. + if ( $o->get('report-format')->{query_report} ) { + print "--order-by attribute $orderby_attrib doesn't exist, " + . "using $default_orderby\n"; + } + + # Fall back to the default orderby attrib. + ( $orderby_attrib, undef ) = split(/:/, $default_orderby); + } + + MKDEBUG && _d('orderby attrib:', $orderby_attrib); + return $orderby_attrib; +} + +sub _d { + my ($package, undef, $line) = caller 0; + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } + map { defined $_ ? $_ : 'undef' } + @_; + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; +} + +# ############################################################################ +# Run the program. +# ############################################################################ +if ( !caller ) { exit main(@ARGV); } + +1; # Because this is a module as well as a script. + +# ############################################################################# +# Documentation. +# ############################################################################# + +=pod + +=head1 NAME + +mk-query-digest - Parses logs and more. Analyze, transform, filter, review and +report on queries. + +=head1 SYNOPSIS + +Analyze and report on a slow log: + + mk-query-digest /path/to/slow.log + +Review a slow log, saving results to the test.query_review table in a MySQL +server running on host1. See L<"--review"> for more on reviewing queries: + + mk-query-digest --review h=host1,D=test,t=query_review /path/to/slow.log + +Watch a server's SHOW FULL PROCESSLIST and analyze the queries as if they were +from a slow query log: + + mk-query-digest --processlist h=host1 + +Watch a server's SHOW FULL PROCESSLIST, filter out everything but SELECT +queries, and replay the queries against another server, then use the timings +from replaying them to analyze their performance: + + mk-query-digest --processlist h=host1 --execute h=another_server \ + --filter '$event->{fingerprint} =~ m/^select/' + +=head1 RISKS + +The following section is included to inform users about the potential risks, +whether known or unknown, of using this tool. The two main categories of risks +are those created by the nature of the tool (e.g. read-only tools vs. read-write +tools) and those created by bugs. + +By default mk-query-digest only reads information. The L<"--execute"> option, +however, can cause mk-query-digest to modify and delete data. mk-query-digest +will write to the L<"--review"> and L<"--review-history"> tables if those +options are used. Parsing huge log files may cause significant CPU and memory +usage. + +At the time of this release, there is a bug with L<"--processlist"> and +delayed replication threads, a bug causing certain queries to not be +rewritten correctly as a SELECT, and a bug which causes crashes on OpenBSD. + +The authoritative source for updated information is always the online issue +tracking system. Issues that affect this tool will be marked as such. You can +see a list of such issues at the following URL: +L. + +See also L<"BUGS"> for more information on filing bugs and getting help. + +=head1 DESCRIPTION + +This tool was formerly known as mk-log-parser. + +C is a framework for doing things with events from a query +source such as the slow query log or PROCESSLIST. By default it acts as a very +sophisticated log analysis tool. You can group and sort queries in many +different ways simultaneously and find the most expensive queries, or create a +timeline of queries in the log, for example. It can also do a "query review," +which means to save a sample of each type of query into a MySQL table so you can +easily see whether you've reviewed and analyzed a query before. The benefit of +this is that you can keep track of changes to your server's queries and avoid +repeated work. You can also save other information with the queries, such as +comments, issue numbers in your ticketing system, and so on. + +Note that this is a work in *very* active progress and you should expect +incompatible changes in the future. + +=head1 ATTRIBUTES + +mk-query-digest works on events, which are a collection of key/value pairs +called attributes. You'll recognize most of the attributes right away: +Query_time, Lock_time, and so on. You can just look at a slow log and see them. +However, there are some that don't exist in the slow log, and slow logs +may actually include different kinds of attributes (for example, you may have a +server with the Percona patches). + +For a full list of attributes, see +L. + +=head2 memcached + +memcached events have additional attributes related to the memcached protocol: +cmd, key, res (result) and val. Also, boolean attributes are created for +the various commands, misses and errors: Memc_CMD where CMD is a memcached +command (get, set, delete, etc.), Memc_error and Memc_miss. + +These attributes are no different from slow log attributes, so you can use them +with L<"--[no]report">, L<"--group-by">, in a L<"--filter">, etc. + +These attributes and more are documented at +L. + +=head1 OUTPUT + +The default output is a query analysis report. The L<"--[no]report"> option +controls whether or not this report is printed. Sometimes you may wish to +parse all the queries but suppress the report, for example when using +L<"--print"> or L<"--review">. + +There is one paragraph for each class of query analyzed. A "class" of queries +all have the same value for the L<"--group-by"> attribute which is +"fingerprint" by default. (See L<"ATTRIBUTES">.) A fingerprint is an +abstracted version of the query text with literals removed, whitespace +collapsed, and so forth. The report is formatted so it's easy to paste into +emails without wrapping, and all non-query lines begin with a comment, so you +can save it to a .sql file and open it in your favorite syntax-highlighting +text editor. There is a response-time profile at the very end. + +The report begins with one paragraph about the entire analysis run. The +information is very similar to what you'll see for each class of queries in the +log, but it doesn't have some information that would be too expensive to keep +globally for the analysis. It also has some statistics about the code's +excution itself, such as the CPU and memory usage. + +Following this, each query then appears in a paragraph. Here's a sample, +slightly reformatted so 'perldoc' will not wrap lines in a terminal. The +following will all be one paragraph, but we'll break it up for commentary. + + # Query 2: 0.01 QPS, 0.02x conc, ID 0xFDEA8D2993C9CAF3 at byte 160665 + +This line identifies the sequential number of the query in the sort order +specified by L<"--order-by">. Then there's the queries per second, and the +approximate concurrency for this query (calculated as a function of the timespan +and total Query_time). Next there's a query ID. This ID is a hex version of +the query's checksum in the database, if you're using L<"--review">. You can +select the reviewed query's details from the database with a query like C field with the info which is otherwise appended +; to URLs. If you want XHTML conformity, remove the form entry. +; Note that all valid entries require a "=", even if no value follows. +url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=,fieldset=" + +[MSSQL] +; Allow or prevent persistent links. +mssql.allow_persistent = On + +; Maximum number of persistent links. -1 means no limit. +mssql.max_persistent = -1 + +; Maximum number of links (persistent+non persistent). -1 means no limit. +mssql.max_links = -1 + +; Minimum error severity to display. +mssql.min_error_severity = 10 + +; Minimum message severity to display. +mssql.min_message_severity = 10 + +; Compatibility mode with old versions of PHP 3.0. +mssql.compatability_mode = Off + +; Connect timeout +;mssql.connect_timeout = 5 + +; Query timeout +;mssql.timeout = 60 + +; Valid range 0 - 2147483647. Default = 4096. +;mssql.textlimit = 4096 + +; Valid range 0 - 2147483647. Default = 4096. +;mssql.textsize = 4096 + +; Limits the number of records in each batch. 0 = all records in one batch. +;mssql.batchsize = 0 + +; Specify how datetime and datetim4 columns are returned +; On => Returns data converted to SQL server settings +; Off => Returns values as YYYY-MM-DD hh:mm:ss +;mssql.datetimeconvert = On + +; Use NT authentication when connecting to the server +mssql.secure_connection = Off + +; Specify max number of processes. -1 = library default +; msdlib defaults to 25 +; FreeTDS defaults to 4096 +;mssql.max_procs = -1 + +; Specify client character set. +; If empty or not set the client charset from freetds.comf is used +; This is only used when compiled with FreeTDS +;mssql.charset = "ISO-8859-1" + +[Assertion] +; Assert(expr); active by default. +;assert.active = On + +; Issue a PHP warning for each failed assertion. +;assert.warning = On + +; Don't bail out by default. +;assert.bail = Off + +; User-function to be called if an assertion fails. +;assert.callback = 0 + +; Eval the expression with current error_reporting(). Set to true if you want +; error_reporting(0) around the eval(). +;assert.quiet_eval = 0 + +[COM] +; path to a file containing GUIDs, IIDs or filenames of files with TypeLibs +;com.typelib_file = +; allow Distributed-COM calls +;com.allow_dcom = true +; autoregister constants of a components typlib on com_load() +;com.autoregister_typelib = true +; register constants casesensitive +;com.autoregister_casesensitive = false +; show warnings on duplicate constant registrations +;com.autoregister_verbose = true + +[mbstring] +; language for internal character representation. +;mbstring.language = Japanese + +; internal/script encoding. +; Some encoding cannot work as internal encoding. +; (e.g. SJIS, BIG5, ISO-2022-*) +;mbstring.internal_encoding = EUC-JP + +; http input encoding. +;mbstring.http_input = auto + +; http output encoding. mb_output_handler must be +; registered as output buffer to function +;mbstring.http_output = SJIS + +; enable automatic encoding translation according to +; mbstring.internal_encoding setting. Input chars are +; converted to internal encoding by setting this to On. +; Note: Do _not_ use automatic encoding translation for +; portable libs/applications. +;mbstring.encoding_translation = Off + +; automatic encoding detection order. +; auto means +;mbstring.detect_order = auto + +; substitute_character used when character cannot be converted +; one from another +;mbstring.substitute_character = none; + +; overload(replace) single byte functions by mbstring functions. +; mail(), ereg(), etc are overloaded by mb_send_mail(), mb_ereg(), +; etc. Possible values are 0,1,2,4 or combination of them. +; For example, 7 for overload everything. +; 0: No overload +; 1: Overload mail() function +; 2: Overload str*() functions +; 4: Overload ereg*() functions +;mbstring.func_overload = 0 + +[FrontBase] +;fbsql.allow_persistent = On +;fbsql.autocommit = On +;fbsql.show_timestamp_decimals = Off +;fbsql.default_database = +;fbsql.default_database_password = +;fbsql.default_host = +;fbsql.default_password = +;fbsql.default_user = "_SYSTEM" +;fbsql.generate_warnings = Off +;fbsql.max_connections = 128 +;fbsql.max_links = 128 +;fbsql.max_persistent = -1 +;fbsql.max_results = 128 + +[gd] +; Tell the jpeg decode to libjpeg warnings and try to create +; a gd image. The warning will then be displayed as notices +; disabled by default +;gd.jpeg_ignore_warning = 0 + +[exif] +; Exif UNICODE user comments are handled as UCS-2BE/UCS-2LE and JIS as JIS. +; With mbstring support this will automatically be converted into the encoding +; given by corresponding encode setting. When empty mbstring.internal_encoding +; is used. For the decode settings you can distinguish between motorola and +; intel byte order. A decode setting cannot be empty. +;exif.encode_unicode = ISO-8859-15 +;exif.decode_unicode_motorola = UCS-2BE +;exif.decode_unicode_intel = UCS-2LE +;exif.encode_jis = +;exif.decode_jis_motorola = JIS +;exif.decode_jis_intel = JIS + +[Tidy] +; The path to a default tidy configuration file to use when using tidy +;tidy.default_config = /usr/local/lib/php/default.tcfg + +; Should tidy clean and repair output automatically? +; WARNING: Do not use this option if you are generating non-html content +; such as dynamic images +tidy.clean_output = Off + +[soap] +; Enables or disables WSDL caching feature. +soap.wsdl_cache_enabled=1 +; Sets the directory name where SOAP extension will put cache files. +soap.wsdl_cache_dir="/tmp" +; (time to live) Sets the number of second while cached file will be used +; instead of original one. +soap.wsdl_cache_ttl=86400 + +; Local Variables: +; tab-width: 4 +; End: diff --git a/php/metadata.json b/php/metadata.json new file mode 100644 index 0000000..47a00e4 --- /dev/null +++ b/php/metadata.json @@ -0,0 +1,101 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs and maintains php and php modules", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "php::module_fpdf": "Install the php-fpdf package", + "php::php5-cgi": "Install the php5-cgi package", + "php::module_sqlite3": "Install the php5-sqlite3 package", + "php::module_gd": "Install the php5-gd package", + "php::module_ldap": "Install the php5-ldap package", + "php": "", + "php::module_curl": "Install the php5-curl package", + "php::module_mysql": "Install the php5-mysql package", + "php::module_apc": "Install the php5-apc package", + "php::pear": "Install the php-pear package", + "php::module_memcache": "Install the php5-memcache package", + "php::php4": "Install packages for PHP version 4", + "php::module_fileinfo": "Install the php5-fileinfo package", + "php::module_pgsql": "Install the php5-pgsql packag", + "php::php5": "Install php5 packages and php.ini config file" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "debian": [ + + ] + }, + "version": "0.7.0", + "name": "php", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "php::module_fpdf": [ + + ], + "php::php5-cgi": [ + + ], + "php": [ + + ], + "php::module_sqlite3": [ + + ], + "php::module_gd": [ + + ], + "php::module_ldap": [ + + ], + "php::module_curl": [ + + ], + "php::module_mysql": [ + + ], + "php::module_apc": [ + + ], + "php::pear": [ + + ], + "php::module_memcache": [ + + ], + "php::php4": [ + + ], + "php::module_fileinfo": [ + + ], + "php::module_pgsql": [ + + ], + "php::php5": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + "apache2": [ + + ] + } +} \ No newline at end of file diff --git a/php/metadata.rb b/php/metadata.rb new file mode 100644 index 0000000..7e592dc --- /dev/null +++ b/php/metadata.rb @@ -0,0 +1,24 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs and maintains php and php modules" +version "0.7" +depends "apache2" +recipe "php::module_apc", "Install the php5-apc package" +recipe "php::module_curl", "Install the php5-curl package" +recipe "php::module_fileinfo", "Install the php5-fileinfo package" +recipe "php::module_fpdf", "Install the php-fpdf package" +recipe "php::module_gd", "Install the php5-gd package" +recipe "php::module_ldap", "Install the php5-ldap package" +recipe "php::module_memcache", "Install the php5-memcache package" +recipe "php::module_mysql", "Install the php5-mysql package" +recipe "php::module_pgsql", "Install the php5-pgsql packag" +recipe "php::module_sqlite3", "Install the php5-sqlite3 package" +recipe "php::pear", "Install the php-pear package" +recipe "php::php4", "Install packages for PHP version 4" +recipe "php::php5-cgi", "Install the php5-cgi package" +recipe "php::php5", "Install php5 packages and php.ini config file" + +%w{ubuntu debian}.each do |os| + supports os +end diff --git a/php/recipes/default.rb b/php/recipes/default.rb new file mode 100644 index 0000000..25049e3 --- /dev/null +++ b/php/recipes/default.rb @@ -0,0 +1,19 @@ +# +# Author:: Joshua Timberman () +# Cookbook Name:: php +# Recipe:: default +# +# Copyright 2009, Opscode, 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/php/recipes/module_apc.rb b/php/recipes/module_apc.rb new file mode 100644 index 0000000..52d37ab --- /dev/null +++ b/php/recipes/module_apc.rb @@ -0,0 +1,23 @@ +# +# Author:: Joshua Timberman () +# Cookbook Name:: php +# Recipe:: module_apc +# +# Copyright 2009, Opscode, 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 "php5-apc" do + action :upgrade +end diff --git a/php/recipes/module_curl.rb b/php/recipes/module_curl.rb new file mode 100644 index 0000000..468547a --- /dev/null +++ b/php/recipes/module_curl.rb @@ -0,0 +1,23 @@ +# +# Author:: Joshua Timberman () +# Cookbook Name:: php +# Recipe:: module_curl +# +# Copyright 2009, Opscode, 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 "php5-curl" do + action :upgrade +end diff --git a/php/recipes/module_fileinfo.rb b/php/recipes/module_fileinfo.rb new file mode 100644 index 0000000..f2bf1dc --- /dev/null +++ b/php/recipes/module_fileinfo.rb @@ -0,0 +1,23 @@ +# +# Author:: Joshua Timberman () +# Cookbook Name:: php +# Recipe:: module_fileinfo +# +# Copyright 2009, Opscode, 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 "php5-fileinfo" do + action :upgrade +end diff --git a/php/recipes/module_fpdf.rb b/php/recipes/module_fpdf.rb new file mode 100644 index 0000000..2c38958 --- /dev/null +++ b/php/recipes/module_fpdf.rb @@ -0,0 +1,23 @@ +# +# Author:: Joshua Timberman () +# Cookbook Name:: php +# Recipe:: module_fpdf +# +# Copyright 2009, Opscode, 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 "php-fpdf" do + action :upgrade +end diff --git a/php/recipes/module_gd.rb b/php/recipes/module_gd.rb new file mode 100644 index 0000000..deba7c1 --- /dev/null +++ b/php/recipes/module_gd.rb @@ -0,0 +1,23 @@ +# +# Author:: Joshua Timberman () +# Cookbook Name:: php +# Recipe:: module_gd +# +# Copyright 2009, Opscode, 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 "php5-gd" do + action :upgrade +end diff --git a/php/recipes/module_ldap.rb b/php/recipes/module_ldap.rb new file mode 100644 index 0000000..fd64bbd --- /dev/null +++ b/php/recipes/module_ldap.rb @@ -0,0 +1,23 @@ +# +# Author:: Joshua Timberman () +# Cookbook Name:: php +# Recipe:: module_ldap +# +# Copyright 2009, Opscode, 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 "php5-ldap" do + action :upgrade +end diff --git a/php/recipes/module_memcache.rb b/php/recipes/module_memcache.rb new file mode 100644 index 0000000..250a417 --- /dev/null +++ b/php/recipes/module_memcache.rb @@ -0,0 +1,23 @@ +# +# Author:: Joshua Timberman () +# Cookbook Name:: php +# Recipe:: module_memcache +# +# Copyright 2009, Opscode, 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 "php5-memcache" do + action :upgrade +end diff --git a/php/recipes/module_mysql.rb b/php/recipes/module_mysql.rb new file mode 100644 index 0000000..70533a1 --- /dev/null +++ b/php/recipes/module_mysql.rb @@ -0,0 +1,23 @@ +# +# Author:: Joshua Timberman () +# Cookbook Name:: php +# Recipe:: module_mysql +# +# Copyright 2009, Opscode, 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 "php5-mysql" do + action :upgrade +end diff --git a/php/recipes/module_pgsql.rb b/php/recipes/module_pgsql.rb new file mode 100644 index 0000000..5906ad2 --- /dev/null +++ b/php/recipes/module_pgsql.rb @@ -0,0 +1,23 @@ +# +# Author:: Joshua Timberman () +# Cookbook Name:: php +# Recipe:: module_pgsql +# +# Copyright 2009, Opscode, 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 "php5-pgsql" do + action :upgrade +end diff --git a/php/recipes/module_sqlite3.rb b/php/recipes/module_sqlite3.rb new file mode 100644 index 0000000..15bf1d0 --- /dev/null +++ b/php/recipes/module_sqlite3.rb @@ -0,0 +1,23 @@ +# +# Author:: Joshua Timberman () +# Cookbook Name:: php +# Recipe:: module_sqlite3 +# +# Copyright 2009, Opscode, 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 "php5-sqlite" do + action :upgrade +end diff --git a/php/recipes/pear.rb b/php/recipes/pear.rb new file mode 100644 index 0000000..5db7d8f --- /dev/null +++ b/php/recipes/pear.rb @@ -0,0 +1,23 @@ +# +# Author:: Joshua Timberman () +# Cookbook Name:: php +# Recipe:: pear +# +# Copyright 2009, Opscode, 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 "php-pear" do + action :install +end diff --git a/php/recipes/php4.rb b/php/recipes/php4.rb new file mode 100644 index 0000000..198f477 --- /dev/null +++ b/php/recipes/php4.rb @@ -0,0 +1,25 @@ +# +# Author:: Joshua Timberman () +# Cookbook Name:: php +# Recipe:: default +# +# Copyright 2009, Opscode, 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. +# + +%w{ php4 php4-mysql php4-ldap php4-gd }.each do |pkg| + package pkg do + action :upgrade + end +end diff --git a/php/recipes/php5-cgi.rb b/php/recipes/php5-cgi.rb new file mode 100644 index 0000000..0389c35 --- /dev/null +++ b/php/recipes/php5-cgi.rb @@ -0,0 +1,30 @@ +# +# Author:: Joshua Timberman () +# Cookbook Name:: php +# Recipe:: php5-cgi +# +# Copyright 2009, Opscode, 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 "apache2" +include_recipe "php::module_mysql" +include_recipe "php::module_sqlite3" +include_recipe "php::module_memcache" +include_recipe "php::module_gd" +include_recipe "php::module_pgsql" + +package "php5-cgi" do + action :upgrade +end diff --git a/php/recipes/php5.rb b/php/recipes/php5.rb new file mode 100644 index 0000000..02acd66 --- /dev/null +++ b/php/recipes/php5.rb @@ -0,0 +1,41 @@ +# +# Author:: Joshua Timberman () +# Cookbook Name:: php +# Recipe:: php5 +# +# Copyright 2009, Opscode, 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 "apache2" +include_recipe "php::module_mysql" +include_recipe "php::module_ldap" +include_recipe "php::module_memcache" +include_recipe "php::module_gd" +include_recipe "php::module_pgsql" +include_recipe "php::pear" + +remote_file value_for_platform([ "centos", "redhat", "suse" ] => {"default" => "/etc/php.ini"}, "default" => "/etc/php5/apache2/php.ini") do + source "apache2-php5.ini" + owner "root" + group "root" + mode 0644 + notifies :restart, resources("service[apache2]"), :delayed +end + +%w{ php5 php5-cli samrty }.each do |pkg| + package pkg do + action :upgrade + end +end diff --git a/php/templates/default/php.conf.erb b/php/templates/default/php.conf.erb new file mode 100644 index 0000000..878eabe --- /dev/null +++ b/php/templates/default/php.conf.erb @@ -0,0 +1,63 @@ + + + DocumentRoot <%= docroot %> + +<% if @node[:virtual_host_name] -%> + ServerName <%= @node[:virtual_host_name] %> +<% end -%> +<% if @node[:virtual_host_alias] -%> +<% va_list = @node[:virtual_host_alias].kind_of?(Array) ? @node[:virtual_host_alias] : [ @node[:virtual_host_alias] ] -%> +<% va_list.each do |va| -%> + ServerAlias <%= va %> +<% end -%> +<% end -%> + + + Options FollowSymLinks + AllowOverride None + + + + SetHandler server-status + + Order Deny,Allow + Deny from all + Allow from 127.0.0.1 + + + LogLevel info + ErrorLog /var/log/apache2/<%= application_name %>-error.log + CustomLog /var/log/apache2/<%= application_name %>-access.log combined + + RewriteEngine On + RewriteLog /var/log/apache2/<%= application_name %>-rewrite.log + RewriteLogLevel 0 + + <% if canonical_hostname != "false" %> + RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f + RewriteCond %{HTTP_HOST} !^<%= canonical_hostname.gsub(/\./, '\.') %> [NC] + RewriteCond %{HTTP_HOST} !^$ + RewriteCond %{HTTP_HOST} !^localhost [NC] + RewriteCond %{HTTP_HOST} !^127\.0\.0\.1 [NC] + RewriteCond %{HTTP_HOST} !^<%= @node[:fqdn].gsub(/\./, '\.') %> [NC] + RewriteCond %{HTTP_HOST} !^<%= @node[:hostname].gsub(/\./, '\.') %> [NC] + RewriteRule ^/(.*) http://<%= canonical_hostname %>/$1 [L,R=301] + <% end %> + + RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f + RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f + RewriteCond %{SCRIPT_FILENAME} !maintenance.html + RewriteRule ^.*$ /system/maintenance.html [L] + + RewriteRule ^/server-status$ /server-status$1 [L] + + > + Options Indexes FollowSymLinks MultiViews + AllowOverride All + Order allow,deny + allow from all + + + AddOutputFilterByType DEFLATE text/html text/plain text/xml + + diff --git a/php5/attributes/php5.rb b/php5/attributes/php5.rb new file mode 100755 index 0000000..9bc2bd1 --- /dev/null +++ b/php5/attributes/php5.rb @@ -0,0 +1,5 @@ +php5 Mash.new unless attribute?("php5") +default[:php5][:version] = "5.3.0" +default[:php5][:path] = "/usr/local/php" +default[:php5][:tar_pkg] = "php-#{php5[:version]}-#{platform}-#{platform_version}-#{kernel[:machine]}.tar.bz2" +default[:php5][:dist_url] = "http://dist/packages/#{php5[:tar_pkg]}" diff --git a/php5/metadata.json b/php5/metadata.json new file mode 100755 index 0000000..04d5d11 --- /dev/null +++ b/php5/metadata.json @@ -0,0 +1,44 @@ +{ + "replacing": { + + }, + "long_description": "", + "attributes": { + + }, + "maintainer": "37signals", + "recommendations": { + + }, + "license": "Apache v2.0", + "recipes": { + "php5::sites": "", + "php5": "" + }, + "maintainer_email": "sysadmins@37signals.com", + "suggestions": { + + }, + "dependencies": { + "apache2": [ + + ] + }, + "conflicting": { + + }, + "platforms": { + + }, + "description": "Configures php5", + "version": "0.1.0", + "name": "php5", + "providing": { + "php5::sites": [ + + ], + "php5": [ + + ] + } +} \ No newline at end of file diff --git a/php5/metadata.rb b/php5/metadata.rb new file mode 100755 index 0000000..756fd46 --- /dev/null +++ b/php5/metadata.rb @@ -0,0 +1,5 @@ +maintainer "37signals" +maintainer_email "sysadmins@37signals.com" +description "Configures php5" +version "0.1" +depends "apache2" \ No newline at end of file diff --git a/php5/recipes/default.rb b/php5/recipes/default.rb new file mode 100755 index 0000000..95c71eb --- /dev/null +++ b/php5/recipes/default.rb @@ -0,0 +1,32 @@ +unless node[:platform] == "ubuntu" + Chef::Log.warn("This recipe is only available for Ubuntu systems.") + return +end + +package "libmcrypt4" +package "libltdl7" +package "apache2-mpm-worker" +package "libapache2-mod-fcgid" +apache_module "fcgid" + +bash "install_php" do + code <<-EOC +wget #{node[:php5][:dist_url]} +tar -C /#{node[:php5][:path].split("/")[1..-2].join("/")} -xpf #{node[:php5][:tar_pkg]} +EOC + user "root" + cwd "/tmp" + not_if { File.directory?(node[:php5][:path]) } +end + +link "/usr/bin/php-cgi" do + to "/usr/local/php/bin/php-cgi" +end + +template "/usr/local/php/lib/php.ini" do + source "php.ini.erb" + owner "root" + group "root" + mode 0644 +end + diff --git a/php5/recipes/sites.rb b/php5/recipes/sites.rb new file mode 100755 index 0000000..f84ca31 --- /dev/null +++ b/php5/recipes/sites.rb @@ -0,0 +1,39 @@ +require_recipe "php5::default" + +directory "/u/logs" do + mode 0755 + owner "root" + group "root" +end + +directory "/u/logs/sites" do + mode 0775 + owner "app" + group "www-data" +end + +logrotate "website_logs" do + files "/u/logs/sites/*.log" + frequency "weekly" + restart_command "/etc/init.d/apache2 reload > /dev/null" +end + +if node[:active_sites] + node[:active_sites].each do |site, conf| + + full_name = "#{site}_#{conf[:env]}" + + apache_site full_name do + config_path "/u/sites/#{site}/current/config/apache/#{conf[:env]}.conf" + only_if { File.exists?("/etc/apache2/sites-available/#{full_name}") } + end + + logrotate full_name do + files "/u/sites/#{site}/shared/log/*.log" + frequency "weekly" + restart_command "/etc/init.d/apache2 reload > /dev/null" + end + end +else + Chef::Log.info "Add an 'active_sites' attribute to configure this node's sites" +end diff --git a/php5/templates/default/php.ini.erb b/php5/templates/default/php.ini.erb new file mode 100755 index 0000000..40f721d --- /dev/null +++ b/php5/templates/default/php.ini.erb @@ -0,0 +1,3 @@ +date.timezone = 'UTC' +allow_url_include = 1 + diff --git a/php5/templates/default/php5.conf.erb b/php5/templates/default/php5.conf.erb new file mode 100755 index 0000000..04fc357 --- /dev/null +++ b/php5/templates/default/php5.conf.erb @@ -0,0 +1,4 @@ + + AddType application/x-httpd-php .php .phtml .php3 + AddType application/x-httpd-php-source .phps + diff --git a/php5/templates/default/php5.load.erb b/php5/templates/default/php5.load.erb new file mode 100755 index 0000000..f015f85 --- /dev/null +++ b/php5/templates/default/php5.load.erb @@ -0,0 +1,3 @@ +LoadModule php5_module <%= @node[:php5][:module_path] %> + + diff --git a/postfix/attributes/postfix.rb b/postfix/attributes/postfix.rb new file mode 100644 index 0000000..9246a44 --- /dev/null +++ b/postfix/attributes/postfix.rb @@ -0,0 +1,14 @@ +set_unless[:postfix][:mail_type] = "client" +set_unless[:postfix][:myhostname] = fqdn +set_unless[:postfix][:mydomain] = domain +set_unless[:postfix][:myorigin] = "$myhostname" +set_unless[:postfix][:relayhost] = "" +set_unless[:postfix][:mail_relay_networks] = "127.0.0.0/8" + +set_unless[:postfix][:smtp_sasl_auth_enable] = "no" +set_unless[:postfix][:smtp_sasl_password_maps] = "hash:/etc/postfix/sasl_passwd" +set_unless[:postfix][:smtp_sasl_security_options] = "noanonymous" +set_unless[:postfix][:smtp_tls_cafile] = "/etc/postfix/cacert.pem" +set_unless[:postfix][:smtp_use_tls] = "yes" +set_unless[:postfix][:smtp_sasl_user_name] = "" +set_unless[:postfix][:smtp_sasl_passwd] = "" diff --git a/postfix/metadata.json b/postfix/metadata.json new file mode 100644 index 0000000..961ec28 --- /dev/null +++ b/postfix/metadata.json @@ -0,0 +1,199 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs and configures postfix for client or outbound relayhost, or to do SASL auth", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "postfix": "", + "postfix::sasl_auth": "Set up postfix to auth to a server with sasl" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "debian": [ + + ] + }, + "version": "0.7.0", + "name": "postfix", + "conflicting": { + + }, + "attributes": { + "postfix\/smtp_sasl_password_maps": { + "default": "hash:\/etc\/postfix\/sasl_passwd", + "type": "string", + "multiple_values": false, + "description": "hashmap of SASL passwords", + "display_name": "Postfix SMTP SASL Password Maps", + "recipes": [ + + ], + "required": false + }, + "postfix\/smtp_sasl_security_options": { + "default": "noanonymous", + "type": "string", + "multiple_values": false, + "description": "Sets the value of smtp_sasl_security_options in main.cf", + "display_name": "Postfix SMTP SASL Security Options", + "recipes": [ + + ], + "required": false + }, + "postfix\/mail_relay_networks": { + "default": "127.0.0.0\/8", + "type": "string", + "multiple_values": false, + "description": "Sets the mynetworks value in main.cf", + "display_name": "Postfix Mail Relay Networks", + "recipes": [ + + ], + "required": false + }, + "postfix\/myorigin": { + "default": "$myhostname", + "type": "string", + "multiple_values": false, + "description": "Sets the myorigin value in main.cf", + "display_name": "Postfix Myorigin", + "recipes": [ + + ], + "required": false + }, + "postfix\/myhostname": { + "default": "fqdn", + "type": "string", + "multiple_values": false, + "description": "Sets the myhostname value in main.cf", + "display_name": "Postfix Myhostname", + "recipes": [ + + ], + "required": false + }, + "postfix\/smtp_sasl_user_name": { + "default": "", + "type": "string", + "multiple_values": false, + "description": "User to auth SMTP via SASL", + "display_name": "Postfix SMTP SASL Username", + "recipes": [ + + ], + "required": false + }, + "postfix\/smtp_tls_cafile": { + "default": "\/etc\/postfix\/cacert.pem", + "type": "string", + "multiple_values": false, + "description": "CA certificate file for SMTP over TLS", + "display_name": "Postfix SMTP TLS CA File", + "recipes": [ + + ], + "required": false + }, + "postfix\/smtp_sasl_passwd": { + "default": "", + "type": "string", + "multiple_values": false, + "description": "Password for smtp_sasl_user_name", + "display_name": "Postfix SMTP SASL Password", + "recipes": [ + + ], + "required": false + }, + "postfix\/mail_type": { + "default": "client", + "type": "string", + "multiple_values": false, + "description": "Is this node a client or server?", + "display_name": "Postfix Mail Type", + "recipes": [ + + ], + "required": false + }, + "postfix\/smtp_use_tls": { + "default": "yes", + "type": "string", + "multiple_values": false, + "description": "Whether SMTP SASL Auth should use TLS encryption", + "display_name": "Postfix SMTP Use TLS?", + "recipes": [ + + ], + "required": false + }, + "postfix\/relayhost": { + "default": "", + "type": "string", + "multiple_values": false, + "description": "Sets the relayhost value in main.cf", + "display_name": "Postfix Relayhost", + "recipes": [ + + ], + "required": false + }, + "postfix\/smtp_sasl_auth_enable": { + "default": "no", + "type": "string", + "multiple_values": false, + "description": "Enable SMTP SASL Authentication", + "display_name": "Postfix SMTP SASL Auth Enable", + "recipes": [ + + ], + "required": false + }, + "postfix\/mydomain": { + "default": "domain", + "type": "string", + "multiple_values": false, + "description": "Sets the mydomain value in main.cf", + "display_name": "Postfix Mydomain", + "recipes": [ + + ], + "required": false + }, + "postfix": { + "type": "hash", + "multiple_values": false, + "description": "Hash of Postfix attributes", + "display_name": "Postfix", + "recipes": [ + + ], + "required": false + } + }, + "providing": { + "postfix::sasl_auth": [ + + ], + "postfix": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/postfix/metadata.rb b/postfix/metadata.rb new file mode 100644 index 0000000..18d8032 --- /dev/null +++ b/postfix/metadata.rb @@ -0,0 +1,81 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs and configures postfix for client or outbound relayhost, or to do SASL auth" +version "0.7" +recipe "postfix::sasl_auth", "Set up postfix to auth to a server with sasl" + +%w{ubuntu debian}.each do |os| + supports os +end + +attribute "postfix", + :display_name => "Postfix", + :description => "Hash of Postfix attributes", + :type => "hash" + +attribute "postfix/mail_type", + :display_name => "Postfix Mail Type", + :description => "Is this node a client or server?", + :default => "client" + +attribute "postfix/myhostname", + :display_name => "Postfix Myhostname", + :description => "Sets the myhostname value in main.cf", + :default => "fqdn" + +attribute "postfix/mydomain", + :display_name => "Postfix Mydomain", + :description => "Sets the mydomain value in main.cf", + :default => "domain" + +attribute "postfix/myorigin", + :display_name => "Postfix Myorigin", + :description => "Sets the myorigin value in main.cf", + :default => "$myhostname" + +attribute "postfix/relayhost", + :display_name => "Postfix Relayhost", + :description => "Sets the relayhost value in main.cf", + :default => "" + +attribute "postfix/mail_relay_networks", + :display_name => "Postfix Mail Relay Networks", + :description => "Sets the mynetworks value in main.cf", + :default => "127.0.0.0/8" + +attribute "postfix/smtp_sasl_auth_enable", + :display_name => "Postfix SMTP SASL Auth Enable", + :description => "Enable SMTP SASL Authentication", + :default => "no" + +attribute "postfix/smtp_sasl_password_maps", + :display_name => "Postfix SMTP SASL Password Maps", + :description => "hashmap of SASL passwords", + :default => "hash:/etc/postfix/sasl_passwd" + +attribute "postfix/smtp_sasl_security_options", + :display_name => "Postfix SMTP SASL Security Options", + :description => "Sets the value of smtp_sasl_security_options in main.cf", + :default => "noanonymous" + +attribute "postfix/smtp_tls_cafile", + :display_name => "Postfix SMTP TLS CA File", + :description => "CA certificate file for SMTP over TLS", + :default => "/etc/postfix/cacert.pem" + +attribute "postfix/smtp_use_tls", + :display_name => "Postfix SMTP Use TLS?", + :description => "Whether SMTP SASL Auth should use TLS encryption", + :default => "yes" + +attribute "postfix/smtp_sasl_user_name", + :display_name => "Postfix SMTP SASL Username", + :description => "User to auth SMTP via SASL", + :default => "" + +attribute "postfix/smtp_sasl_passwd", + :display_name => "Postfix SMTP SASL Password", + :description => "Password for smtp_sasl_user_name", + :default => "" + diff --git a/postfix/recipes/default.rb b/postfix/recipes/default.rb new file mode 100644 index 0000000..5c97fe5 --- /dev/null +++ b/postfix/recipes/default.rb @@ -0,0 +1,37 @@ +# +# Author:: Joshua Timberman() +# Cookbook Name:: postfix +# Recipe:: default +# +# Copyright 2009, Opscode, 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 "postfix" do + action :install +end + +service "postfix" do + action :enable +end + +%w{main master}.each do |cfg| + template "/etc/postfix/#{cfg}.cf" do + source "#{cfg}.cf.erb" + owner "root" + group "root" + mode 0644 + notifies :restart, resources(:service => "postfix") + end +end diff --git a/postfix/recipes/sasl_auth.rb b/postfix/recipes/sasl_auth.rb new file mode 100644 index 0000000..7ea922d --- /dev/null +++ b/postfix/recipes/sasl_auth.rb @@ -0,0 +1,40 @@ +# +# Author:: Joshua Timberman() +# Cookbook Name:: postfix +# Recipe:: sasl_auth +# +# Copyright 2009, Opscode, 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. +# + +%w{ libsasl2-2 ca-certificates}.each do |pkg| + package pkg do + action :install + end +end + +execute "postmap-sasl_passwd" do + command "postmap /etc/postfix/sasl_passwd" + action :nothing +end + +template "/etc/postfix/sasl_passwd" do + source "sasl_passwd.erb" + owner "root" + group "root" + mode 0400 + notifies :run, resources(:execute => "postmap-sasl_passwd"), :immediately + notifies :restart, resources(:service => "postfix") +end + diff --git a/postfix/templates/default/main.cf.erb b/postfix/templates/default/main.cf.erb new file mode 100644 index 0000000..0e8144f --- /dev/null +++ b/postfix/templates/default/main.cf.erb @@ -0,0 +1,37 @@ +### +# Generated by Chef for <%= @node[:fqdn] %> +# Configured as <%= @node[:postfix][:mail_type] %> +### + +biff = no +append_dot_mydomain = no +smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem +smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key +smtpd_use_tls=yes +smtpd_tls_session_cache_database = btree:${queue_directory}/smtpd_scache +smtp_tls_session_cache_database = btree:${queue_directory}/smtp_scache +smtp_sasl_auth_enable = <%= @node[:postfix][:smtp_sasl_auth_enable] %> +<% if @node[:postfix][:smtp_sasl_auth_enable] == "yes" -%> +smtp_sasl_password_maps = <%= @node[:postfix][:smtp_sasl_password_maps] %> +smtp_sasl_security_options = <%= @node[:postfix][:smtp_sasl_security_options] %> +smtp_tls_CAfile = <%= @node[:postfix][:smtp_tls_cafile] %> +smtp_use_tls = <%= @node[:postfix][:smtp_use_tls] %> +<% end -%> +myhostname = <%= @node[:postfix][:myhostname] %> +mydomain = <%= @node[:postfix][:mydomain] %> +myorigin = <%= @node[:postfix][:myorigin] %> +smtpd_banner = $myhostname ESMTP $mail_name +alias_maps = hash:/etc/aliases +alias_database = hash:/etc/aliases +mydestination = <%= @node[:postfix][:myhostname] %>, <%= @node[:hostname] %>, localhost.localdomain, localhost +<% if @node[:postfix][:mail_type] == "master" -%> +relayhost = +mynetworks = <%= @node[:postfix][:mail_relay_networks] %> +inet_interfaces = all +<% else -%> +relayhost = <%= @node[:postfix][:relayhost] %> +mynetworks = <%= @node[:postfix][:mail_relay_networks] %> +inet_interfaces = loopback-only +<% end -%> +mailbox_size_limit = 0 +recipient_delimiter = + diff --git a/postfix/templates/default/master.cf.erb b/postfix/templates/default/master.cf.erb new file mode 100644 index 0000000..89b7f18 --- /dev/null +++ b/postfix/templates/default/master.cf.erb @@ -0,0 +1,79 @@ +# +# Postfix master process configuration file. For details on the format +# of the file, see the master(5) manual page (command: "man 5 master"). +# +# ========================================================================== +# service type private unpriv chroot wakeup maxproc command + args +# (yes) (yes) (yes) (never) (100) +# ========================================================================== +smtp inet n - n - - smtpd +#submission inet n - n - - smtpd +# -o smtpd_enforce_tls=yes +# -o smtpd_sasl_auth_enable=yes +# -o smtpd_client_restrictions=permit_sasl_authenticated,reject +#smtps inet n - n - - smtpd +# -o smtpd_tls_wrappermode=yes +# -o smtpd_sasl_auth_enable=yes +# -o smtpd_client_restrictions=permit_sasl_authenticated,reject +#628 inet n - n - - qmqpd +pickup fifo n - n 60 1 pickup +cleanup unix n - n - 0 cleanup +qmgr fifo n - n 300 1 qmgr +#qmgr fifo n - n 300 1 oqmgr +tlsmgr unix - - n 1000? 1 tlsmgr +rewrite unix - - n - - trivial-rewrite +bounce unix - - n - 0 bounce +defer unix - - n - 0 bounce +trace unix - - n - 0 bounce +verify unix - - n - 1 verify +flush unix n - n 1000? 0 flush +proxymap unix - - n - - proxymap +smtp unix - - n - 500 smtp +# When relaying mail as backup MX, disable fallback_relay to avoid MX loops +relay unix - - n - - smtp + -o fallback_relay= +# -o smtp_helo_timeout=5 -o smtp_connect_timeout=5 +showq unix n - n - - showq +error unix - - n - - error +discard unix - - n - - discard +local unix - n n - - local +virtual unix - n n - - virtual +lmtp unix - - n - - lmtp +anvil unix - - n - 1 anvil +scache unix - - n - 1 scache +# +# ==================================================================== +# Interfaces to non-Postfix software. Be sure to examine the manual +# pages of the non-Postfix software to find out what options it wants. +# +# Many of the following services use the Postfix pipe(8) delivery +# agent. See the pipe(8) man page for information about ${recipient} +# and other message envelope options. +# ==================================================================== +# +# maildrop. See the Postfix MAILDROP_README file for details. +# Also specify in main.cf: maildrop_destination_recipient_limit=1 +# +maildrop unix - n n - - pipe + flags=DRhu user=vmail argv=/usr/local/bin/maildrop -d ${recipient} +# +# The Cyrus deliver program has changed incompatibly, multiple times. +# +old-cyrus unix - n n - - pipe + flags=R user=cyrus argv=/usr/lib/cyrus-imapd/deliver -e -m ${extension} ${user} +# Cyrus 2.1.5 (Amos Gouaux) +# Also specify in main.cf: cyrus_destination_recipient_limit=1 +cyrus unix - n n - - pipe + user=cyrus argv=/usr/lib/cyrus-imapd/deliver -e -r ${sender} -m ${extension} ${user} +# +# See the Postfix UUCP_README file for configuration details. +# +uucp unix - n n - - pipe + flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient) +# +# Other external delivery methods. +# +ifmail unix - n n - - pipe + flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient) +bsmtp unix - n n - - pipe + flags=Fq. user=foo argv=/usr/local/sbin/bsmtp -f $sender $nexthop $recipient diff --git a/postfix/templates/default/sasl_passwd.erb b/postfix/templates/default/sasl_passwd.erb new file mode 100644 index 0000000..10a4a23 --- /dev/null +++ b/postfix/templates/default/sasl_passwd.erb @@ -0,0 +1 @@ +<%= @node[:postfix][:relayhost] %> <%= @node[:postfix][:smtp_sasl_user_name] %>:<%= @node[:postfix][:smtp_sasl_passwd] %> diff --git a/postgresql/README.rdoc b/postgresql/README.rdoc new file mode 100644 index 0000000..3348946 --- /dev/null +++ b/postgresql/README.rdoc @@ -0,0 +1,45 @@ += DESCRIPTION: + +Installs and configures postgresql client or server. + += REQUIREMENTS: + +== Platform: + +Tested on Ubuntu 8.10, but adapted from Red Hat Enterprise 5.0 based recipes. + +== Cookbooks: + += ATTRIBUTES: + +* postgresql[:dir] - configuration file location. + += USAGE: + +For clients: + + include_recipe "postgresql::client" + +For server: + + include_recipe "postgresql::server" + +(client is already included by server) + += LICENSE and AUTHOR: + +Author:: Joshua Timberman () + +Copyright:: 2009, Opscode, 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/postgresql/attributes/postgresql.rb b/postgresql/attributes/postgresql.rb new file mode 100644 index 0000000..fed13ea --- /dev/null +++ b/postgresql/attributes/postgresql.rb @@ -0,0 +1,27 @@ +# +# Cookbook Name:: postgresql +# Attributes:: postgresql +# +# Copyright 2008-2009, Opscode, 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. +# + +case platform +when "redhat","centos","fedora","suse" + set[:postgresql][:dir] = "/var/lib/pgsql/data" +when "debian","ubuntu" + set[:postgresql][:dir] = "/etc/postgresql/8.3/main" +else + set[:postgresql][:dir] = "/etc/postgresql/8.3/main" +end diff --git a/postgresql/metadata.json b/postgresql/metadata.json new file mode 100644 index 0000000..2cfeee6 --- /dev/null +++ b/postgresql/metadata.json @@ -0,0 +1,67 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs and configures postgresql for clients or servers", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "postgresql::server": "Installs postgresql server packages, templates", + "postgresql::client": "Installs postgresql client package(s)", + "postgresql": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "rhel": [ + + ], + "centos": [ + + ], + "debian": [ + + ] + }, + "version": "0.7.0", + "name": "postgresql", + "conflicting": { + + }, + "attributes": { + "postgresql\/dir": { + "default": "\/etc\/postgresql\/8.3\/main", + "type": "string", + "multiple_values": false, + "description": "Location of the PostgreSQL databases", + "display_name": "PostgreSQL Directory", + "recipes": [ + + ], + "required": false + } + }, + "providing": { + "postgresql::server": [ + + ], + "postgresql::client": [ + + ], + "postgresql": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "= DESCRIPTION:\n\nInstalls and configures postgresql client or server.\n\n= REQUIREMENTS:\n\n== Platform:\n\nTested on Ubuntu 8.10, but adapted from Red Hat Enterprise 5.0 based recipes.\n\n== Cookbooks:\n\n= ATTRIBUTES: \n\n* postgresql[:dir] - configuration file location.\n\n= USAGE:\n\nFor clients:\n\n include_recipe \"postgresql::client\"\n \nFor server: \n\n include_recipe \"postgresql::server\"\n \n(client is already included by server)\n\n= LICENSE and AUTHOR:\n \nAuthor:: Joshua Timberman ()\n\nCopyright:: 2009, Opscode, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http:\/\/www.apache.org\/licenses\/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/postgresql/metadata.rb b/postgresql/metadata.rb new file mode 100644 index 0000000..4721911 --- /dev/null +++ b/postgresql/metadata.rb @@ -0,0 +1,18 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs and configures postgresql for clients or servers" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.7" +recipe "postgresql::client", "Installs postgresql client package(s)" +recipe "postgresql::server", "Installs postgresql server packages, templates" + +%w{rhel centos ubuntu debian}.each do |os| + supports os +end + +attribute "postgresql/dir", + :display_name => "PostgreSQL Directory", + :description => "Location of the PostgreSQL databases", + :default => "/etc/postgresql/8.3/main" + diff --git a/postgresql/recipes/client.rb b/postgresql/recipes/client.rb new file mode 100644 index 0000000..7e6043b --- /dev/null +++ b/postgresql/recipes/client.rb @@ -0,0 +1,25 @@ +# +# Cookbook Name:: postgresql +# Recipe:: client +# +# Copyright 2009, Opscode, 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. +# + +case node[:platform] +when "ubuntu","debian" + package "postgresql-client" +when "redhat","centos","fedora" + package "postgresql-devel" +end diff --git a/postgresql/recipes/default.rb b/postgresql/recipes/default.rb new file mode 100644 index 0000000..8563c05 --- /dev/null +++ b/postgresql/recipes/default.rb @@ -0,0 +1,18 @@ +# +# Cookbook Name:: postgresql +# Recipe:: default +# +# Copyright 2009, Opscode, 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/postgresql/recipes/server.rb b/postgresql/recipes/server.rb new file mode 100644 index 0000000..75ada22 --- /dev/null +++ b/postgresql/recipes/server.rb @@ -0,0 +1,47 @@ +#/postgresql.conf. +# Cookbook Name:: postgresql +# Recipe:: server +# +# Copyright 2009, Opscode, 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 "postgresql::client" + +package "postgresql" + +service "postgresql" do + case node[:platform] + when "debian","ubuntu" + service_name "postgresql-8.3" + end + supports :restart => true, :status => true, :reload => true + action :nothing +end + +template "#{node[:postgresql][:dir]}/pg_hba.conf" do + source "pg_hba.conf.erb" + owner "postgres" + group "postgres" + mode 0600 + notifies :reload, resources(:service => "postgresql") +end + +template "#{node[:postgresql][:dir]}/postgresql.conf" do + source "postgresql.conf.erb" + owner "postgres" + group "postgres" + mode 0600 + notifies :restart, resources(:service => "postgresql") +end diff --git a/postgresql/templates/default/pg_hba.conf.erb b/postgresql/templates/default/pg_hba.conf.erb new file mode 100644 index 0000000..524cbb9 --- /dev/null +++ b/postgresql/templates/default/pg_hba.conf.erb @@ -0,0 +1,83 @@ +# PostgreSQL Client Authentication Configuration File +# =================================================== +# +# Refer to the "Client Authentication" section in the +# PostgreSQL documentation for a complete description +# of this file. A short synopsis follows. +# +# This file controls: which hosts are allowed to connect, how clients +# are authenticated, which PostgreSQL user names they can use, which +# databases they can access. Records take one of these forms: +# +# local DATABASE USER METHOD [OPTION] +# host DATABASE USER CIDR-ADDRESS METHOD [OPTION] +# hostssl DATABASE USER CIDR-ADDRESS METHOD [OPTION] +# hostnossl DATABASE USER CIDR-ADDRESS METHOD [OPTION] +# +# (The uppercase items must be replaced by actual values.) +# +# The first field is the connection type: "local" is a Unix-domain socket, +# "host" is either a plain or SSL-encrypted TCP/IP socket, "hostssl" is an +# SSL-encrypted TCP/IP socket, and "hostnossl" is a plain TCP/IP socket. +# +# DATABASE can be "all", "sameuser", "samerole", a database name, or +# a comma-separated list thereof. +# +# USER can be "all", a user name, a group name prefixed with "+", or +# a comma-separated list thereof. In both the DATABASE and USER fields +# you can also write a file name prefixed with "@" to include names from +# a separate file. +# +# CIDR-ADDRESS specifies the set of hosts the record matches. +# It is made up of an IP address and a CIDR mask that is an integer +# (between 0 and 32 (IPv4) or 128 (IPv6) inclusive) that specifies +# the number of significant bits in the mask. Alternatively, you can write +# an IP address and netmask in separate columns to specify the set of hosts. +# +# METHOD can be "trust", "reject", "md5", "crypt", "password", "gss", "sspi", +# "krb5", "ident", "pam" or "ldap". Note that "password" sends passwords +# in clear text; "md5" is preferred since it sends encrypted passwords. +# +# OPTION is the ident map or the name of the PAM service, depending on METHOD. +# +# Database and user names containing spaces, commas, quotes and other special +# characters must be quoted. Quoting one of the keywords "all", "sameuser" or +# "samerole" makes the name lose its special character, and just match a +# database or username with that name. +# +# This file is read on server startup and when the postmaster receives +# a SIGHUP signal. If you edit the file on a running system, you have +# to SIGHUP the postmaster for the changes to take effect. You can use +# "pg_ctl reload" to do that. + +# Put your actual configuration here +# ---------------------------------- +# +# If you want to allow non-local connections, you need to add more +# "host" records. In that case you will also need to make PostgreSQL listen +# on a non-local interface via the listen_addresses configuration parameter, +# or via the -i or -h command line switches. +# + + + + +# DO NOT DISABLE! +# If you change this first entry you will need to make sure that the +# database +# super user can access the database using some other method. +# Noninteractive +# access to all databases is required during automatic maintenance +# (autovacuum, daily cronjob, replication, and similar tasks). +# +# Database administrative login by UNIX sockets +local all postgres ident sameuser + +# TYPE DATABASE USER CIDR-ADDRESS METHOD + +# "local" is for Unix domain socket connections only +local all all ident sameuser +# IPv4 local connections: +host all all 127.0.0.1/32 md5 +# IPv6 local connections: +host all all ::1/128 md5 \ No newline at end of file diff --git a/postgresql/templates/default/postgresql.conf.erb b/postgresql/templates/default/postgresql.conf.erb new file mode 100644 index 0000000..ccc760c --- /dev/null +++ b/postgresql/templates/default/postgresql.conf.erb @@ -0,0 +1,493 @@ +# ----------------------------- +# PostgreSQL configuration file +# ----------------------------- +# +# This file consists of lines of the form: +# +# name = value +# +# (The "=" is optional.) Whitespace may be used. Comments are introduced with +# "#" anywhere on a line. The complete list of parameter names and allowed +# values can be found in the PostgreSQL documentation. +# +# The commented-out settings shown in this file represent the default values. +# Re-commenting a setting is NOT sufficient to revert it to the default value; +# you need to reload the server. +# +# This file is read on server startup and when the server receives a SIGHUP +# signal. If you edit the file on a running system, you have to SIGHUP the +# server for the changes to take effect, or use "pg_ctl reload". Some +# parameters, which are marked below, require a server shutdown and restart to +# take effect. +# +# Any parameter can also be given as a command-line option to the server, e.g., +# "postgres -c log_connections=on". Some paramters can be changed at run time +# with the "SET" SQL command. +# +# Memory units: kB = kilobytes MB = megabytes GB = gigabytes +# Time units: ms = milliseconds s = seconds min = minutes h = hours d = days + + +#------------------------------------------------------------------------------ +# FILE LOCATIONS +#------------------------------------------------------------------------------ + +# The default values of these variables are driven from the -D command-line +# option or PGDATA environment variable, represented here as ConfigDir. + +data_directory = '/var/lib/postgresql/8.3/main' # use data in another directory + # (change requires restart) +hba_file = '/etc/postgresql/8.3/main/pg_hba.conf' # host-based authentication file + # (change requires restart) +ident_file = '/etc/postgresql/8.3/main/pg_ident.conf' # ident configuration file + # (change requires restart) + +# If external_pid_file is not explicitly set, no extra PID file is written. +external_pid_file = '/var/run/postgresql/8.3-main.pid' # write an extra PID file + # (change requires restart) + + +#------------------------------------------------------------------------------ +# CONNECTIONS AND AUTHENTICATION +#------------------------------------------------------------------------------ + +# - Connection Settings - + +#listen_addresses = 'localhost' # what IP address(es) to listen on; + # comma-separated list of addresses; + # defaults to 'localhost', '*' = all + # (change requires restart) +port = 5432 # (change requires restart) +max_connections = 100 # (change requires restart) +# Note: Increasing max_connections costs ~400 bytes of shared memory per +# connection slot, plus lock space (see max_locks_per_transaction). You might +# also need to raise shared_buffers to support more connections. +#superuser_reserved_connections = 3 # (change requires restart) +unix_socket_directory = '/var/run/postgresql' # (change requires restart) +#unix_socket_group = '' # (change requires restart) +#unix_socket_permissions = 0777 # begin with 0 to use octal notation + # (change requires restart) +#bonjour_name = '' # defaults to the computer name + # (change requires restart) + +# - Security and Authentication - + +#authentication_timeout = 1min # 1s-600s +ssl = true # (change requires restart) +#ssl_ciphers = 'ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH' # allowed SSL ciphers + # (change requires restart) +#password_encryption = on +#db_user_namespace = off + +# Kerberos and GSSAPI +#krb_server_keyfile = '' # (change requires restart) +#krb_srvname = 'postgres' # (change requires restart, Kerberos only) +#krb_server_hostname = '' # empty string matches any keytab entry + # (change requires restart, Kerberos only) +#krb_caseins_users = off # (change requires restart) +#krb_realm = '' # (change requires restart) + +# - TCP Keepalives - +# see "man 7 tcp" for details + +#tcp_keepalives_idle = 0 # TCP_KEEPIDLE, in seconds; + # 0 selects the system default +#tcp_keepalives_interval = 0 # TCP_KEEPINTVL, in seconds; + # 0 selects the system default +#tcp_keepalives_count = 0 # TCP_KEEPCNT; + # 0 selects the system default + + +#------------------------------------------------------------------------------ +# RESOURCE USAGE (except WAL) +#------------------------------------------------------------------------------ + +# - Memory - + +shared_buffers = 24MB # min 128kB or max_connections*16kB + # (change requires restart) +#temp_buffers = 8MB # min 800kB +#max_prepared_transactions = 5 # can be 0 or more + # (change requires restart) +# Note: Increasing max_prepared_transactions costs ~600 bytes of shared memory +# per transaction slot, plus lock space (see max_locks_per_transaction). +#work_mem = 1MB # min 64kB +#maintenance_work_mem = 16MB # min 1MB +#max_stack_depth = 2MB # min 100kB + +# - Free Space Map - + +max_fsm_pages = 153600 # min max_fsm_relations*16, 6 bytes each + # (change requires restart) +#max_fsm_relations = 1000 # min 100, ~70 bytes each + # (change requires restart) + +# - Kernel Resource Usage - + +#max_files_per_process = 1000 # min 25 + # (change requires restart) +#shared_preload_libraries = '' # (change requires restart) + +# - Cost-Based Vacuum Delay - + +#vacuum_cost_delay = 0 # 0-1000 milliseconds +#vacuum_cost_page_hit = 1 # 0-10000 credits +#vacuum_cost_page_miss = 10 # 0-10000 credits +#vacuum_cost_page_dirty = 20 # 0-10000 credits +#vacuum_cost_limit = 200 # 1-10000 credits + +# - Background Writer - + +#bgwriter_delay = 200ms # 10-10000ms between rounds +#bgwriter_lru_maxpages = 100 # 0-1000 max buffers written/round +#bgwriter_lru_multiplier = 2.0 # 0-10.0 multipler on buffers scanned/round + + +#------------------------------------------------------------------------------ +# WRITE AHEAD LOG +#------------------------------------------------------------------------------ + +# - Settings - + +#fsync = on # turns forced synchronization on or off +#synchronous_commit = on # immediate fsync at commit +#wal_sync_method = fsync # the default is the first option + # supported by the operating system: + # open_datasync + # fdatasync + # fsync + # fsync_writethrough + # open_sync +#full_page_writes = on # recover from partial page writes +#wal_buffers = 64kB # min 32kB + # (change requires restart) +#wal_writer_delay = 200ms # 1-10000 milliseconds + +#commit_delay = 0 # range 0-100000, in microseconds +#commit_siblings = 5 # range 1-1000 + +# - Checkpoints - + +#checkpoint_segments = 3 # in logfile segments, min 1, 16MB each +#checkpoint_timeout = 5min # range 30s-1h +#checkpoint_completion_target = 0.5 # checkpoint target duration, 0.0 - 1.0 +#checkpoint_warning = 30s # 0 is off + +# - Archiving - + +#archive_mode = off # allows archiving to be done + # (change requires restart) +#archive_command = '' # command to use to archive a logfile segment +#archive_timeout = 0 # force a logfile segment switch after this + # time; 0 is off + + +#------------------------------------------------------------------------------ +# QUERY TUNING +#------------------------------------------------------------------------------ + +# - Planner Method Configuration - + +#enable_bitmapscan = on +#enable_hashagg = on +#enable_hashjoin = on +#enable_indexscan = on +#enable_mergejoin = on +#enable_nestloop = on +#enable_seqscan = on +#enable_sort = on +#enable_tidscan = on + +# - Planner Cost Constants - + +#seq_page_cost = 1.0 # measured on an arbitrary scale +#random_page_cost = 4.0 # same scale as above +#cpu_tuple_cost = 0.01 # same scale as above +#cpu_index_tuple_cost = 0.005 # same scale as above +#cpu_operator_cost = 0.0025 # same scale as above +#effective_cache_size = 128MB + +# - Genetic Query Optimizer - + +#geqo = on +#geqo_threshold = 12 +#geqo_effort = 5 # range 1-10 +#geqo_pool_size = 0 # selects default based on effort +#geqo_generations = 0 # selects default based on effort +#geqo_selection_bias = 2.0 # range 1.5-2.0 + +# - Other Planner Options - + +#default_statistics_target = 10 # range 1-1000 +#constraint_exclusion = off +#from_collapse_limit = 8 +#join_collapse_limit = 8 # 1 disables collapsing of explicit + # JOIN clauses + + +#------------------------------------------------------------------------------ +# ERROR REPORTING AND LOGGING +#------------------------------------------------------------------------------ + +# - Where to Log - + +#log_destination = 'stderr' # Valid values are combinations of + # stderr, csvlog, syslog and eventlog, + # depending on platform. csvlog + # requires logging_collector to be on. + +# This is used when logging to stderr: +#logging_collector = off # Enable capturing of stderr and csvlog + # into log files. Required to be on for + # csvlogs. + # (change requires restart) + +# These are only used if logging_collector is on: +#log_directory = 'pg_log' # directory where log files are written, + # can be absolute or relative to PGDATA +#log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' # log file name pattern, + # can include strftime() escapes +#log_truncate_on_rotation = off # If on, an existing log file of the + # same name as the new log file will be + # truncated rather than appended to. + # But such truncation only occurs on + # time-driven rotation, not on restarts + # or size-driven rotation. Default is + # off, meaning append to existing files + # in all cases. +#log_rotation_age = 1d # Automatic rotation of logfiles will + # happen after that time. 0 to disable. +#log_rotation_size = 10MB # Automatic rotation of logfiles will + # happen after that much log output. + # 0 to disable. + +# These are relevant when logging to syslog: +#syslog_facility = 'LOCAL0' +#syslog_ident = 'postgres' + + +# - When to Log - + +#client_min_messages = notice # values in order of decreasing detail: + # debug5 + # debug4 + # debug3 + # debug2 + # debug1 + # log + # notice + # warning + # error + +#log_min_messages = notice # values in order of decreasing detail: + # debug5 + # debug4 + # debug3 + # debug2 + # debug1 + # info + # notice + # warning + # error + # log + # fatal + # panic + +#log_error_verbosity = default # terse, default, or verbose messages + +#log_min_error_statement = error # values in order of decreasing detail: + # debug5 + # debug4 + # debug3 + # debug2 + # debug1 + # info + # notice + # warning + # error + # log + # fatal + # panic (effectively off) + +#log_min_duration_statement = -1 # -1 is disabled, 0 logs all statements + # and their durations, > 0 logs only + # statements running at least this time. + +#silent_mode = off # DO NOT USE without syslog or + # logging_collector + # (change requires restart) + +# - What to Log - + +#debug_print_parse = off +#debug_print_rewritten = off +#debug_print_plan = off +#debug_pretty_print = off +#log_checkpoints = off +#log_connections = off +#log_disconnections = off +#log_duration = off +#log_hostname = off +log_line_prefix = '%t ' # special values: + # %u = user name + # %d = database name + # %r = remote host and port + # %h = remote host + # %p = process ID + # %t = timestamp without milliseconds + # %m = timestamp with milliseconds + # %i = command tag + # %c = session ID + # %l = session line number + # %s = session start timestamp + # %v = virtual transaction ID + # %x = transaction ID (0 if none) + # %q = stop here in non-session + # processes + # %% = '%' + # e.g. '<%u%%%d> ' +#log_lock_waits = off # log lock waits >= deadlock_timeout +#log_statement = 'none' # none, ddl, mod, all +#log_temp_files = -1 # log temporary files equal or larger + # than specified size; + # -1 disables, 0 logs all temp files +#log_timezone = unknown # actually, defaults to TZ environment + # setting + + +#------------------------------------------------------------------------------ +# RUNTIME STATISTICS +#------------------------------------------------------------------------------ + +# - Query/Index Statistics Collector - + +#track_activities = on +#track_counts = on +#update_process_title = on + + +# - Statistics Monitoring - + +#log_parser_stats = off +#log_planner_stats = off +#log_executor_stats = off +#log_statement_stats = off + + +#------------------------------------------------------------------------------ +# AUTOVACUUM PARAMETERS +#------------------------------------------------------------------------------ + +#autovacuum = on # Enable autovacuum subprocess? 'on' + # requires track_counts to also be on. +#log_autovacuum_min_duration = -1 # -1 disables, 0 logs all actions and + # their durations, > 0 logs only + # actions running at least that time. +#autovacuum_max_workers = 3 # max number of autovacuum subprocesses +#autovacuum_naptime = 1min # time between autovacuum runs +#autovacuum_vacuum_threshold = 50 # min number of row updates before + # vacuum +#autovacuum_analyze_threshold = 50 # min number of row updates before + # analyze +#autovacuum_vacuum_scale_factor = 0.2 # fraction of table size before vacuum +#autovacuum_analyze_scale_factor = 0.1 # fraction of table size before analyze +#autovacuum_freeze_max_age = 200000000 # maximum XID age before forced vacuum + # (change requires restart) +#autovacuum_vacuum_cost_delay = 20 # default vacuum cost delay for + # autovacuum, -1 means use + # vacuum_cost_delay +#autovacuum_vacuum_cost_limit = -1 # default vacuum cost limit for + # autovacuum, -1 means use + # vacuum_cost_limit + + +#------------------------------------------------------------------------------ +# CLIENT CONNECTION DEFAULTS +#------------------------------------------------------------------------------ + +# - Statement Behavior - + +#search_path = '"$user",public' # schema names +#default_tablespace = '' # a tablespace name, '' uses the default +#temp_tablespaces = '' # a list of tablespace names, '' uses + # only default tablespace +#check_function_bodies = on +#default_transaction_isolation = 'read committed' +#default_transaction_read_only = off +#session_replication_role = 'origin' +#statement_timeout = 0 # 0 is disabled +#vacuum_freeze_min_age = 100000000 +#xmlbinary = 'base64' +#xmloption = 'content' + +# - Locale and Formatting - + +datestyle = 'iso, mdy' +#timezone = unknown # actually, defaults to TZ environment + # setting +#timezone_abbreviations = 'Default' # Select the set of available time zone + # abbreviations. Currently, there are + # Default + # Australia + # India + # You can create your own file in + # share/timezonesets/. +#extra_float_digits = 0 # min -15, max 2 +#client_encoding = sql_ascii # actually, defaults to database + # encoding + +# These settings are initialized by initdb, but they can be changed. +lc_messages = 'en_US.UTF-8' # locale for system error message + # strings +lc_monetary = 'en_US.UTF-8' # locale for monetary formatting +lc_numeric = 'en_US.UTF-8' # locale for number formatting +lc_time = 'en_US.UTF-8' # locale for time formatting + +# default configuration for text search +default_text_search_config = 'pg_catalog.english' + +# - Other Defaults - + +#explain_pretty_print = on +#dynamic_library_path = '$libdir' +#local_preload_libraries = '' + + +#------------------------------------------------------------------------------ +# LOCK MANAGEMENT +#------------------------------------------------------------------------------ + +#deadlock_timeout = 1s +#max_locks_per_transaction = 64 # min 10 + # (change requires restart) +# Note: Each lock table slot uses ~270 bytes of shared memory, and there are +# max_locks_per_transaction * (max_connections + max_prepared_transactions) +# lock table slots. + + +#------------------------------------------------------------------------------ +# VERSION/PLATFORM COMPATIBILITY +#------------------------------------------------------------------------------ + +# - Previous PostgreSQL Versions - + +#add_missing_from = off +#array_nulls = on +#backslash_quote = safe_encoding # on, off, or safe_encoding +#default_with_oids = off +#escape_string_warning = on +#regex_flavor = advanced # advanced, extended, or basic +#sql_inheritance = on +#standard_conforming_strings = off +#synchronize_seqscans = on + +# - Other Platforms and Clients - + +#transform_null_equals = off + + +#------------------------------------------------------------------------------ +# CUSTOMIZED OPTIONS +#------------------------------------------------------------------------------ + +#custom_variable_classes = '' # list of custom variable class names diff --git a/python/metadata.json b/python/metadata.json new file mode 100644 index 0000000..b34acf8 --- /dev/null +++ b/python/metadata.json @@ -0,0 +1,43 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs python packages", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "python": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "debian": [ + + ] + }, + "version": "0.7.0", + "name": "python", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "python": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/python/metadata.rb b/python/metadata.rb new file mode 100644 index 0000000..d134052 --- /dev/null +++ b/python/metadata.rb @@ -0,0 +1,9 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs python packages" +version "0.7" + +%w{ debian ubuntu }.each do |os| + supports os +end diff --git a/python/recipes/default.rb b/python/recipes/default.rb new file mode 100644 index 0000000..bc97e7e --- /dev/null +++ b/python/recipes/default.rb @@ -0,0 +1,30 @@ +# +# Cookbook Name:: python +# Recipe:: default +# +# Copyright 2009, Opscode, 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 "python" do + action :install +end + +%w{ + dev imaging matplotlib matplotlib-data matplotlib-doc mysqldb + numpy numpy-ext paramiko scipy setuptools sqlite +}.each do |pkg| + package "python-#{pkg}" do + action :install + end +end diff --git a/quick_start/attributes/quick_start.rb b/quick_start/attributes/quick_start.rb new file mode 100644 index 0000000..1ce3289 --- /dev/null +++ b/quick_start/attributes/quick_start.rb @@ -0,0 +1 @@ +deep_thought "If a tree falls in the forest..." diff --git a/quick_start/metadata.json b/quick_start/metadata.json new file mode 100644 index 0000000..03ef2c3 --- /dev/null +++ b/quick_start/metadata.json @@ -0,0 +1,74 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Example cookbook for quick_start wiki document", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "quick_start": "" + }, + "suggestions": { + + }, + "platforms": { + "solaris": [ + + ], + "freebsd": [ + + ], + "ubuntu": [ + + ], + "openbsd": [ + + ], + "fedora": [ + + ], + "macosx": [ + + ], + "centos": [ + + ], + "debian": [ + + ], + "redhat": [ + + ] + }, + "version": "0.7.0", + "name": "quick_start", + "conflicting": { + + }, + "attributes": { + "quick_start\/deep_thought": { + "default": "If a tree falls in the forest...", + "type": "string", + "multiple_values": false, + "description": "A deep thought", + "display_name": "Quick Start Deep Thought", + "recipes": [ + + ], + "required": false + } + }, + "providing": { + "quick_start": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/quick_start/metadata.rb b/quick_start/metadata.rb new file mode 100644 index 0000000..e74eedb --- /dev/null +++ b/quick_start/metadata.rb @@ -0,0 +1,19 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Example cookbook for quick_start wiki document" +version "0.7" + +%w{ + redhat fedora centos + ubuntu debian + macosx freebsd openbsd + solaris +}.each do |os| + supports os +end + +attribute "quick_start/deep_thought", + :display_name => "Quick Start Deep Thought", + :description => "A deep thought", + :default => "If a tree falls in the forest..." diff --git a/quick_start/recipes/default.rb b/quick_start/recipes/default.rb new file mode 100644 index 0000000..dc3d695 --- /dev/null +++ b/quick_start/recipes/default.rb @@ -0,0 +1,24 @@ +# +# Cookbook Name:: quick_start +# Recipe:: default +# +# Copyright 2009, OpsCode +# +# 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. +# + +template "/tmp/deep_thought.txt" do + source "deep_thought.txt.erb" + variables :deep_thought => node[:deep_thought] + action :create +end diff --git a/quick_start/templates/default/deep_thought.txt.erb b/quick_start/templates/default/deep_thought.txt.erb new file mode 100644 index 0000000..d4c9713 --- /dev/null +++ b/quick_start/templates/default/deep_thought.txt.erb @@ -0,0 +1 @@ +Todays deep thought: <%= @deep_thought %> diff --git a/rabbitmq/metadata.json b/rabbitmq/metadata.json new file mode 100755 index 0000000..81d7fc9 --- /dev/null +++ b/rabbitmq/metadata.json @@ -0,0 +1,52 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs the RabbitMQ AMQP Broker", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "rabbitmq": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "fedora": [ + + ], + "centos": [ + + ], + "debian": [ + + ], + "redhat": [ + + ] + }, + "version": "0.8.0", + "name": "rabbitmq", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "rabbitmq": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/rabbitmq/metadata.rb b/rabbitmq/metadata.rb new file mode 100755 index 0000000..04b1594 --- /dev/null +++ b/rabbitmq/metadata.rb @@ -0,0 +1,9 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs the RabbitMQ AMQP Broker" +version "0.8" + +%w{ centos redhat fedora ubuntu debian }.each do |os| + supports os +end diff --git a/rabbitmq/recipes/default.rb b/rabbitmq/recipes/default.rb new file mode 100755 index 0000000..1e57993 --- /dev/null +++ b/rabbitmq/recipes/default.rb @@ -0,0 +1,13 @@ +# Is this valid for all platforms? Is it not just rabbitmq on some platform? +# Valid for ubuntu, *probably* debian and EL5 +# http://download.fedora.redhat.com/pub/epel/5/x86_64/repoview/letter_r.group.html +package "rabbitmq-server" + +service "rabbitmq-server" do + if platform?("centos","redhat","fedora") + start_command "/sbin/service rabbitmq-server start &> /dev/null" + stop_command "/sbin/service rabbitmq-server stop &> /dev/null" + end + supports [ :restart, :status ] + action [ :enable, :start ] +end diff --git a/radiant/README.rdoc b/radiant/README.rdoc new file mode 100644 index 0000000..3418f8b --- /dev/null +++ b/radiant/README.rdoc @@ -0,0 +1,74 @@ += DESCRIPTION: + +Installs RadiantCMS, a Ruby on Rails content management system. + += CHANGELOG: + +Changes to note in this version (from COOK-117). + +* added gem install capabilities +* default to gem install +* removed dependency on ezmobius/chef-deploy (use deploy provider instead) +* fixed tiny error in attributes. +* updated attribute syntax + += REQUIREMENTS: + +== Platform: + +Tested on Ubuntu 9.04, uses the Opscode Apache2 cookbook which is Ubuntu/Debian specific. + +Requires Chef 0.7.12 for Deploy resource when installing from Radiant's git repo. + +== Cookbooks: + +Opscode cookbooks (http://github.com/opscode/cookbooks/tree/master) + +* git +* sqlite +* rails +* apache2 + += ATTRIBUTES: + +* radiant[:edge] - Do a deploy from github repo if true, use gems if false, default false. +* radiant[:branch] - Branch to deploy from, default HEAD. +* radiant[:migrate] - Whether to do a database migration, default false. +* radiant[:migrate_command] - Command to do a database migration, default 'rake db:migrate'. +* radiant[:environment] - Rails environment to use, default is production. +* radiant[:revision] - Revision to deploy, default HEAD. +* radiant[:action] - Whether to deploy, rollback or nothing, default nothing. + += USAGE: + +This recipe uses SQLite3 for the database by default. To set up the default database to get Radiant rolling, run a db:bootstrap by changing the radiant[:migrate] command to the following in the webui: + + yes | rake production db:bootstrap \ + ADMIN_NAME=Administrator \ + ADMIN_USERNAME=admin \ + ADMIN_PASSWORD=radiant \ + DATABASE_TEMPLATE=empty.yml + +Change as required for your environment. If the target system doesn't have /usr/bin/yes, use echo 'yes' instead. + +Radiant supports other database backends. We don't yet have automation ready to set up a database user and grant privileges, or creating the database itself. + += LICENSE and AUTHOR: + + +Author:: Joshua Timberman () +Copyright:: 2009, Opscode, 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/radiant/attributes/radiant.rb b/radiant/attributes/radiant.rb new file mode 100644 index 0000000..747cdef --- /dev/null +++ b/radiant/attributes/radiant.rb @@ -0,0 +1,27 @@ +# +# Cookbook Name:: radiant +# Attributes:: radiant +# +# Copyright 2009, Opscode, Inc. +# Copyright 2009, Daniel DeLeo +# +# 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. +# + +set_unless[:radiant][:branch] = "HEAD" +set_unless[:radiant][:migrate] = false +set_unless[:radiant][:migrate_command] = "rake db:migrate" +set_unless[:radiant][:environment] = "production" +set_unless[:radiant][:revision] = "HEAD" +set_unless[:radiant][:action] = "nothing" +set_unless[:radiant][:edge] = false diff --git a/radiant/libraries/radiant.rb b/radiant/libraries/radiant.rb new file mode 100644 index 0000000..ab779bf --- /dev/null +++ b/radiant/libraries/radiant.rb @@ -0,0 +1,7 @@ +class Chef + class Recipe + def radiant_edge? + @node[:radiant][:edge] + end + end +end \ No newline at end of file diff --git a/radiant/metadata.json b/radiant/metadata.json new file mode 100644 index 0000000..4ff6fcd --- /dev/null +++ b/radiant/metadata.json @@ -0,0 +1,125 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs radiant from Git repository", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "radiant": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "debian": [ + + ] + }, + "version": "0.9.0", + "name": "radiant", + "conflicting": { + + }, + "attributes": { + "radiant\/action": { + "default": "nothing", + "type": "string", + "multiple_values": false, + "description": "Whether to deploy the application or not", + "display_name": "Radiant Action", + "recipes": [ + + ], + "required": false + }, + "radiant\/revision": { + "default": "HEAD", + "type": "string", + "multiple_values": false, + "description": "Revision to use from Git", + "display_name": "Radiant Revision", + "recipes": [ + + ], + "required": false + }, + "radiant\/environment": { + "default": "production", + "type": "string", + "multiple_values": false, + "description": "Rails environment to use", + "display_name": "Radiant Environment", + "recipes": [ + + ], + "required": false + }, + "radiant\/migrate_command": { + "default": "rake db:migrate", + "type": "string", + "multiple_values": false, + "description": "Command to perform migration", + "display_name": "Radiant Migrate Command", + "recipes": [ + + ], + "required": false + }, + "radiant\/migrate": { + "default": "false", + "type": "string", + "multiple_values": false, + "description": "Whether to do a migration", + "display_name": "Radiant Migrate", + "recipes": [ + + ], + "required": false + }, + "radiant\/branch": { + "default": "HEAD", + "type": "string", + "multiple_values": false, + "description": "Branch from Git to use", + "display_name": "Radiant Branch", + "recipes": [ + + ], + "required": false + } + }, + "providing": { + "radiant": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "= DESCRIPTION:\n\nInstalls RadiantCMS, a Ruby on Rails content management system.\n\n= CHANGELOG:\n\nChanges to note in this version (from COOK-117).\n\n* added gem install capabilities\n* default to gem install\n* removed dependency on ezmobius\/chef-deploy (use deploy provider instead)\n* fixed tiny error in attributes.\n* updated attribute syntax\n\n= REQUIREMENTS:\n\n== Platform:\n\nTested on Ubuntu 9.04, uses the Opscode Apache2 cookbook which is Ubuntu\/Debian specific.\n\nRequires Chef 0.7.12 for Deploy resource when installing from Radiant's git repo.\n\n== Cookbooks:\n\nOpscode cookbooks (http:\/\/github.com\/opscode\/cookbooks\/tree\/master)\n\n* git\n* sqlite\n* rails\n* apache2\n\n= ATTRIBUTES:\n\n* radiant[:edge] - Do a deploy from github repo if true, use gems if false, default false.\n* radiant[:branch] - Branch to deploy from, default HEAD.\n* radiant[:migrate] - Whether to do a database migration, default false.\n* radiant[:migrate_command] - Command to do a database migration, default 'rake db:migrate'.\n* radiant[:environment] - Rails environment to use, default is production.\n* radiant[:revision] - Revision to deploy, default HEAD.\n* radiant[:action] - Whether to deploy, rollback or nothing, default nothing.\n\n= USAGE:\n\nThis recipe uses SQLite3 for the database by default. To set up the default database to get Radiant rolling, run a db:bootstrap by changing the radiant[:migrate] command to the following in the webui:\n\n yes | rake production db:bootstrap \\\n ADMIN_NAME=Administrator \\\n ADMIN_USERNAME=admin \\\n ADMIN_PASSWORD=radiant \\\n DATABASE_TEMPLATE=empty.yml\n\nChange as required for your environment. If the target system doesn't have \/usr\/bin\/yes, use echo 'yes' instead.\n\nRadiant supports other database backends. We don't yet have automation ready to set up a database user and grant privileges, or creating the database itself.\n\n= LICENSE and AUTHOR:\n\n\nAuthor:: Joshua Timberman ()\nCopyright:: 2009, Opscode, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http:\/\/www.apache.org\/licenses\/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\n\n", + "replacing": { + + }, + "dependencies": { + "rails": [ + + ], + "passenger_apache2": [ + + ], + "mysql": [ + + ], + "sqlite": [ + + ], + "git": [ + + ], + "apache2": [ + + ] + } +} \ No newline at end of file diff --git a/radiant/metadata.rb b/radiant/metadata.rb new file mode 100644 index 0000000..fcbd009 --- /dev/null +++ b/radiant/metadata.rb @@ -0,0 +1,44 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs radiant from Git repository" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.9" + +%w{ git sqlite rails apache2 mysql passenger_apache2 apache2 }.each do |cb| + depends cb +end + +%w{ ubuntu debian }.each do |os| + supports os +end + +attribute "radiant/branch", + :display_name => "Radiant Branch", + :description => "Branch from Git to use", + :default => "HEAD" + +attribute "radiant/migrate", + :display_name => "Radiant Migrate", + :description => "Whether to do a migration", + :default => "false" + +attribute "radiant/migrate_command", + :display_name => "Radiant Migrate Command", + :description => "Command to perform migration", + :default => "rake db:migrate" + +attribute "radiant/environment", + :display_name => "Radiant Environment", + :description => "Rails environment to use", + :default => "production" + +attribute "radiant/revision", + :display_name => "Radiant Revision", + :description => "Revision to use from Git", + :default => "HEAD" + +attribute "radiant/action", + :display_name => "Radiant Action", + :description => "Whether to deploy the application or not", + :default => "nothing" diff --git a/radiant/recipes/default.rb b/radiant/recipes/default.rb new file mode 100644 index 0000000..3080367 --- /dev/null +++ b/radiant/recipes/default.rb @@ -0,0 +1,95 @@ +# +# Author:: Joshua Timberman +# Author:: Daniel DeLeo +# Cookbook Name:: radiant +# Recipe:: default +# +# Copyright 2009, Opscode, Inc. +# Copyright 2009, Daniel DeLeo +# +# 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. +# + +appname = "radiant" + +include_recipe "git" +include_recipe "sqlite" +include_recipe "rails" +include_recipe "apache2" +include_recipe "apache2::mod_rewrite" +include_recipe "passenger_apache2::mod_rails" + +gem_package "sqlite3-ruby" + +if radiant_edge? + + %w{config log pids sqlite system}.each do |dir| + directory "/srv/#{appname}/shared/#{dir}" do + recursive true + owner "railsdev" + group "railsdev" + mode "0775" + end + end + + template "/srv/#{appname}/shared/config/database.yml" do + source "database.yml.erb" + owner "railsdev" + group "railsdev" + variables :appname => appname + mode "0664" + end + + file "/srv/#{appname}/shared/sqlite/production.sqlite3" do + owner "railsdev" + group "railsdev" + mode "0664" + end + + deploy "/srv/#{appname}" do + repo "git://github.com/radiant/radiant.git" + branch node[:radiant][:branch] + user "railsdev" + enable_submodules false + migrate node[:radiant][:migrate] + migration_command node[:radiant][:migrate_command] + environment node[:radiant][:environment] + shallow_clone true + revision node[:radiant][:revision] + action node[:radiant][:action].to_sym + restart_command "touch tmp/restart.txt" + end +else + directory "/srv/#{appname}/current/" do + recursive true + owner "railsdev" + group "railsdev" + mode "0775" + end + + gem_package "radiant" + + execute "radiant_generate" do + command "radiant -d sqlite3 /srv/#{appname}/current/" + creates "/srv/#{appname}/current/public" + user "railsdev" + end +end + +web_app "#{appname}" do + docroot "/srv/#{appname}/current/public" + template "#{appname}.conf.erb" + server_name "#{appname}.#{node[:domain]}" + server_aliases [ "#{appname}", node[:hostname] ] + rails_env "production" +end diff --git a/radiant/templates/default/database.yml.erb b/radiant/templates/default/database.yml.erb new file mode 100644 index 0000000..e9a7e46 --- /dev/null +++ b/radiant/templates/default/database.yml.erb @@ -0,0 +1,4 @@ +production: + adapter: sqlite3 + database: /srv/<%= @appname %>/shared/sqlite/production.sqlite3 + timeout: 5000 diff --git a/radiant/templates/default/radiant.conf.erb b/radiant/templates/default/radiant.conf.erb new file mode 100644 index 0000000..4115cc7 --- /dev/null +++ b/radiant/templates/default/radiant.conf.erb @@ -0,0 +1,21 @@ + + ServerName <%= @params[:server_name] %> + ServerAlias <% @params[:server_aliases].each do |a| %><%= "#{a}" %> <% end %> + DocumentRoot <%= @params[:docroot] %> + + RailsBaseURI / + RailsEnv <%= @params[:rails_env] %> + + PassengerMaxPoolSize <%= @node[:rails][:max_pool_size] %> + + > + Options FollowSymLinks + AllowOverride None + Order allow,deny + Allow from all + + + LogLevel info + ErrorLog <%= @node[:apache][:log_dir] %>/<%= @params[:name] %>-error.log + CustomLog <%= @node[:apache][:log_dir] %>/<%= @params[:name] %>-access.log combined + diff --git a/rails/README.rdoc b/rails/README.rdoc new file mode 100644 index 0000000..70e8583 --- /dev/null +++ b/rails/README.rdoc @@ -0,0 +1,54 @@ += DESCRIPTION: + +Installs Rails and contains Rails tuning parameters. + += REQUIREMENTS: + +== Platform: + +Tested on Ubuntu 8.10, should work on other platforms. + +== Cookbooks: + +Opscode cookbooks, http://github.com/opscode/cookbooks/tree/master: + +* ruby +* apache2 +* passenger + += ATTRIBUTES: + +* rails[:version] - Install the specified version. Default false (installs latest). +* rails[:environment] - Set Rails environment. Default production. + += USAGE: + +The recommended Rails application deployment method is Passenger and use the Apache2 cookbook's web_app define. + + include_recipe "apache2" + include_recipe "passenger" + include_recipe "rails" + + web_app "some_rails_app" do + docroot "/srv/some_rails_app/public" + template "some_rails_app.conf.erb" + end + +We provide an example rails application vhost config file in this cookbook. Remember, for Passenger, DocumentRoot (docroot) needs 'public'. Per the web_app define, other parameters can be passed arbitrarily and used in the template. + += LICENSE and AUTHOR: + +Author:: Joshua Timberman () +Copyright:: 2009, Opscode, 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/rails/attributes/rails.rb b/rails/attributes/rails.rb new file mode 100644 index 0000000..f3122b7 --- /dev/null +++ b/rails/attributes/rails.rb @@ -0,0 +1,3 @@ +set_unless[:rails][:version] = false +set_unless[:rails][:environment] = "production" +set_unless[:rails][:max_pool_size] = 4 diff --git a/rails/metadata.json b/rails/metadata.json new file mode 100644 index 0000000..ae78d6c --- /dev/null +++ b/rails/metadata.json @@ -0,0 +1,99 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs rails and provides a sample template for use with passenger", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "rails": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "fedora": [ + + ], + "centos": [ + + ], + "redhat": [ + + ], + "debian": [ + + ] + }, + "version": "0.8.0", + "name": "rails", + "conflicting": { + + }, + "attributes": { + "rails": { + "type": "hash", + "multiple_values": false, + "description": "Hash of Rails attributes", + "display_name": "Rails", + "recipes": [ + + ], + "required": false + }, + "rails\/version": { + "default": "false", + "type": "string", + "multiple_values": false, + "description": "Specify the version of Rails to install", + "display_name": "Rails Version", + "recipes": [ + + ], + "required": false + }, + "rails\/max_pool_size": { + "default": "4", + "type": "string", + "multiple_values": false, + "description": "Specify the MaxPoolSize in the Apache vhost", + "display_name": "Rails Max Pool Size", + "recipes": [ + + ], + "required": false + }, + "rails\/environment": { + "default": "production", + "type": "string", + "multiple_values": false, + "description": "Specify the environment to use for Rails", + "display_name": "Rails Environment", + "recipes": [ + + ], + "required": false + } + }, + "providing": { + "rails": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "= DESCRIPTION:\n\nInstalls Rails and contains Rails tuning parameters.\n\n= REQUIREMENTS:\n\n== Platform:\n\nTested on Ubuntu 8.10, should work on other platforms.\n\n== Cookbooks:\n\nOpscode cookbooks, http:\/\/github.com\/opscode\/cookbooks\/tree\/master:\n\n* ruby \n* apache2 \n* passenger \n\n= ATTRIBUTES: \n\n* rails[:version] - Install the specified version. Default false (installs latest).\n* rails[:environment] - Set Rails environment. Default production.\n\n= USAGE:\n\nThe recommended Rails application deployment method is Passenger and use the Apache2 cookbook's web_app define.\n\n include_recipe \"apache2\"\n include_recipe \"passenger\"\n include_recipe \"rails\"\n\n web_app \"some_rails_app\" do\n docroot \"\/srv\/some_rails_app\/public\"\n template \"some_rails_app.conf.erb\"\n end\n\nWe provide an example rails application vhost config file in this cookbook. Remember, for Passenger, DocumentRoot (docroot) needs 'public'. Per the web_app define, other parameters can be passed arbitrarily and used in the template. \n\n= LICENSE and AUTHOR:\n\nAuthor:: Joshua Timberman ()\nCopyright:: 2009, Opscode, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http:\/\/www.apache.org\/licenses\/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n", + "replacing": { + + }, + "dependencies": { + "apache2": [ + + ], + "ruby": [ + + ] + } +} \ No newline at end of file diff --git a/rails/metadata.rb b/rails/metadata.rb new file mode 100644 index 0000000..75112e4 --- /dev/null +++ b/rails/metadata.rb @@ -0,0 +1,35 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs rails and provides a sample template for use with passenger" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.8" + +%w{ ruby apache2 }.each do |cb| + depends cb +end + +%w{ ubuntu debian centos redhat fedora}.each do |os| + supports os +end + +attribute "rails", + :display_name => "Rails", + :description => "Hash of Rails attributes", + :type => "hash" + +attribute "rails/version", + :display_name => "Rails Version", + :description => "Specify the version of Rails to install", + :default => "false" + +attribute "rails/environment", + :display_name => "Rails Environment", + :description => "Specify the environment to use for Rails", + :default => "production" + +attribute "rails/max_pool_size", + :display_name => "Rails Max Pool Size", + :description => "Specify the MaxPoolSize in the Apache vhost", + :default => "4" + diff --git a/rails/recipes/default.rb b/rails/recipes/default.rb new file mode 100644 index 0000000..fcef404 --- /dev/null +++ b/rails/recipes/default.rb @@ -0,0 +1,31 @@ +# +# Cookbook Name:: rails +# Recipe:: default +# +# Copyright 2009, Opscode, 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 "ruby" + +%w{ rails actionmailer actionpack activerecord activesupport activeresource }.each do |rails_gem| + gem_package rails_gem do + if node[:rails][:version] + version node[:rails][:version] + action :install + else + action :install + end + end +end diff --git a/rails/templates/default/rails_app.conf.erb b/rails/templates/default/rails_app.conf.erb new file mode 100644 index 0000000..7081289 --- /dev/null +++ b/rails/templates/default/rails_app.conf.erb @@ -0,0 +1,30 @@ + + ServerName <%= @params[:server_name] %> + DocumentRoot <%= @params[:docroot] %> + + RailsBaseURI / + RailsMaxPoolSize <%= @node[:rails][:max_pool_size] %> + RailsPoolIdleTime 3600 + RailsEnv '<%= @node[:rails][:environment] %>' + + LogLevel info + ErrorLog <%= @node[:apache][:log_dir] %>/<%= @params[:name] %>_error.log + CustomLog <%= @node[:apache][:log_dir] %>/<%= @params[:name] %>_access.log combined + + ErrorDocument 404 /404.html + ErrorDocument 500 /500.html + + RewriteEngine On + + # Handle maintenance mode + RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f + RewriteCond %{SCRIPT_FILENAME} !maintenance.html + RewriteRule ^/(.*)$ /system/maintenance.html [L] + + > + Options FollowSymLinks + AllowOverride None + Order allow,deny + Allow from all + + diff --git a/rails_enterprise/README.rdoc b/rails_enterprise/README.rdoc new file mode 100644 index 0000000..f4c1f87 --- /dev/null +++ b/rails_enterprise/README.rdoc @@ -0,0 +1,24 @@ += DESCRIPTION: + +Installs Ruby on Rails under Ruby Enterprise Edition + += REQUIREMENTS: + +ruby_enterprise + += LICENSE and AUTHOR: + +Author:: Joshua Timberman () +Copyright:: 2009, Opscode, 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/rails_enterprise/metadata.json b/rails_enterprise/metadata.json new file mode 100644 index 0000000..4d6966a --- /dev/null +++ b/rails_enterprise/metadata.json @@ -0,0 +1,45 @@ +{ + "replacing": { + + }, + "dependencies": { + "ruby_enterprise": [ + + ] + }, + "groupings": { + + }, + "long_description": "= DESCRIPTION:\n\nInstalls Ruby on Rails under Ruby Enterprise Edition\n\n= REQUIREMENTS:\n\nruby_enterprise\n\n= LICENSE and AUTHOR:\n\nAuthor:: Joshua Timberman ()\nCopyright:: 2009, Opscode, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n", + "description": "Installs Ruby on Rails with Ruby Enterprise Edition", + "recommendations": { + + }, + "platforms": { + "ubuntu": [ + + ] + }, + "version": "0.1.0", + "maintainer": "Opscode, Inc.", + "name": "rails_enterprise", + "suggestions": { + + }, + "maintainer_email": "ops@opscode.com", + "recipes": { + "rails_enterprise": "" + }, + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "rails_enterprise": [ + + ] + }, + "license": "Apache 2.0" +} \ No newline at end of file diff --git a/rails_enterprise/metadata.rb b/rails_enterprise/metadata.rb new file mode 100644 index 0000000..818c83f --- /dev/null +++ b/rails_enterprise/metadata.rb @@ -0,0 +1,12 @@ +maintainer "Opscode, Inc." +maintainer_email "ops@opscode.com" +license "Apache 2.0" +description "Installs Ruby on Rails with Ruby Enterprise Edition" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.1" + +%w{ ruby_enterprise }.each do |cb| + depends cb +end + +supports "ubuntu" diff --git a/rails_enterprise/recipes/default.rb b/rails_enterprise/recipes/default.rb new file mode 100644 index 0000000..497232a --- /dev/null +++ b/rails_enterprise/recipes/default.rb @@ -0,0 +1,29 @@ +# +# Cookbook Name:: rails_enterprise +# Recipe:: default +# +# Author:: Joshua Timberman () +# +# Copyright 2009-2010, Opscode, 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 "ruby_enterprise" + +ree_gem "rake" do + version "0.8.7" +end + +ree_gem "rails" do + version "2.3.5" +end diff --git a/redmine/README.rdoc b/redmine/README.rdoc new file mode 100644 index 0000000..a6a9202 --- /dev/null +++ b/redmine/README.rdoc @@ -0,0 +1,58 @@ += DESCRIPTION: + +Installs Redmine, a Ruby on Rails ticket tracking and wiki tool. + += REQUIREMENTS: + +== Platform: + +Tested on Ubuntu 9.04, uses the Opscode Apache2 cookbook which is Ubuntu/Debian specific. + +== Cookbooks: + +Opscode cookbooks (http://github.com/opscode/cookbooks/tree/master) + +* git +* sqlite +* mysql +* rails +* passenger_apache2 +* apache2 + += ATTRIBUTES: + +* redmine[:dl_id] - download id on the rubyforge page, needs to be updated on new redmine releases. +* redmine[:version] - release version of redmine to use. +* redmine[:dir] - directory where redmine will be installed. +* redmine[:db][:type] - type of database to use, default is sqlite. mysql or postgresql can be used, but the recipe will need to modified, and the next three attributes adjusted. +* redmine[:db][:user] - database user to connect as, default is redmine. +* redmine[:db][:password] - password for the user, default is a random string generated with OpenSSL::Random.random_bytes. +* redmine[:db][:hostname] - hostname of database server, default is localhost. + += USAGE: + +Including this recipe in a run_list, role or on a node will install Redmine as a Passenger application under Apache2. + + include_recipe "redmine" + +You'll probably want to customize it to fit your environment, as a site-cookbook, especially if you want to use something besides sqlite as the database backend. The attributes file has database_master commented out as an example start on using a node search to determine a database host. See the Chef wiki regarding searches for more information. + + http://wiki.opscode.com/display/chef/Search+Indexes + += LICENSE and AUTHOR: + +Author:: Joshua Timberman () +Copyright:: 2009, Opscode, 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/redmine/attributes/redmine.rb b/redmine/attributes/redmine.rb new file mode 100644 index 0000000..7c4b773 --- /dev/null +++ b/redmine/attributes/redmine.rb @@ -0,0 +1,36 @@ +# Cookbook Name:: redmine +# Attributes:: redmine +# +# Copyright 2009, Opscode, 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. + +require 'openssl' + +pw = String.new + +while pw.length < 20 + pw << OpenSSL::Random.random_bytes(1).gsub(/\W/, '') +end + +#database_server = search(:node, "database_master:true").map {|n| n['fqdn']}.first + +set[:redmine][:dir] = "/srv/redmine-#{redmine[:version]}" + +set_unless[:redmine][:dl_id] = "56909" +set_unless[:redmine][:version] = "0.8.4" + +set_unless[:redmine][:db][:type] = "sqlite" +set_unless[:redmine][:db][:user] = "redmine" +set_unless[:redmine][:db][:password] = pw +set_unless[:redmine][:db][:hostname] = "localhost" diff --git a/redmine/metadata.json b/redmine/metadata.json new file mode 100644 index 0000000..75f8908 --- /dev/null +++ b/redmine/metadata.json @@ -0,0 +1,57 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs and configures redmine as a Rails app in passenger+apache2", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "redmine": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "debian": [ + + ] + }, + "version": "0.8.0", + "name": "redmine", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "redmine": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + "rails": [ + + ], + "mysql": [ + + ], + "passenger_apache2": [ + + ], + "sqlite": [ + + ], + "apache2": [ + + ] + } +} \ No newline at end of file diff --git a/redmine/metadata.rb b/redmine/metadata.rb new file mode 100644 index 0000000..e667d0e --- /dev/null +++ b/redmine/metadata.rb @@ -0,0 +1,13 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs and configures redmine as a Rails app in passenger+apache2" +version "0.9" + +%w{ apache2 rails passenger_apache2 mysql sqlite }.each do |cb| + depends cb +end + +%w{ ubuntu debian }.each do |os| + supports os +end diff --git a/redmine/recipes/default.rb b/redmine/recipes/default.rb new file mode 100644 index 0000000..de27b5d --- /dev/null +++ b/redmine/recipes/default.rb @@ -0,0 +1,74 @@ +# +# Author: Joshua Timberman +# Cookbook Name:: redmine +# Recipe:: default +# +# Copyright 2008-2009, Joshua Timberman +# +# 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 "rails" +include_recipe "apache2" +include_recipe "apache2::mod_rewrite" +include_recipe "passenger_apache2::mod_rails" + +bash "install_redmine" do + cwd "/srv" + user "root" + code <<-EOH + wget http://rubyforge.org/frs/download.php/#{node[:redmine][:dl_id]}/redmine-#{node[:redmine][:version]}.tar.gz + tar xf redmine-#{node[:redmine][:version]}.tar.gz + chown -R #{node[:apache][:user]} redmine-#{node[:redmine][:version]} + EOH + not_if { File.exists?("/srv/redmine-#{node[:redmine][:version]}/Rakefile") } +end + +link "/srv/redmine" do + to "/srv/redmine-#{node[:redmine][:version]}" +end + +case node[:redmine][:db][:type] +when "sqlite" + include_recipe "sqlite" + gem_package "sqlite3-ruby" + file "/srv/redmine-#{node[:redmine][:version]}/db/production.db" do + owner node[:apache][:user] + group node[:apache][:user] + mode "0644" + end +when "mysql" + include_recipe "mysql::client" +end + +template "/srv/redmine-#{node[:redmine][:version]}/config/database.yml" do + source "database.yml.erb" + owner "root" + group "root" + variables :database_server => node[:redmine][:db][:hostname] + mode "0664" +end + +execute "rake db:migrate RAILS_ENV='production'" do + user node[:apache][:user] + cwd "/srv/redmine-#{node[:redmine][:version]}" + not_if { File.exists?("/srv/redmine-#{node[:redmine][:version]}/db/schema.rb") } +end + +web_app "redmine" do + docroot "/srv/redmine/public" + template "redmine.conf.erb" + server_name "redmine.#{node[:domain]}" + server_aliases [ "redmine", node[:hostname] ] + rails_env "production" +end diff --git a/redmine/templates/default/database.yml.erb b/redmine/templates/default/database.yml.erb new file mode 100644 index 0000000..92cb2cd --- /dev/null +++ b/redmine/templates/default/database.yml.erb @@ -0,0 +1,22 @@ +# MySQL (default setup). Versions 4.1 and 5.0 are recommended. +# +# Get the fast C bindings: +# gem install mysql +# (on OS X: gem install mysql -- --include=/usr/local/lib) +# And be sure to use new-style password hashing: +# http://dev.mysql.com/doc/refman/5.0/en/old-client.html + +<% case @node[:redmine][:db][:type] -%> +<% when "mysql" -%> +production: + adapter: mysql + database: redmine + host: <%= @database_server %> + username: <%= @node[:redmine][:db][:user] %> + password: <%= @node[:redmine][:db][:password] %> + encoding: utf8 +<% when "sqlite" -%> +production: + adapter: sqlite3 + dbfile: db/production.db +<% end -%> diff --git a/redmine/templates/default/port_redmine.erb b/redmine/templates/default/port_redmine.erb new file mode 100644 index 0000000..609c59b --- /dev/null +++ b/redmine/templates/default/port_redmine.erb @@ -0,0 +1,2 @@ +# Redmine +-A FWR -p tcp -m tcp --dport 3000 -j ACCEPT \ No newline at end of file diff --git a/redmine/templates/default/redmine.conf.erb b/redmine/templates/default/redmine.conf.erb new file mode 100644 index 0000000..93ca5a4 --- /dev/null +++ b/redmine/templates/default/redmine.conf.erb @@ -0,0 +1,19 @@ + + ServerName <%= @params[:server_name] %> + ServerAlias <% @params[:server_aliases].each do |a| %><%= "#{a}" %> <% end %> + DocumentRoot <%= @params[:docroot] %> + + RailsBaseURI / + RailsEnv <%= @params[:rails_env] %> + + > + Options FollowSymLinks + AllowOverride None + Order allow,deny + Allow from all + + + LogLevel info + ErrorLog <%= @node[:apache][:log_dir] %>/<%= @params[:name] %>-error.log + CustomLog <%= @node[:apache][:log_dir] %>/<%= @params[:name] %>-access.log combined + diff --git a/redmine/templates/default/settings.yml.erb b/redmine/templates/default/settings.yml.erb new file mode 100644 index 0000000..5006445 --- /dev/null +++ b/redmine/templates/default/settings.yml.erb @@ -0,0 +1,142 @@ +# redMine - project management software +# Copyright (C) 2006-2007 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# DO NOT MODIFY THIS FILE !!! +# Settings can be defined through the application in Admin -> Settings + +app_title: + default: Redmine +app_subtitle: + default: Project management +welcome_text: + default: +login_required: + default: 0 +self_registration: + default: '2' +lost_password: + default: 1 +attachment_max_size: + format: int + default: 5120 +issues_export_limit: + format: int + default: 500 +activity_days_default: + format: int + default: 30 +per_page_options: + default: '25,50,100' +mail_from: + default: redmine@example.net +bcc_recipients: + default: 1 +plain_text_mail: + default: 0 +text_formatting: + default: textile +wiki_compression: + default: "" +default_language: + default: en +host_name: + default: localhost:3000 +protocol: + default: http +feeds_limit: + format: int + default: 15 +diff_max_lines_displayed: + format: int + default: 1500 +enabled_scm: + serialized: true + default: + - Subversion + - Darcs + - Mercurial + - Cvs + - Bazaar + - Git +autofetch_changesets: + default: 1 +sys_api_enabled: + default: 0 +commit_ref_keywords: + default: 'refs,references,IssueID' +commit_fix_keywords: + default: 'fixes,closes' +commit_fix_status_id: + format: int + default: 0 +commit_fix_done_ratio: + default: 100 +# autologin duration in days +# 0 means autologin is disabled +autologin: + format: int + default: 0 +# date format +date_format: + default: '' +time_format: + default: '' +user_format: + default: :firstname_lastname + format: symbol +cross_project_issue_relations: + default: 0 +notified_events: + serialized: true + default: + - issue_added + - issue_updated +mail_handler_api_enabled: + default: 0 +mail_handler_api_key: + default: +issue_list_default_columns: + serialized: true + default: + - tracker + - status + - priority + - subject + - assigned_to + - updated_on +display_subprojects_issues: + default: 1 +default_projects_public: + default: 1 +sequential_project_identifiers: + default: 0 +# encodings used to convert repository files content to UTF-8 +# multiple values accepted, comma separated +repositories_encodings: + default: '' +# encoding used to convert commit logs to UTF-8 +commit_logs_encoding: + default: 'UTF-8' +ui_theme: + default: '' +emails_footer: + default: |- + You have received this notification because you have either subscribed to it, or are involved in it. + To change your notification preferences, please click here: http://hostname/my/account +gravatar_enabled: + default: 0 diff --git a/redmine/templates/default/sv-redmine-log-run.erb b/redmine/templates/default/sv-redmine-log-run.erb new file mode 100644 index 0000000..a79a518 --- /dev/null +++ b/redmine/templates/default/sv-redmine-log-run.erb @@ -0,0 +1,2 @@ +#!/bin/sh +exec svlogd -tt ./main diff --git a/redmine/templates/default/sv-redmine-run.erb b/redmine/templates/default/sv-redmine-run.erb new file mode 100644 index 0000000..cab6f5c --- /dev/null +++ b/redmine/templates/default/sv-redmine-run.erb @@ -0,0 +1,3 @@ +#!/bin/sh +exec 2>&1 +exec chpst -u <%= @node[:apache_user] %> /srv/redmine/script/server -e production diff --git a/resolver/attributes/resolver.rb b/resolver/attributes/resolver.rb new file mode 100644 index 0000000..86dbae4 --- /dev/null +++ b/resolver/attributes/resolver.rb @@ -0,0 +1,2 @@ +set_unless[:resolver][:search] = domain +set_unless[:resolver][:nameservers] = [ "" ] diff --git a/resolver/metadata.json b/resolver/metadata.json new file mode 100644 index 0000000..a6daae4 --- /dev/null +++ b/resolver/metadata.json @@ -0,0 +1,94 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Configures \/etc\/resolv.conf", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "resolver": "" + }, + "suggestions": { + + }, + "platforms": { + "freebsd": [ + + ], + "ubuntu": [ + + ], + "openbsd": [ + + ], + "fedora": [ + + ], + "macosx": [ + + ], + "centos": [ + + ], + "redhat": [ + + ], + "debian": [ + + ] + }, + "version": "0.7.0", + "name": "resolver", + "conflicting": { + + }, + "attributes": { + "resolver\/nameservers": { + "default": [ + "" + ], + "type": "array", + "multiple_values": false, + "description": "Default nameservers", + "display_name": "Resolver Nameservers", + "recipes": [ + + ], + "required": false + }, + "resolver": { + "type": "hash", + "multiple_values": false, + "description": "Hash of Resolver attributes", + "display_name": "Resolver", + "recipes": [ + + ], + "required": false + }, + "resolver\/search": { + "default": "domain", + "type": "string", + "multiple_values": false, + "description": "Default domain to search", + "display_name": "Resolver Search", + "recipes": [ + + ], + "required": false + } + }, + "providing": { + "resolver": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/resolver/metadata.rb b/resolver/metadata.rb new file mode 100644 index 0000000..02fa146 --- /dev/null +++ b/resolver/metadata.rb @@ -0,0 +1,26 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Configures /etc/resolv.conf" +version "0.7" + +%w{ ubuntu debian fedora centos redhat freebsd openbsd macosx }.each do |os| + supports os +end + +attribute "resolver", + :display_name => "Resolver", + :description => "Hash of Resolver attributes", + :type => "hash" + +attribute "resolver/search", + :display_name => "Resolver Search", + :description => "Default domain to search", + :default => "domain" + +attribute "resolver/nameservers", + :display_name => "Resolver Nameservers", + :description => "Default nameservers", + :type => "array", + :default => [""] + diff --git a/resolver/recipes/default.rb b/resolver/recipes/default.rb new file mode 100644 index 0000000..7dd3932 --- /dev/null +++ b/resolver/recipes/default.rb @@ -0,0 +1,27 @@ +# +# Cookbook Name:: resolver +# Recipe:: default +# +# Copyright 2009, Opscode, 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. +# +# = Requires +# * node[:resolver][:nameservers] + +template "/etc/resolv.conf" do + source "resolv.conf.erb" + owner "root" + group "root" + mode 0644 +end diff --git a/resolver/templates/default/resolv.conf.erb b/resolver/templates/default/resolv.conf.erb new file mode 100644 index 0000000..35b536e --- /dev/null +++ b/resolver/templates/default/resolv.conf.erb @@ -0,0 +1,4 @@ +search <%= @node[:resolver][:search] %> +<% @node[:resolver][:nameservers].each do |nameserver| -%> +nameserver <%= nameserver %> +<% end -%> diff --git a/rsnapshot/attributes/rsnapshot.rb b/rsnapshot/attributes/rsnapshot.rb new file mode 100755 index 0000000..33c1b61 --- /dev/null +++ b/rsnapshot/attributes/rsnapshot.rb @@ -0,0 +1 @@ +rsnapshot Mash.new unless attribute?(:rsnapshot) diff --git a/rsnapshot/recipes/client.rb b/rsnapshot/recipes/client.rb new file mode 100755 index 0000000..a92fb25 --- /dev/null +++ b/rsnapshot/recipes/client.rb @@ -0,0 +1,2 @@ +package "rsnapshot" + diff --git a/rsnapshot/recipes/server.rb b/rsnapshot/recipes/server.rb new file mode 100755 index 0000000..6edce64 --- /dev/null +++ b/rsnapshot/recipes/server.rb @@ -0,0 +1,5 @@ +package "rsnapshot" + +template "/etc/rsnapshot.conf" do + source "rsnapshot.conf.erb" +end \ No newline at end of file diff --git a/rsnapshot/templates/default/rsnapshot.conf.erb b/rsnapshot/templates/default/rsnapshot.conf.erb new file mode 100755 index 0000000..892b675 --- /dev/null +++ b/rsnapshot/templates/default/rsnapshot.conf.erb @@ -0,0 +1,54 @@ +# Automatically generated by Chef. Local changes will be overwritten. +# +# This file requires tabs between elements +# +# Directories require a trailing slash: +# right: /home/ +# wrong: /home + +config_version 1.2 + +snapshot_root /u/backup/snapshots + +cmd_cp /bin/cp +cmd_rm /bin/rm +cmd_rsync /usr/bin/rsync +cmd_ssh /usr/bin/ssh +cmd_logger /usr/bin/logger + +######################################### +# BACKUP INTERVALS # +# Must be unique and in ascending order # +# i.e. hourly, daily, weekly, etc. # +######################################### + +interval hourly 6 +interval daily 7 +interval weekly 4 +#interval monthly 3 + +# Verbose level, 1 through 5. +# 1 Quiet Print fatal errors only +# 2 Default Print errors and warnings only +# 3 Verbose Show equivalent shell commands being executed +# 4 Extra Verbose Show extra verbose information +# 5 Debug mode Everything +# +verbose 2 + +# Same as "verbose" above, but controls the amount of data sent to the +# logfile, if one is being used. The default is 3. +# +loglevel 3 + +lockfile /var/run/rsnapshot.pid + +#rsync_short_args -a +#rsync_long_args --delete --numeric-ids --relative --delete-excluded + +# LOCALHOST +<% if @node[:rsnapshot][:backups] %> +<% @node[:rsnapshot][:backups].each do |source, config| %> +backup <%= source %> <%= config[:target] %> +<% end %> +<% end %> \ No newline at end of file diff --git a/rsync/metadata.json b/rsync/metadata.json new file mode 100644 index 0000000..208a073 --- /dev/null +++ b/rsync/metadata.json @@ -0,0 +1,52 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs rsync", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "rsync": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "fedora": [ + + ], + "centos": [ + + ], + "debian": [ + + ], + "redhat": [ + + ] + }, + "version": "0.7.0", + "name": "rsync", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "rsync": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/rsync/metadata.rb b/rsync/metadata.rb new file mode 100644 index 0000000..9d2c3f1 --- /dev/null +++ b/rsync/metadata.rb @@ -0,0 +1,9 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs rsync" +version "0.7" + +%w{ centos fedora redhat ubuntu debian }.each do |os| + supports os +end diff --git a/rsync/recipes/default.rb b/rsync/recipes/default.rb new file mode 100644 index 0000000..396a9ec --- /dev/null +++ b/rsync/recipes/default.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: rsync +# Recipe:: default +# +# Copyright 2008-2009, Opscode, 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 "rsync" diff --git a/rsyslog/README.rdoc b/rsyslog/README.rdoc new file mode 100644 index 0000000..ed8ee93 --- /dev/null +++ b/rsyslog/README.rdoc @@ -0,0 +1,55 @@ += DESCRIPTION: + +Installs rsyslog to replace sysklogd for client and/or server use. By default, server will be set up to log to files. + += REQUIREMENTS: + +== Platform: + +Tested on Ubuntu 8.10. + +== Cookbooks: + += ATTRIBUTES: + +* rsyslog[:log_dir] - specify the directory to store logs (applicable to server only) +* rsyslog[:server] - specify the remote rsyslog server. +* rsyslog[:protocol] - specify whether to use udp or tcp for remote log transmission. tcp is default. + += USAGE: + +To replace the sysklogd syslog service with rsyslog: + + include_recipe "rsyslog" + +To set up a client with a remote [r]syslog server: + + include_recipe "rsyslog::client" + +By default, this cookbook will use TCP so the server should be configured for TCP. This can be done easily with the server recipe: + + include_recipe "rsyslog::server" + +To switch to UDP, change the rsyslog[:protocol] attribute. Note this needs to be done on each client as well. + +Also, the server configuration will set up log_dir for each client, by date. Structure: + + <%= @log_dir %>/YEAR/MONTH/DAY/HOSTNAME/"logfile" + += LICENSE and AUTHOR: + +Author:: Joshua Timberman () + +Copyright:: 2009, Opscode, 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/rsyslog/attributes/rsyslog.rb b/rsyslog/attributes/rsyslog.rb new file mode 100644 index 0000000..c79897c --- /dev/null +++ b/rsyslog/attributes/rsyslog.rb @@ -0,0 +1,22 @@ +# +# Cookbook Name:: rsyslog +# Attributes:: rsyslog +# +# Copyright 2009, Opscode, 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. +# + +set_unless[:rsyslog][:log_dir] = "/srv/rsyslog" +set_unless[:rsyslog][:server] = false +set_unless[:rsyslog][:protocol] = "tcp" diff --git a/rsyslog/files/default/rsyslog.default b/rsyslog/files/default/rsyslog.default new file mode 100644 index 0000000..87449b3 --- /dev/null +++ b/rsyslog/files/default/rsyslog.default @@ -0,0 +1,9 @@ +# Generated by Chef +# +# Use v3 native mode, rather than compatibility mode by specifying -c3 +# here. Compatibility mode for older versions is not recommended as +# custom configuration may get messy. +# +# See rsyslogd(8) for more details + +RSYSLOGD_OPTIONS="-c3" diff --git a/rsyslog/files/ubuntu-9.10/rsyslog.default b/rsyslog/files/ubuntu-9.10/rsyslog.default new file mode 100644 index 0000000..2e4599f --- /dev/null +++ b/rsyslog/files/ubuntu-9.10/rsyslog.default @@ -0,0 +1,9 @@ +# Generated by Chef +# +# Options for rsyslogd +# -m 0 disables 'MARK' messages (deprecated, only used in compat mode < 3) +# -r enables logging from remote machines (deprecated, only used in compat mode < 3) +# -x disables DNS lookups on messages received with -r +# -c compatibility mode +# See rsyslogd(8) for more details +RSYSLOGD_OPTIONS="-c4" diff --git a/rsyslog/metadata.json b/rsyslog/metadata.json new file mode 100644 index 0000000..ddbc671 --- /dev/null +++ b/rsyslog/metadata.json @@ -0,0 +1,93 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs and configures rsyslog", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "rsyslog::server": "Sets up an rsyslog server", + "rsyslog::client": "Sets up a client to log to a remote rsyslog server", + "rsyslog": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + ">= 8.10" + ], + "debian": [ + ">= 5.0" + ] + }, + "version": "0.7.0", + "name": "rsyslog", + "conflicting": { + + }, + "attributes": { + "rsyslog\/protocol": { + "default": "tcp", + "type": "string", + "multiple_values": false, + "description": "Set which network protocol to use for rsyslog", + "display_name": "Rsyslog Protocol", + "recipes": [ + + ], + "required": false + }, + "rsyslog": { + "type": "hash", + "multiple_values": false, + "description": "Hash of Rsyslog attributes", + "display_name": "Rsyslog", + "recipes": [ + + ], + "required": false + }, + "rsyslog\/log_dir": { + "default": "\/srv\/rsyslog", + "type": "string", + "multiple_values": false, + "description": "Filesystem location of logs from clients", + "display_name": "Rsyslog Log Directory", + "recipes": [ + + ], + "required": false + }, + "rsyslog\/server": { + "default": "false", + "type": "string", + "multiple_values": false, + "description": "Is this node an rsyslog server?", + "display_name": "Rsyslog Server?", + "recipes": [ + + ], + "required": false + } + }, + "providing": { + "rsyslog::server": [ + + ], + "rsyslog": [ + + ], + "rsyslog::client": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "= DESCRIPTION:\n\nInstalls rsyslog to replace sysklogd for client and\/or server use. By default, server will be set up to log to files.\n\n= REQUIREMENTS:\n\n== Platform:\n\nTested on Ubuntu 8.10.\n\n== Cookbooks:\n\n= ATTRIBUTES: \n\n* rsyslog[:log_dir] - specify the directory to store logs (applicable to server only)\n* rsyslog[:server] - specify the remote rsyslog server.\n* rsyslog[:protocol] - specify whether to use udp or tcp for remote log transmission. tcp is default.\n\n= USAGE:\n\nTo replace the sysklogd syslog service with rsyslog:\n\n include_recipe \"rsyslog\"\n \nTo set up a client with a remote [r]syslog server:\n\n include_recipe \"rsyslog::client\"\n \nBy default, this cookbook will use TCP so the server should be configured for TCP. This can be done easily with the server recipe:\n\n include_recipe \"rsyslog::server\"\n\nTo switch to UDP, change the rsyslog[:protocol] attribute. Note this needs to be done on each client as well.\n\nAlso, the server configuration will set up log_dir for each client, by date. Structure:\n\n <%= @log_dir %>\/YEAR\/MONTH\/DAY\/HOSTNAME\/\"logfile\"\n\n= LICENSE and AUTHOR:\n \nAuthor:: Joshua Timberman ()\n\nCopyright:: 2009, Opscode, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http:\/\/www.apache.org\/licenses\/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/rsyslog/metadata.rb b/rsyslog/metadata.rb new file mode 100644 index 0000000..50b4bbd --- /dev/null +++ b/rsyslog/metadata.rb @@ -0,0 +1,32 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs and configures rsyslog" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.7" +recipe "rsyslog::client", "Sets up a client to log to a remote rsyslog server" +recipe "rsyslog::server", "Sets up an rsyslog server" + +supports "ubuntu", ">= 8.10" +supports "debian", ">= 5.0" + +attribute "rsyslog", + :display_name => "Rsyslog", + :description => "Hash of Rsyslog attributes", + :type => "hash" + +attribute "rsyslog/log_dir", + :display_name => "Rsyslog Log Directory", + :description => "Filesystem location of logs from clients", + :default => "/srv/rsyslog" + +attribute "rsyslog/server", + :display_name => "Rsyslog Server?", + :description => "Is this node an rsyslog server?", + :default => "false" + +attribute "rsyslog/protocol", + :display_name => "Rsyslog Protocol", + :description => "Set which network protocol to use for rsyslog", + :default => "tcp" + diff --git a/rsyslog/recipes/client.rb b/rsyslog/recipes/client.rb new file mode 100644 index 0000000..4fbf58b --- /dev/null +++ b/rsyslog/recipes/client.rb @@ -0,0 +1,40 @@ +# +# Cookbook Name:: rsyslog +# Recipe:: client +# +# Copyright 2009, Opscode, 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 "rsyslog" + +rsyslog_server = node[:rsyslog][:server] ? node[:rsyslog][:server] : search(:node, "rsyslog_server:true").map { |n| n["fqdn"] }.first + +unless node[:rsyslog][:server] + template "/etc/rsyslog.d/remote.conf" do + source "remote.conf.erb" + backup false + variables :server => rsyslog_server, :protocol => node[:rsyslog][:protocol] + owner "root" + group "root" + mode 0644 + notifies :restart, resources(:service => "rsyslog"), :delayed + end + + file "/etc/rsyslog.d/server.conf" do + action :delete + notifies :reload, resources(:service => "rsyslog"), :delayed + only_if do File.exists?("/etc/rsyslog.d/server.conf") end + end +end diff --git a/rsyslog/recipes/default.rb b/rsyslog/recipes/default.rb new file mode 100644 index 0000000..cbf9b5b --- /dev/null +++ b/rsyslog/recipes/default.rb @@ -0,0 +1,61 @@ +# +# Cookbook Name:: rsyslog +# Recipe:: default +# +# Copyright 2009, Opscode, 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 "rsyslog" do + action :install +end + +service "rsyslog" do + supports :restart => true, :reload => true + action [:enable, :start] +end + +remote_file "/etc/default/rsyslog" do + source "rsyslog.default" + owner "root" + group "root" + mode 0644 +end + +directory "/etc/rsyslog.d" do + owner "root" + group "root" + mode 0755 +end + +template "/etc/rsyslog.conf" do + source "rsyslog.conf.erb" + owner "root" + group "root" + mode 0644 + notifies :restart, resources(:service => "rsyslog"), :delayed +end + +case node[:platform] +when "ubuntu" + if node[:platform_version] >= "9.10" + template "/etc/rsyslog.d/50-default.conf" do + source "50-default.conf.erb" + backup false + owner "root" + group "root" + mode 0644 + end + end +end diff --git a/rsyslog/recipes/server.rb b/rsyslog/recipes/server.rb new file mode 100644 index 0000000..b03aaa8 --- /dev/null +++ b/rsyslog/recipes/server.rb @@ -0,0 +1,51 @@ +# +# Cookbook Name:: rsyslog +# Recipe:: server +# +# Copyright 2009, Opscode, 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 "rsyslog" + +directory node[:rsyslog][:log_dir] do + owner "root" + group "root" + mode 0755 +end + +template "/etc/rsyslog.d/server.conf" do + source "server.conf.erb" + backup false + variables :log_dir => node[:rsyslog][:log_dir], :protocol => node[:rsyslog][:protocol] + owner "root" + group "root" + mode 0644 + notifies :restart, resources(:service => "rsyslog"), :delayed +end + +file "/etc/rsyslog.d/remote.conf" do + action :delete + backup false + notifies :reload, resources(:service => "rsyslog"), :delayed + only_if do File.exists?("/etc/rsyslog.d/remote.conf") end +end + +template "/etc/cron.d/rsyslog_gz" do + source "rsyslog_gz.erb" + owner "root" + group "root" + mode 0644 + variables :log_dir => node[:rsyslog][:log_dir] +end diff --git a/rsyslog/templates/default/remote.conf.erb b/rsyslog/templates/default/remote.conf.erb new file mode 100644 index 0000000..02068f4 --- /dev/null +++ b/rsyslog/templates/default/remote.conf.erb @@ -0,0 +1,6 @@ +<% case @protocol -%> +<% when "tcp" -%> +*.* @@<%= @server %> +<% when "udp" -%> +*.* @<%= @server %> +<% end -%> diff --git a/rsyslog/templates/default/rsyslog.conf.erb b/rsyslog/templates/default/rsyslog.conf.erb new file mode 100644 index 0000000..4af21e7 --- /dev/null +++ b/rsyslog/templates/default/rsyslog.conf.erb @@ -0,0 +1,115 @@ +# /etc/rsyslog.conf Configuration file for rsyslog v3. +# +# For more information see +# /usr/share/doc/rsyslog-doc/html/rsyslog_conf.html + + +################# +#### MODULES #### +################# + +$ModLoad imuxsock # provides support for local system logging +$ModLoad imklog # provides kernel logging support (previously done by rklogd) +#$ModLoad immark # provides --MARK-- message capability + +# provides UDP syslog reception +#$ModLoad imudp +#$UDPServerRun 514 + +# provides TCP syslog reception +#$ModLoad imtcp +#$InputTCPServerRun 514 + + +########################### +#### GLOBAL DIRECTIVES #### +########################### + +# +# Use default timestamp format. +# To enable high precision timestamps, comment out the following line. +# +$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat + +# +# Set the default permissions for all log files. +# +$FileOwner root +$FileGroup adm +$FileCreateMode 0640 + +# +# Include all config files in /etc/rsyslog.d/ +# +$IncludeConfig /etc/rsyslog.d/*.conf + + +############### +#### RULES #### +############### + +# +# First some standard log files. Log by facility. +# +auth,authpriv.* /var/log/auth.log +*.*;auth,authpriv.none -/var/log/syslog +#cron.* /var/log/cron.log +daemon.* -/var/log/daemon.log +kern.* -/var/log/kern.log +lpr.* -/var/log/lpr.log +mail.* -/var/log/mail.log +user.* -/var/log/user.log + +# +# Logging for the mail system. Split it up so that +# it is easy to write scripts to parse these files. +# +mail.info -/var/log/mail.info +mail.warn -/var/log/mail.warn +mail.err /var/log/mail.err + +# +# Logging for INN news system. +# +news.crit /var/log/news/news.crit +news.err /var/log/news/news.err +news.notice -/var/log/news/news.notice + +# +# Some "catch-all" log files. +# +*.=debug;\ + auth,authpriv.none;\ + news.none;mail.none -/var/log/debug +*.=info;*.=notice;*.=warn;\ + auth,authpriv.none;\ + cron,daemon.none;\ + mail,news.none -/var/log/messages + +# +# Emergencies are sent to everybody logged in. +# +*.emerg * + +# +# I like to have messages displayed on the console, but only on a virtual +# console I usually leave idle. +# +#daemon,mail.*;\ +# news.=crit;news.=err;news.=notice;\ +# *.=debug;*.=info;\ +# *.=notice;*.=warn /dev/tty8 + +# The named pipe /dev/xconsole is for the `xconsole' utility. To use it, +# you must invoke `xconsole' with the `-file' option: +# +# $ xconsole -file /dev/xconsole [...] +# +# NOTE: adjust the list below, or you'll go crazy if you have a reasonably +# busy site.. +# +daemon.*;mail.*;\ + news.err;\ + *.=debug;*.=info;\ + *.=notice;*.=warn |/dev/xconsole + diff --git a/rsyslog/templates/default/rsyslog_gz.erb b/rsyslog/templates/default/rsyslog_gz.erb new file mode 100644 index 0000000..650b8ea --- /dev/null +++ b/rsyslog/templates/default/rsyslog_gz.erb @@ -0,0 +1,2 @@ +# Chef Name: rsyslog_gz +0 4 * * * find <%= @log_dir %>/$(date +\%Y) -type f -mtime +1 -exec gzip -q {} \; diff --git a/rsyslog/templates/default/server.conf.erb b/rsyslog/templates/default/server.conf.erb new file mode 100644 index 0000000..1fef5e0 --- /dev/null +++ b/rsyslog/templates/default/server.conf.erb @@ -0,0 +1,58 @@ +# Generated by Chef. +# Local modifications will be overwritten. +<% case @protocol -%> +<% when "tcp" -%> +$ModLoad imtcp +$InputTCPServerRun 514 +<% when "udp" -%> +$ModLoad imudp +$UDPServerRun 514 +<% end -%> + +$DirGroup root +$DirCreateMode 0755 +$FileGroup root + +$template PerHostAuth,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/auth.log" +$template PerHostCron,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/cron.log" +$template PerHostSyslog,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/syslog" +$template PerHostDaemon,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/daemon.log" +$template PerHostKern,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/kern.log" +$template PerHostLpr,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/lpr.log" +$template PerHostUser,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/user.log" +$template PerHostMail,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/mail.log" +$template PerHostMailInfo,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/mail.info" +$template PerHostMailWarn,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/mail.warn" +$template PerHostMailErr,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/mail.err" +$template PerHostNewsCrit,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/news.crit" +$template PerHostNewsErr,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/news.err" +$template PerHostNewsNotice,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/news.notice" +$template PerHostDebug,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/debug" +$template PerHostMessages,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/messages" + +auth,authpriv.* ?PerHostAuth +*.*;auth,authpriv.none -?PerHostSyslog +cron.* ?PerHostCron +daemon.* -?PerHostDaemon +kern.* -?PerHostKern +lpr.* -?PerHostLpr +mail.* -?PerHostMail +user.* -?PerHostUser + +mail.info -?PerHostMailInfo +mail.warn ?PerHostMailWarn +mail.err ?PerHostMailErr + +news.crit ?PerHostNewsCrit +news.err ?PerHostNewsErr +news.notice -?PerHostNewsNotice + +*.=debug;\ + auth,authpriv.none;\ + news.none;mail.none -?PerHostDebug + +*.=info;*.=notice;*.=warn;\ + auth,authpriv.none;\ + cron,daemon.none;\ + mail,news.none -?PerHostMessages + diff --git a/rsyslog/templates/ubuntu-9.10/50-default.conf.erb b/rsyslog/templates/ubuntu-9.10/50-default.conf.erb new file mode 100644 index 0000000..b45f419 --- /dev/null +++ b/rsyslog/templates/ubuntu-9.10/50-default.conf.erb @@ -0,0 +1,69 @@ +# Default rules for rsyslog. +# +# For more information see rsyslog.conf(5) and /etc/rsyslog.conf + +# +# First some standard log files. Log by facility. +# +auth,authpriv.* /var/log/auth.log +*.*;auth,authpriv.none -/var/log/syslog +#cron.* /var/log/cron.log +daemon.* -/var/log/daemon.log +kern.* -/var/log/kern.log +lpr.* -/var/log/lpr.log +mail.* -/var/log/mail.log +user.* -/var/log/user.log + +# +# Logging for the mail system. Split it up so that +# it is easy to write scripts to parse these files. +# +mail.info -/var/log/mail.info +mail.warn -/var/log/mail.warn +mail.err /var/log/mail.err + +# +# Logging for INN news system. +# +news.crit /var/log/news/news.crit +news.err /var/log/news/news.err +news.notice -/var/log/news/news.notice + +# +# Some "catch-all" log files. +# +*.=debug;\ + auth,authpriv.none;\ + news.none;mail.none -/var/log/debug +*.=info;*.=notice;*.=warn;\ + auth,authpriv.none;\ + cron,daemon.none;\ + mail,news.none -/var/log/messages + +# +# Emergencies are sent to everybody logged in. +# +*.emerg * + +# +# I like to have messages displayed on the console, but only on a virtual +# console I usually leave idle. +# +#daemon,mail.*;\ +# news.=crit;news.=err;news.=notice;\ +# *.=debug;*.=info;\ +# *.=notice;*.=warn /dev/tty8 + +# The named pipe /dev/xconsole is for the `xconsole' utility. To use it, +# you must invoke `xconsole' with the `-file' option: +# +# $ xconsole -file /dev/xconsole [...] +# +# NOTE: adjust the list below, or you'll go crazy if you have a reasonably +# busy site.. +# +daemon.*;mail.*;\ + news.err;\ + *.=debug;*.=info;\ + *.=notice;*.=warn |/dev/xconsole + diff --git a/rsyslog/templates/ubuntu-9.10/remote.conf.erb b/rsyslog/templates/ubuntu-9.10/remote.conf.erb new file mode 100644 index 0000000..02068f4 --- /dev/null +++ b/rsyslog/templates/ubuntu-9.10/remote.conf.erb @@ -0,0 +1,6 @@ +<% case @protocol -%> +<% when "tcp" -%> +*.* @@<%= @server %> +<% when "udp" -%> +*.* @<%= @server %> +<% end -%> diff --git a/rsyslog/templates/ubuntu-9.10/server.conf.erb b/rsyslog/templates/ubuntu-9.10/server.conf.erb new file mode 100644 index 0000000..1fef5e0 --- /dev/null +++ b/rsyslog/templates/ubuntu-9.10/server.conf.erb @@ -0,0 +1,58 @@ +# Generated by Chef. +# Local modifications will be overwritten. +<% case @protocol -%> +<% when "tcp" -%> +$ModLoad imtcp +$InputTCPServerRun 514 +<% when "udp" -%> +$ModLoad imudp +$UDPServerRun 514 +<% end -%> + +$DirGroup root +$DirCreateMode 0755 +$FileGroup root + +$template PerHostAuth,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/auth.log" +$template PerHostCron,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/cron.log" +$template PerHostSyslog,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/syslog" +$template PerHostDaemon,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/daemon.log" +$template PerHostKern,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/kern.log" +$template PerHostLpr,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/lpr.log" +$template PerHostUser,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/user.log" +$template PerHostMail,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/mail.log" +$template PerHostMailInfo,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/mail.info" +$template PerHostMailWarn,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/mail.warn" +$template PerHostMailErr,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/mail.err" +$template PerHostNewsCrit,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/news.crit" +$template PerHostNewsErr,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/news.err" +$template PerHostNewsNotice,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/news.notice" +$template PerHostDebug,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/debug" +$template PerHostMessages,"<%= @log_dir %>/%$YEAR%/%$MONTH%/%$DAY%/%HOSTNAME%/messages" + +auth,authpriv.* ?PerHostAuth +*.*;auth,authpriv.none -?PerHostSyslog +cron.* ?PerHostCron +daemon.* -?PerHostDaemon +kern.* -?PerHostKern +lpr.* -?PerHostLpr +mail.* -?PerHostMail +user.* -?PerHostUser + +mail.info -?PerHostMailInfo +mail.warn ?PerHostMailWarn +mail.err ?PerHostMailErr + +news.crit ?PerHostNewsCrit +news.err ?PerHostNewsErr +news.notice -?PerHostNewsNotice + +*.=debug;\ + auth,authpriv.none;\ + news.none;mail.none -?PerHostDebug + +*.=info;*.=notice;*.=warn;\ + auth,authpriv.none;\ + cron,daemon.none;\ + mail,news.none -?PerHostMessages + diff --git a/ruby-shadow/attributes/ruby-shadow.rb b/ruby-shadow/attributes/ruby-shadow.rb new file mode 100644 index 0000000..ff345b7 --- /dev/null +++ b/ruby-shadow/attributes/ruby-shadow.rb @@ -0,0 +1 @@ +set_unless[:ruby_shadow][:site_ruby] = "/usr/local/lib/ruby/site_ruby/1.8" \ No newline at end of file diff --git a/ruby-shadow/files/default/shadow-1.4.1/HISTORY b/ruby-shadow/files/default/shadow-1.4.1/HISTORY new file mode 100755 index 0000000..cd7d87e --- /dev/null +++ b/ruby-shadow/files/default/shadow-1.4.1/HISTORY @@ -0,0 +1,34 @@ +[1999/08/18] +* version 1.4.1 + - extconf.rb supports glibc2(libc6). + +[1999/03/09] +* version 1.4 + - require ruby-1.3 or later version. + - sShadowPasswd,mShadow,eFileLock was renamed. + - FileLock class is inner class of Shadow Module. + - lock,unlock was changed. + - lock? method was added. + - getspent,fgetspent doesn't raise EOFError + - class hierarchy was changed. + Shadow Module + + Passwd Module + + Entry Structure + + Group Module (not implemented yet) + + Entry Structure (not implemented yet) + + FileLock Class + +[1998/12/17] +* version 1.3 + - require ruby-1.1d0 or later version. + +[1998/10/31] +* version 1.2 + - only some bug fix. + +[1998/08/31] +* version 1.1 + - structure Shadow::ShadowPasswd is added. + +[1998/07/15] +* version 1.0 released. diff --git a/ruby-shadow/files/default/shadow-1.4.1/MANIFEST b/ruby-shadow/files/default/shadow-1.4.1/MANIFEST new file mode 100755 index 0000000..4d28f0b --- /dev/null +++ b/ruby-shadow/files/default/shadow-1.4.1/MANIFEST @@ -0,0 +1,7 @@ +HISTORY +MANIFEST +README +README.euc +depend +extconf.rb +shadow.c diff --git a/ruby-shadow/files/default/shadow-1.4.1/README b/ruby-shadow/files/default/shadow-1.4.1/README new file mode 100755 index 0000000..f6a0d32 --- /dev/null +++ b/ruby-shadow/files/default/shadow-1.4.1/README @@ -0,0 +1,79 @@ +Shadow Password module + +Copyright (C) 1998-1999 Takaaki Tateishi +Modified at: <1999/8/19 06:47:14 by ttate> +License: Free for any use with your own risk! + + +1. What's this + +This is the module which used when you access +linux shadow password files. + + +2. install + +ruby extconf.rb +make +(make install) + +* Note: + version 1.3 require the ruby-1.3 or later version. + +3. Shadow::Passwd module's methods + +getspent +getspnam(name) +setspent +endspent +fgetspent(file) +sgetspent(str) +putspent(entry,file) +lckpwdf,lock +ulckpwdf,unlock +lock? + +4. Structure + +Shadow::Passwd::Entry (Struct::PasswdEntry) + sp_namp - pointer to null-terminated user name. + sp_pwdp - pointer to null-terminated password. + sp_lstchg - days since Jan 1, 1970 password was last + changed. + sp_min - days before which password may not be changed. + sp_max - days after which password must be changed. + sp_warn - days before password is to expire that user is + warned of pending password expiration. + sp_inact - days after password expires that account is + considered inactive and disabled. + sp_expire - days since Jan 1, 1970 when account will be + + +5. Description + +getspent, getspname, fgetspent and sgetspent each return +a structure Shadow::Passwd::Entry. getspent returns the +next entry from the file, and fgetspent returns the next +entry from the given stream. sgetspent returns a structure +Shadow::Passwd::Entry using the provided string as input. +getspnam searches from the current position in the file for +an entry matching name. +if you get EOF from each operation, you will get nil. + +setspent and endspent may be used to begin and end, respe- +ctively, access to the shadow password file. + +lckpwdf(lock) and ulckpwdf(unlock) methods should be used +to insure exclusive access to the /etc/shadow file. +when either method fail, Exception Shadow::FileLock is raised. +if you use lock as the iterator, unlock is automatically called +when you exit the iterator block. + +6. Reference + +* man shadow +* /usr/include/shadow.h + + + + ttate@jaist.ac.jp diff --git a/ruby-shadow/files/default/shadow-1.4.1/README.euc b/ruby-shadow/files/default/shadow-1.4.1/README.euc new file mode 100755 index 0000000..075a74b --- /dev/null +++ b/ruby-shadow/files/default/shadow-1.4.1/README.euc @@ -0,0 +1,80 @@ +Shadow Password module + +Copyright (C) 1998-1999 Takaaki Tateishi +Modified at: <1999/8/19 06:48:01 by ttate> +License: Free for any use with your own risk! + + +1. ³µÍ× + +linux¤Ë¤ª¤¤¤Æshadow password¥Õ¥¡¥¤¥ë¤ò°·¤¦¤¿¤á +¤Î¥â¥¸¥å¡¼¥ë¡£ + + +2. ¥¤¥ó¥¹¥È¡¼¥ë + +ruby extconf.rb +make +make install + +* Ãí°Õ + shadow-1.3¤Ç¤Ïruby-1.3¤â¤·¤¯¤Ï¤½¤ì°Ê¹ß¤Î¥Ð¡¼¥¸¥ç¥ó + ¤¬É¬ÍפǤ¹¡£ + +3. Shadow::Passwd¥â¥¸¥å¡¼¥ë¤Î¥á¥½¥Ã¥Éã + +getspent +getspnam(name) +setspent +endspent +fgetspent(file) +sgetspent(str) +putspent(entry,file) +lckpwdf,lock +ulckpwdf,unlock +lock? + +4. Structure + +Shadow::Passwd::Entry (Struct::PasswdEntry) + sp_namp - pointer to null-terminated user name. + sp_pwdp - pointer to null-terminated password. + sp_lstchg - days since Jan 1, 1970 password was last + changed. + sp_min - days before which password may not be changed. + sp_max - days after which password must be changed. + sp_warn - days before password is to expire that user is + warned of pending password expiration. + sp_inact - days after password expires that account is + considered inactive and disabled. + sp_expire - days since Jan 1, 1970 when account will be + + +5. ÀâÌÀ + +getspent, getspname, fgetspent, sgetspent¤ÏShadow::Passwd::Entry +¥¹¥È¥é¥¯¥Á¥ã¤òÊÖ¤·¤Þ¤¹¡£getspent ¤Ï¥Õ¥¡¥¤¥ë¤«¤é¼¡¤Î¥Ñ¥¹¥ï +¡¼¥É¥¨¥ó¥È¥ê¤òÊÖ¤·¡¢fgetspent ¤ÏÍ¿¤¨¤é¤ì¤¿IO¤«¤é¼¡¤Î¥¨¥ó¥È +¥ê¤òÊÖ¤·¤Þ¤¹¡£sgetspent¤ÏÍ¿¤¨¤é¤ì¤¿Ê¸»úÎ󤫤éShadow::Passwd::Entry +¥¹¥È¥é¥¯¥Á¥ã¤òÊÖ¤·¤Þ¤¹¡£getspnam¤Ï¥æ¡¼¥¶Ì¾¤òÍ¿¤¨¤ë¤È/etc/shadow +¤«¤é¤½¤Î¥æ¡¼¥¶¤ÎShadow::Passwd::Entry¥¹¥È¥é¥¯¥Á¥ã¤òÊÖ¤·¤Þ¤¹¡£ +¥Õ¥¡¥¤¥ë¤Î½ªÃ¼¤Ë㤹¤ë¤Ènil¤ÎÃͤòÊÖ¤·¤Þ¤¹¡£ + +setspent,endspent¤Ï¤½¤ì¤¾¤ì¡¢¥Õ¥¡¥¤¥ë¤Ø¤Î¥¢¥¯¥»¥¹¤Î¤Ï¤¸¤á¤È +¤ª¤ï¤ê¤Ë»È¤¤¤Þ¤¹¡£ + +lckpwdf(lock),ulckpwdf(unlock)¤Ï/etc/shadow¤Ø¤ÎÇÓ¾Ū¥¢¥¯¥»¥¹ +¤ò¼Â¸½¤¹¤ë¤¿¤á¤Ë¤¢¤ê¤Þ¤¹¡£ +lock¤Ë¼ºÇÔ¤¹¤ë¤ÈShadow::FileLock¤È¤¤¤¦Îã³°¤òȯÀ¸¤µ¤»¤Þ¤¹¡£ +lock¤ò¥¤¥Æ¥ì¡¼¥¿¤È¤·¤Æ»È¤¦¤³¤È¤Ë¤è¤Ã¤Æ¡¢¥¤¥Æ¥ì¡¼¥¿¥Ö¥í¥Ã¥¯¤òÈ´¤±¤ë +¤È¤­¤Ë¼«Æ°Åª¤Ëunlock¤ò¹Ô¤Ê¤¤¤Þ¤¹¡£ + + +6. »²¹Í + +* man shadow +* /usr/include/shadow.h + + + + ttate@jaist.ac.jp diff --git a/ruby-shadow/files/default/shadow-1.4.1/depend b/ruby-shadow/files/default/shadow-1.4.1/depend new file mode 100755 index 0000000..f5811a2 --- /dev/null +++ b/ruby-shadow/files/default/shadow-1.4.1/depend @@ -0,0 +1 @@ +shadow.o : shadow.c $(hdrdir)/ruby.h $(hdrdir)/rubyio.h diff --git a/ruby-shadow/files/default/shadow-1.4.1/extconf.rb b/ruby-shadow/files/default/shadow-1.4.1/extconf.rb new file mode 100755 index 0000000..6f300e5 --- /dev/null +++ b/ruby-shadow/files/default/shadow-1.4.1/extconf.rb @@ -0,0 +1,26 @@ +# -*- ruby -*- +# extconf.rb +# +# Modified at: <1999/8/19 06:38:55 by ttate> +# + +require 'mkmf' + +$CFLAGS = "" +$LDFLAGS = "-lshadow" + +if( ! (ok = have_library("shadow","getspent")) ) + $LDFLAGS = "" + ok = have_func("getspent") +end + +ok &= have_func("sgetspent") +ok &= have_func("fgetspent") +ok &= have_func("setspent") +ok &= have_func("endspent") +ok &= have_func("lckpwdf") +ok &= have_func("ulckpwdf") + +if ok + create_makefile("shadow") +end diff --git a/ruby-shadow/files/default/shadow-1.4.1/shadow.c b/ruby-shadow/files/default/shadow-1.4.1/shadow.c new file mode 100755 index 0000000..8a52c83 --- /dev/null +++ b/ruby-shadow/files/default/shadow-1.4.1/shadow.c @@ -0,0 +1,281 @@ +/* + * shadow.c + * + * Ruby extention module for using Linux shadow password. + * + * Copyright (C) 1998-1999 by Takaaki.Tateishi(ttate@jaist.ac.jp) + * License: Free for any use with your own risk! + * Modified at: <1999/8/19 06:48:18 by ttate> + */ + +#include +#include "ruby.h" +#include "rubyio.h" + +static VALUE rb_mShadow; +static VALUE rb_mPasswd; +static VALUE rb_sPasswdEntry; +static VALUE rb_mGroup; +static VALUE rb_sGroupEntry; +static VALUE rb_eFileLock; + + +static VALUE +rb_shadow_setspent(VALUE self) +{ + setspent(); + return Qnil; +}; + + +static VALUE +rb_shadow_endspent(VALUE self) +{ + endspent(); + return Qnil; +}; + + +static VALUE +rb_shadow_sgetspent(VALUE self, VALUE str) +{ + struct spwd *entry; + VALUE result; + + if( TYPE(str) != T_STRING ) + rb_raise(rb_eException,"argument must be a string."); + + entry = sgetspent(STR2CSTR(str)); + + if( entry == NULL ) + return Qnil; + + result = rb_struct_new(rb_sPasswdEntry, + rb_tainted_str_new2(entry->sp_namp), + rb_tainted_str_new2(entry->sp_pwdp), + INT2FIX(entry->sp_lstchg), + INT2FIX(entry->sp_min), + INT2FIX(entry->sp_max), + INT2FIX(entry->sp_warn), + INT2FIX(entry->sp_inact), + INT2FIX(entry->sp_expire), + INT2FIX(entry->sp_flag), + 0); + free(entry); + return result; +}; + +static VALUE +rb_shadow_fgetspent(VALUE self, VALUE file) +{ + struct spwd *entry; + VALUE result; + + if( TYPE(file) != T_FILE ) + rb_raise(rb_eTypeError,"argument must be a File."); + + entry = fgetspent((RFILE(file)->fptr)->f); + + if( entry == NULL ) + return Qnil; + + result = rb_struct_new(rb_sPasswdEntry, + rb_tainted_str_new2(entry->sp_namp), + rb_tainted_str_new2(entry->sp_pwdp), + INT2FIX(entry->sp_lstchg), + INT2FIX(entry->sp_min), + INT2FIX(entry->sp_max), + INT2FIX(entry->sp_warn), + INT2FIX(entry->sp_inact), + INT2FIX(entry->sp_expire), + INT2FIX(entry->sp_flag), + 0); + return result; +}; + +static VALUE +rb_shadow_getspent(VALUE self) +{ + struct spwd *entry; + VALUE result; + + entry = getspent(); + + if( entry == NULL ) + return Qnil; + + result = rb_struct_new(rb_sPasswdEntry, + rb_tainted_str_new2(entry->sp_namp), + rb_tainted_str_new2(entry->sp_pwdp), + INT2FIX(entry->sp_lstchg), + INT2FIX(entry->sp_min), + INT2FIX(entry->sp_max), + INT2FIX(entry->sp_warn), + INT2FIX(entry->sp_inact), + INT2FIX(entry->sp_expire), + INT2FIX(entry->sp_flag), + 0); + return result; +}; + +static VALUE +rb_shadow_getspnam(VALUE self, VALUE name) +{ + struct spwd *entry; + VALUE result; + + if( TYPE(name) != T_STRING ) + rb_raise(rb_eException,"argument must be a string."); + + entry = getspnam(STR2CSTR(name)); + + if( entry == NULL ) + return Qnil; + + result = rb_struct_new(rb_sPasswdEntry, + rb_tainted_str_new2(entry->sp_namp), + rb_tainted_str_new2(entry->sp_pwdp), + INT2FIX(entry->sp_lstchg), + INT2FIX(entry->sp_min), + INT2FIX(entry->sp_max), + INT2FIX(entry->sp_warn), + INT2FIX(entry->sp_inact), + INT2FIX(entry->sp_expire), + INT2FIX(entry->sp_flag), + 0); + return result; +}; + + +static VALUE +rb_shadow_putspent(VALUE self, VALUE entry, VALUE file) +{ + struct spwd centry; + FILE* cfile; + VALUE val[9]; + int i; + int result; + + for(i=0; i<=8; i++) + val[i] = RSTRUCT(entry)->ptr[i]; + cfile = RFILE(file)->fptr->f; + + centry.sp_namp = STR2CSTR(val[0]); + centry.sp_pwdp = STR2CSTR(val[1]); + centry.sp_lstchg = FIX2INT(val[2]); + centry.sp_min = FIX2INT(val[3]); + centry.sp_max = FIX2INT(val[4]); + centry.sp_warn = FIX2INT(val[5]); + centry.sp_inact = FIX2INT(val[6]); + centry.sp_expire = FIX2INT(val[7]); + centry.sp_flag = FIX2INT(val[8]); + + result = putspent(¢ry,cfile); + + if( result == -1 ) + rb_raise(rb_eStandardError,"can't change password"); + + return Qtrue; +}; + + +static VALUE +rb_shadow_lckpwdf(VALUE self) +{ + int result; + result = lckpwdf(); + if( result == -1 ) + rb_raise(rb_eFileLock,"password file was locked"); + else + return Qtrue; +}; + +static int in_lock; + +static VALUE +rb_shadow_lock(VALUE self) +{ + int result; + + if( rb_iterator_p() ){ + result = lckpwdf(); + if( result == -1 ){ + rb_raise(rb_eFileLock,"password file was locked"); + } + else{ + in_lock++; + rb_yield(Qnil); + in_lock--; + ulckpwdf(); + }; + return Qtrue; + } + else{ + return rb_shadow_lckpwdf(self); + }; +}; + + +static VALUE +rb_shadow_ulckpwdf(VALUE self) +{ + if( in_lock ){ + rb_raise(rb_eFileLock,"you call unlock method in lock iterator."); + }; + ulckpwdf(); + return Qtrue; +}; + +static VALUE +rb_shadow_unlock(VALUE self) +{ + return rb_shadow_ulckpwdf(self); +}; + +static VALUE +rb_shadow_lock_p(VALUE self) +{ + int result; + + result = lckpwdf(); + if( result == -1 ){ + return Qtrue; + } + else{ + ulckpwdf(); + return Qfalse; + }; +}; + + +void +Init_shadow() +{ + rb_sPasswdEntry = rb_struct_define("PasswdEntry", + "sp_namp","sp_pwdp","sp_lstchg", + "sp_min","sp_max","sp_warn", + "sp_inact","sp_expire","sp_flag",0); + rb_sGroupEntry = rb_struct_define("GroupEntry", + "sg_name","sg_passwd", + "sg_adm","sg_mem",0); + + rb_mShadow = rb_define_module("Shadow"); + rb_eFileLock = rb_define_class_under(rb_mShadow,"FileLock",rb_eException); + rb_mPasswd = rb_define_module_under(rb_mShadow,"Passwd"); + rb_define_const(rb_mPasswd,"Entry",rb_sPasswdEntry); + rb_mGroup = rb_define_module_under(rb_mShadow,"Group"); + rb_define_const(rb_mGroup,"Entry",rb_sGroupEntry); + + rb_define_module_function(rb_mPasswd,"setspent",rb_shadow_setspent,0); + rb_define_module_function(rb_mPasswd,"endspent",rb_shadow_endspent,0); + rb_define_module_function(rb_mPasswd,"sgetspent",rb_shadow_sgetspent,1); + rb_define_module_function(rb_mPasswd,"fgetspent",rb_shadow_fgetspent,1); + rb_define_module_function(rb_mPasswd,"getspent",rb_shadow_getspent,0); + rb_define_module_function(rb_mPasswd,"getspnam",rb_shadow_getspnam,1); + rb_define_module_function(rb_mPasswd,"putspent",rb_shadow_putspent,2); + rb_define_module_function(rb_mPasswd,"lckpwdf",rb_shadow_lckpwdf,0); + rb_define_module_function(rb_mPasswd,"lock",rb_shadow_lock,0); + rb_define_module_function(rb_mPasswd,"ulckpwdf",rb_shadow_ulckpwdf,0); + rb_define_module_function(rb_mPasswd,"unlock",rb_shadow_unlock,0); + rb_define_module_function(rb_mPasswd,"lock?",rb_shadow_lock_p,0); +}; diff --git a/ruby-shadow/recipes/default.rb b/ruby-shadow/recipes/default.rb new file mode 100755 index 0000000..d9236d3 --- /dev/null +++ b/ruby-shadow/recipes/default.rb @@ -0,0 +1,15 @@ +remote_directory "/usr/local/src/shadow-1.4.1" do + source 'shadow-1.4.1' + not_if { File.exists?(File.join(node[:ruby_shadow][:site_ruby], "#{node[:languages][:ruby][:platform]}/shadow.so")) } +end + +bash "install ruby shadow library" do + user "root" + cwd "/usr/local/src" + code <<-EOH + cd shadow-1.4.1 + ruby extconf.rb + make install + EOH + not_if { File.exists?(File.join(node[:ruby_shadow][:site_ruby], "/#{node[:languages][:ruby][:platform]}/shadow.so")) } +end \ No newline at end of file diff --git a/ruby/metadata.json b/ruby/metadata.json new file mode 100644 index 0000000..e5e6eed --- /dev/null +++ b/ruby/metadata.json @@ -0,0 +1,52 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs ruby packages", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "ruby": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "fedora": [ + + ], + "centos": [ + + ], + "debian": [ + + ], + "redhat": [ + + ] + }, + "version": "0.7.0", + "name": "ruby", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "ruby": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/ruby/metadata.rb b/ruby/metadata.rb new file mode 100644 index 0000000..45889d4 --- /dev/null +++ b/ruby/metadata.rb @@ -0,0 +1,9 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs ruby packages" +version "0.7" + +%w{ centos redhat fedora ubuntu debian }.each do |os| + supports os +end diff --git a/ruby/recipes/default.rb b/ruby/recipes/default.rb new file mode 100644 index 0000000..09f98b3 --- /dev/null +++ b/ruby/recipes/default.rb @@ -0,0 +1,49 @@ +# +# Cookbook Name:: ruby +# Recipe:: default +# +# Copyright 2008-2009, Opscode, 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 "ruby" do + action :install +end + +extra_packages = case node[:platform] + when "ubuntu","debian" + %w{ + ruby1.8 + ruby1.8-dev + rdoc1.8 + ri1.8 + libopenssl-ruby + } + when "centos","redhat","fedora" + %w{ + ruby-libs + ruby-devel + ruby-docs + ruby-ri + ruby-irb + ruby-rdoc + ruby-mode + } + end + +extra_packages.each do |pkg| + package pkg do + action :install + end +end diff --git a/ruby_enterprise/README.rdoc b/ruby_enterprise/README.rdoc new file mode 100644 index 0000000..476cf5d --- /dev/null +++ b/ruby_enterprise/README.rdoc @@ -0,0 +1,53 @@ += DESCRIPTION: + +Installs Ruby Enterprise Edition (REE) from Phusion. + += REQUIREMENTS: + +Opscode's build-essential cookbook to get a compiler and associated files installed. + += ATTRIBUTES: + +* ruby_enterprise[:install_path] - Location to install REE. Default /opt/ruby-enterprise +* ruby_enterprise[:version] - Version-datestamp to use. Default 1.8.6-20090610. May lag behind latest REE release. +* ruby_enterprise[:url] - URL to download. Default is from RubyForge, with the version specified. Note the download ID must be updated when there are new releases. + += USAGE: + +Include the ruby_enterprise recipe to install REE. + + include_recipe "ruby_enterprise" + +Or add it to your role, or directly to a node's recipes. + +Install RubyGems under REE with the ree_gem definition. + + ree_gem "rails" do + source "http://gems.rubyforge.org" + version "2.3.4" + end + +The definition supports parameters for source and version, though they are optional. + += LICENSE and AUTHOR: + +Author:: Joshua Timberman () +Author:: Sean Cribbs () +Author:: Michael Hale () + +Copyright:: 2009-2010, Opscode, Inc. +Copyright:: 2009, Sean Cribbs +Copyright:: 2009, Michael Hale + +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/ruby_enterprise/attributes/ruby_enterprise.rb b/ruby_enterprise/attributes/ruby_enterprise.rb new file mode 100644 index 0000000..ecb4b87 --- /dev/null +++ b/ruby_enterprise/attributes/ruby_enterprise.rb @@ -0,0 +1,30 @@ +# +# Cookbook Name:: ruby_enterprise +# attributes:: ruby_enterprise +# +# Author:: Joshua Timberman () +# Author:: Sean Cribbs () +# Author:: Michael Hale () +# +# Copyright:: 2009-2010, Opscode, Inc. +# Copyright:: 2009, Sean Cribbs +# Copyright:: 2009, Michael Hale +# +# 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. +# + +set_unless[:ruby_enterprise][:install_path] = "/opt/ruby-enterprise" +set_unless[:ruby_enterprise][:ruby_bin] = "/opt/ruby-enterprise/bin/ruby" +set_unless[:ruby_enterprise][:gems_dir] = "#{ruby_enterprise[:install_path]}/lib/ruby/gems/1.8" +set_unless[:ruby_enterprise][:version] = '1.8.7-2009.10' +set_unless[:ruby_enterprise][:url] = "http://rubyforge.org/frs/download.php/66162/ruby-enterprise-#{ruby_enterprise[:version]}" diff --git a/ruby_enterprise/definitions/ree_gem.rb b/ruby_enterprise/definitions/ree_gem.rb new file mode 100644 index 0000000..200ee21 --- /dev/null +++ b/ruby_enterprise/definitions/ree_gem.rb @@ -0,0 +1,28 @@ +# +# Cookbook Name:: ruby_enterprise +# Recipe:: ree_gem +# +# Author:: Joshua Timberman () +# +# Copyright 2009, Opscode, 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. +# + +define :ree_gem, :source => nil, :version => nil do + gem_package params[:name] do + gem_binary "#{node[:ruby_enterprise][:install_path]}/bin/gem" + source params[:source] if params[:source] + version params[:version] if params[:version] + end +end diff --git a/ruby_enterprise/metadata.json b/ruby_enterprise/metadata.json new file mode 100644 index 0000000..94ac30b --- /dev/null +++ b/ruby_enterprise/metadata.json @@ -0,0 +1,45 @@ +{ + "replacing": { + + }, + "dependencies": { + "build-essential": [ + + ] + }, + "groupings": { + + }, + "long_description": "= DESCRIPTION:\n\nInstalls Ruby Enterprise Edition (REE) from Phusion.\n\n= REQUIREMENTS:\n\nOpscode's build-essential cookbook to get a compiler and associated files installed.\n\n= ATTRIBUTES: \n\n* ruby_enterprise[:install_path] - Location to install REE. Default /opt/ruby-enterprise\n* ruby_enterprise[:version] - Version-datestamp to use. Default 1.8.6-20090610. May lag behind latest REE release.\n* ruby_enterprise[:url] - URL to download. Default is from RubyForge, with the version specified. Note the download ID must be updated when there are new releases.\n\n= USAGE:\n\nInclude the ruby_enterprise recipe to install REE.\n\n include_recipe \"ruby_enterprise\"\n\nOr add it to your role, or directly to a node's recipes.\n\nInstall RubyGems under REE with the ree_gem definition.\n\n ree_gem \"rails\" do\n source \"http://gems.rubyforge.org\"\n version \"2.3.4\"\n end\n\nThe definition supports parameters for source and version, though they are optional.\n\n= LICENSE and AUTHOR:\n\nAuthor:: Joshua Timberman ()\nCopyright:: 2009, Opscode, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\n", + "description": "Installs/Configures ruby-enterprise", + "recommendations": { + + }, + "platforms": { + "ubuntu": [ + + ] + }, + "version": "0.1.0", + "maintainer": "Opscode, Inc.", + "name": "ruby_enterprise", + "suggestions": { + + }, + "maintainer_email": "ops@opscode.com", + "recipes": { + "ruby_enterprise": "" + }, + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "ruby_enterprise": [ + + ] + }, + "license": "Apache 2.0" +} \ No newline at end of file diff --git a/ruby_enterprise/metadata.rb b/ruby_enterprise/metadata.rb new file mode 100644 index 0000000..e28cbd7 --- /dev/null +++ b/ruby_enterprise/metadata.rb @@ -0,0 +1,9 @@ +maintainer "Opscode, Inc." +maintainer_email "ops@opscode.com" +license "Apache 2.0" +description "Installs/Configures ruby-enterprise" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.1" + +depends "build-essential" +supports "ubuntu" diff --git a/ruby_enterprise/recipes/default.rb b/ruby_enterprise/recipes/default.rb new file mode 100644 index 0000000..3969f18 --- /dev/null +++ b/ruby_enterprise/recipes/default.rb @@ -0,0 +1,49 @@ +# +# Cookbook Name:: ruby_enterprise +# Recipe:: default +# +# Author:: Joshua Timberman () +# Author:: Sean Cribbs () +# Author:: Michael Hale () +# +# Copyright:: 2009-2010, Opscode, Inc. +# Copyright:: 2009, Sean Cribbs +# Copyright:: 2009, Michael Hale +# +# 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 "build-essential" + +%w{ libssl-dev libreadline5-dev }.each do |pkg| + package pkg +end + +remote_file "/tmp/ruby-enterprise-#{node[:ruby_enterprise][:version]}.tar.gz" do + source "#{node[:ruby_enterprise][:url]}.tar.gz" + not_if { ::File.exists?("/tmp/ruby-enterprise-#{node[:ruby_enterprise][:version]}.tar.gz") } +end + +bash "Install Ruby Enterprise Edition" do + cwd "/tmp" + code <<-EOH + tar zxf ruby-enterprise-#{node[:ruby_enterprise][:version]}.tar.gz + ruby-enterprise-#{node[:ruby_enterprise][:version]}/installer \ + --auto=#{node[:ruby_enterprise][:install_path]} \ + --dont-install-useful-gems + EOH + not_if do + ::File.exists?("#{node[:ruby_enterprise][:install_path]}/bin/ree-version") && + system("#{node[:ruby_enterprise][:install_path]}/bin/ree-version | grep -q '#{node[:ruby_enterprise][:version]}$'") + end +end diff --git a/ruby_enterprise_edition/attributes/ree.rb b/ruby_enterprise_edition/attributes/ree.rb new file mode 100755 index 0000000..9436f77 --- /dev/null +++ b/ruby_enterprise_edition/attributes/ree.rb @@ -0,0 +1,3 @@ +default.ree[:version] = "1.8.7-2009.10" +#default.ree[:version] = "1.8.6-20090610" +default.ree[:architecture] = kernel[:machine] == "x86_64" ? "amd64" : "i386" \ No newline at end of file diff --git a/ruby_enterprise_edition/recipes/default.rb b/ruby_enterprise_edition/recipes/default.rb new file mode 100755 index 0000000..62e545a --- /dev/null +++ b/ruby_enterprise_edition/recipes/default.rb @@ -0,0 +1,9 @@ +ree_filename = ["ruby-enterprise", node[:ree][:version], node[:ree][:architecture]].join("_")+".deb" + +remote_file "/tmp/#{ree_filename}" do + source ree_filename +end + +dpkg_package "ruby-enterprise" do + source "/tmp/#{ree_filename}" +end \ No newline at end of file diff --git a/rubygems/metadata.rb b/rubygems/metadata.rb new file mode 100644 index 0000000..70d5028 --- /dev/null +++ b/rubygems/metadata.rb @@ -0,0 +1,9 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Opscode rubygems config" +long_description <<-EOH +Configures rubygems sources lists +EOH +version "0.1" +recipe "rubygems", "Configures rubygems" diff --git a/rubygems/recipes/default.rb b/rubygems/recipes/default.rb new file mode 100644 index 0000000..a178b9b --- /dev/null +++ b/rubygems/recipes/default.rb @@ -0,0 +1,25 @@ +# +# Author:: Adam Jacob +# Cookbook Name:: rubygems +# Recipe:: default +# +# Copyright 2009, Opscode, 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. +# + +%w{ rubyforge.org opscode.com }.each do |domain| + execute "gem sources --add http://gems.#{domain}" do + not_if "gem sources --list | grep gems.#{domain}" + end +end diff --git a/runit/attributes/sv_bin.rb b/runit/attributes/sv_bin.rb new file mode 100644 index 0000000..84a09b3 --- /dev/null +++ b/runit/attributes/sv_bin.rb @@ -0,0 +1,25 @@ +# +# Cookbook Name:: runit +# Attribute File:: sv_bin +# +# Copyright 2008-2009, Opscode, 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. +# + +case platform +when "ubuntu","debian" + set[:runit][:sv_bin] = "/usr/bin/sv" + set[:runit][:service_dir] = "/etc/service" + set[:runit][:sv_dir] = "/etc/sv" +end diff --git a/runit/definitions/runit_service.rb b/runit/definitions/runit_service.rb new file mode 100644 index 0000000..bcb1ad9 --- /dev/null +++ b/runit/definitions/runit_service.rb @@ -0,0 +1,87 @@ +# +# Cookbook Name:: runit +# Definition:: runit_service +# +# Copyright 2008-2009, Opscode, 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. +# + +define :runit_service, :directory => nil, :only_if => false, :options => Hash.new do + + params[:directory] ||= node[:runit][:sv_dir] + + sv_dir_name = "#{params[:directory]}/#{params[:name]}" + + directory sv_dir_name do + mode 0755 + action :create + end + + directory "#{sv_dir_name}/log" do + mode 0755 + action :create + end + + directory "#{sv_dir_name}/log/main" do + mode 0755 + action :create + end + + params[:template_name] ||= params[:name] + template "#{sv_dir_name}/run" do + mode 0755 + source "sv-#{params[:template_name]}-run.erb" + cookbook params[:cookbook] if params[:cookbook] + if params[:options].respond_to?(:has_key?) + variables :options => params[:options] + end + end + + template "#{sv_dir_name}/log/run" do + mode 0755 + source "sv-#{params[:template_name]}-log-run.erb" + cookbook params[:cookbook] if params[:cookbook] + if params[:options].respond_to?(:has_key?) + variables :options => params[:options] + end + end + + link "/etc/init.d/#{params[:name]}" do + to node[:runit][:sv_bin] + end + + link "#{node[:runit][:service_dir]}/#{params[:name]}" do + to "#{sv_dir_name}" + end + + ruby_block "supervise_#{params[:name]}_sleep" do + block do + (1..6).each {|i| sleep 1 unless ::FileTest.pipe?("#{sv_dir_name}/supervise/ok") } + end + not_if { FileTest.pipe?("#{sv_dir_name}/supervise/ok") } + end + + service params[:name] do + supports :restart => true, :status => true + subscribes :restart, resources(:template => "#{sv_dir_name}/run"), :delayed + subscribes :restart, resources(:template => "#{sv_dir_name}/log/run"), :delayed + action :nothing + end + + #execute "#{params[:name]}-down" do + # command "/etc/init.d/#{params[:name]} down" + # only_if do params[:only_if] end + #end + +end diff --git a/runit/files/default/runsvdir b/runit/files/default/runsvdir new file mode 100644 index 0000000..e69de29 diff --git a/runit/files/ubuntu-6.10/runsvdir b/runit/files/ubuntu-6.10/runsvdir new file mode 100644 index 0000000..4040e34 --- /dev/null +++ b/runit/files/ubuntu-6.10/runsvdir @@ -0,0 +1,6 @@ +start on runlevel-2 +start on runlevel-3 +start on runlevel-4 +start on runlevel-5 +stop on shutdown +respawn /usr/sbin/runsvdir-start diff --git a/runit/files/ubuntu-7.04/runsvdir b/runit/files/ubuntu-7.04/runsvdir new file mode 100644 index 0000000..ee173c9 --- /dev/null +++ b/runit/files/ubuntu-7.04/runsvdir @@ -0,0 +1,7 @@ +start on runlevel 2 +start on runlevel 3 +start on runlevel 4 +start on runlevel 5 +stop on shutdown +respawn +exec /usr/sbin/runsvdir-start diff --git a/runit/files/ubuntu-7.10/runsvdir b/runit/files/ubuntu-7.10/runsvdir new file mode 100644 index 0000000..ee173c9 --- /dev/null +++ b/runit/files/ubuntu-7.10/runsvdir @@ -0,0 +1,7 @@ +start on runlevel 2 +start on runlevel 3 +start on runlevel 4 +start on runlevel 5 +stop on shutdown +respawn +exec /usr/sbin/runsvdir-start diff --git a/runit/files/ubuntu-8.04/runsvdir b/runit/files/ubuntu-8.04/runsvdir new file mode 100644 index 0000000..ee173c9 --- /dev/null +++ b/runit/files/ubuntu-8.04/runsvdir @@ -0,0 +1,7 @@ +start on runlevel 2 +start on runlevel 3 +start on runlevel 4 +start on runlevel 5 +stop on shutdown +respawn +exec /usr/sbin/runsvdir-start diff --git a/runit/metadata.json b/runit/metadata.json new file mode 100644 index 0000000..2b3a13e --- /dev/null +++ b/runit/metadata.json @@ -0,0 +1,85 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs runit and provides runit_service definition", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "runit": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "debian": [ + + ] + }, + "version": "0.7.0", + "name": "runit", + "conflicting": { + + }, + "attributes": { + "runit\/service_dir": { + "default": "\/etc\/service", + "type": "string", + "multiple_values": false, + "description": "Symlinks to services managed under runit", + "display_name": "Runit service directory", + "recipes": [ + + ], + "required": false + }, + "runit\/sv_bin": { + "default": "\/usr\/bin\/sv", + "type": "string", + "multiple_values": false, + "description": "Location of the sv binary", + "display_name": "Runit sv bin", + "recipes": [ + + ], + "required": false + }, + "runit": { + "type": "hash", + "multiple_values": false, + "description": "Hash of runit attributes", + "display_name": "Runit", + "recipes": [ + + ], + "required": false + }, + "runit\/sv_dir": { + "default": "\/etc\/sv", + "type": "string", + "multiple_values": false, + "description": "Location of services managed by runit", + "display_name": "Runit sv directory", + "recipes": [ + + ], + "required": false + } + }, + "providing": { + "runit": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/runit/metadata.rb b/runit/metadata.rb new file mode 100644 index 0000000..7f3f925 --- /dev/null +++ b/runit/metadata.rb @@ -0,0 +1,30 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs runit and provides runit_service definition" +version "0.8" + +%w{ ubuntu debian }.each do |os| + supports os +end + +attribute "runit", + :display_name => "Runit", + :description => "Hash of runit attributes", + :type => "hash" + +attribute "runit/sv_bin", + :display_name => "Runit sv bin", + :description => "Location of the sv binary", + :default => "/usr/bin/sv" + +attribute "runit/service_dir", + :display_name => "Runit service directory", + :description => "Symlinks to services managed under runit", + :default => "/etc/service" + +attribute "runit/sv_dir", + :display_name => "Runit sv directory", + :description => "Location of services managed by runit", + :default => "/etc/sv" + diff --git a/runit/recipes/default.rb b/runit/recipes/default.rb new file mode 100644 index 0000000..10f6f9f --- /dev/null +++ b/runit/recipes/default.rb @@ -0,0 +1,46 @@ +# +# Cookbook Name:: runit +# Recipe:: default +# +# Copyright 2008-2009, Opscode, 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. +# + +case node[:platform] +when "debian","ubuntu" + execute "start-runsvdir" do + command value_for_platform( + "debian" => { "default" => "runsvdir-start" }, + "ubuntu" => { "default" => "start runsvdir" } + ) + action :nothing + end + + package "runit" do + action :install + notifies value_for_platform( + "debian" => { "4.0" => :run, "default" => :nothing }, + "ubuntu" => { "default" => :run } + ), resources(:execute => "start-runsvdir") + end + + if node[:platform_version] <= "8.04" && node[:platform] =~ /ubuntu/i + remote_file "/etc/event.d/runsvdir" do + source "runsvdir" + mode 0644 + notifies :run, resources(:execute => "start-runsvdir") + only_if do File.directory?("/etc/event.d") end + end + end +end diff --git a/screen/metadata.json b/screen/metadata.json new file mode 100644 index 0000000..de1d7e5 --- /dev/null +++ b/screen/metadata.json @@ -0,0 +1,52 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs screen", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "screen": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "fedora": [ + + ], + "centos": [ + + ], + "debian": [ + + ], + "redhat": [ + + ] + }, + "version": "0.7.0", + "name": "screen", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "screen": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/screen/metadata.rb b/screen/metadata.rb new file mode 100644 index 0000000..5fac8e3 --- /dev/null +++ b/screen/metadata.rb @@ -0,0 +1,9 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs screen" +version "0.7" + +%w{ redhat centos fedora ubuntu debian }.each do |os| + supports os +end diff --git a/screen/recipes/default.rb b/screen/recipes/default.rb new file mode 100644 index 0000000..0f81ff4 --- /dev/null +++ b/screen/recipes/default.rb @@ -0,0 +1,22 @@ +# +# Cookbook Name:: screen +# Recipe:: default +# +# Copyright 2008-2009, Opscode, 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 "screen" do + action :install +end diff --git a/simple_rails_app/attributes/simple_rails_app.rb b/simple_rails_app/attributes/simple_rails_app.rb new file mode 100644 index 0000000..0c79131 --- /dev/null +++ b/simple_rails_app/attributes/simple_rails_app.rb @@ -0,0 +1,2 @@ +set_unless[:nginx][:conf_dir] = "/etc/nginx" +set_unless[:apps] = [{ :name => "enki", :username => "site", :git_branch => "master"}] \ No newline at end of file diff --git a/simple_rails_app/recipes/default.rb b/simple_rails_app/recipes/default.rb new file mode 100644 index 0000000..48fe684 --- /dev/null +++ b/simple_rails_app/recipes/default.rb @@ -0,0 +1,51 @@ +include_recipe "git" + +node[:apps].each do |app| + home_path = "/home/#{app[:username]}" + repos_path = "#{home_path}/repos/#{app[:name]}.git" + app_path = "#{home_path}/#{app[:name]}" + + # initialize bare git repo + bash "create repo folder" do + user app[:username] + code "mkdir -p #{repos_path} && cd #{repos_path} && git init --bare" + not_if { File.exists?(repos_path) } + end + + template "#{repos_path}/hooks/post-receive" do + path "#{repos_path}/hooks/post-receive" + source "post-receive.erb" + owner app[:username] + group app[:group] || app[:username] + mode 0755 + variables( + :app_path => app_path, + :git_branch => app[:git_branch] || "master" + ) + action :create + end + + # set web app permissions + bash "clone git repo" do + user app[:username] + code "cd #{home_path} && git clone #{repos_path} #{app[:name]}" + not_if { File.exists?(app_path) } + end + + template "#{node[:nginx][:conf_dir]}/sites-available/#{app[:name]}" do + source "rails_app.conf.erb" + owner "root" + group "root" + mode 0644 + variables( + :root_dir => app_path, + :server_name => app[:server] + ) + if File.exists?("#{node[:nginx][:conf_dir]}/sites-enabled/#{app[:name]}") + notifies :reload, resources(:service => "nginx"), :delayed + end + not_if { File.exists?("#{node[:nginx][:conf_dir]}/sites-enabled/#{app[:name]}") } + end + + nginx_site app[:name] +end \ No newline at end of file diff --git a/simple_rails_app/templates/default/post-receive.erb b/simple_rails_app/templates/default/post-receive.erb new file mode 100644 index 0000000..d36057b --- /dev/null +++ b/simple_rails_app/templates/default/post-receive.erb @@ -0,0 +1,23 @@ +#!/bin/sh +cd <%= @app_path %> +env -i [ -d log ] || mkdir log +env -i [ -d tmp ] || mkdir tmp +env -i git reset --hard +env -i git pull origin <%= @git_branch %> +env -i [ -f .gitmodules ] && git submodule update +env -i rake db:migrate RAILS_ENV=production +env -i touch tmp/restart.txt + +# +# An example hook script for the post-receive event +# +# This script is run after receive-pack has accepted a pack and the +# repository has been updated. It is passed arguments in through stdin +# in the form +# +# For example: +# aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/master +# +# see contrib/hooks/ for an sample, or uncomment the next line (on debian) +# +#. /usr/share/doc/git-core/contrib/hooks/post-receive-email diff --git a/simple_rails_app/templates/default/rails_app_conf.erb b/simple_rails_app/templates/default/rails_app_conf.erb new file mode 100644 index 0000000..7faa55b --- /dev/null +++ b/simple_rails_app/templates/default/rails_app_conf.erb @@ -0,0 +1,13 @@ +server { + server_name <%= @server_name %>; + listen 80; + + location / { + root <%= @root_dir %>/public; + passenger_enabled on; + + if (-f $document_root/system/maintenance.html) { + rewrite ^(.*)$ /system/maintenance.html break; + } + } +} diff --git a/solr/README.rdoc b/solr/README.rdoc new file mode 100644 index 0000000..dea8cc5 --- /dev/null +++ b/solr/README.rdoc @@ -0,0 +1,57 @@ += DESCRIPTION: + +Sets up user and environment for running solr instances. + += REQUIREMENTS: + +== Platform and Application Environment: + +Tested on Ubuntu 8.10. May work on other platforms, esp Ubuntu/Debian. + +Requires solr installed, such as a vendor plugin for a Rails application. Assumes 'start.jar' exists. Also requires ssh keys for solr user. See usage. + +== Cookbooks: + +Opscode cookbooks, http://github.com/opscode/cookbooks/tree/master: + +* capistrano (capistrano_setup) +* java +* runit (runit_service) + += ATTRIBUTES: + +* solr[:user] - username for solr process and files/dirs. +* solr[:uid] - UID for solr user. +* solr[:group] - group name for solr files/dirs. +* solr[:gid] - GID for solr group. + += USAGE: + +To create a solr instance for an application, use the solr_instance define: + + solr_instance "my_app" + +The recipe assumes that id_rsa ssh key pair has been created for the solr user. The files should be located in the cookbook where the solr_instance is used (for example a site-cookbook). + +Also create the runit run and log run templates. For now the directory to cd into needs to be specified in the run template. See the sample in this cookbook. + +== Parameters: + +Optionally specify a cookbook where the ssh keypair is located, otherwise generate keys and put the files in the solr cookbook. Empty files are located there for placeholders. + += LICENSE and AUTHOR: + +Author:: Joshua Timberman () +Copyright:: 2009, Opscode, 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/solr/attributes/solr.rb b/solr/attributes/solr.rb new file mode 100644 index 0000000..21b1650 --- /dev/null +++ b/solr/attributes/solr.rb @@ -0,0 +1,23 @@ +# +# Cookbook Name:: solr +# Attributes:: solr +# +# Copyright 2008-2009, Opscode, 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. +# + +set_unless[:solr][:user] = 'solr' +set_unless[:solr][:uid] = 551 +set_unless[:solr][:group] = 'solr' +set_unless[:solr][:gid] = 551 diff --git a/solr/definitions/solr_instance.rb b/solr/definitions/solr_instance.rb new file mode 100644 index 0000000..0d7cbe0 --- /dev/null +++ b/solr/definitions/solr_instance.rb @@ -0,0 +1,65 @@ +# +# Cookbook Name:: solr +# Definition:: solr_instance +# +# Copyright 2009, Opscode, 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. +# + +define :solr_instance, :path => "/srv", :type => "master" do + include_recipe "solr" + + cap_setup "#{params[:name]}" do + path "#{params[:path]}/#{params[:name]}" + appowner "solr" + end + + %w{ solr solr/data }.each do |dir| + directory "#{params[:path]}/#{params[:name]}/#{dir}" do + owner node[:solr][:user] + group node[:solr][:group] + mode 0755 + end + end + + %w{ bin conf }.each do |dir| + directory "#{params[:path]}/#{params[:name]}/#{dir}" do + owner "root" + group "nogroup" + mode 0755 + end + end + + runit_service "#{params[:name]}_solr" + + directory "#{params[:path]}/#{params[:name]}/.ssh" do + owner node[:solr][:user] + group node[:solr][:group] + mode 0700 + end + + %w{ id_rsa id_rsa.pub authorized_keys }.each do |ssh_file| + remote_file "#{params[:path]}/#{params[:name]}/.ssh/#{ssh_file}" do + source ssh_file + owner node[:solr][:user] + group node[:solr][:group] + mode 0600 + if params[:cookbook] + cookbook params[:cookbook] + else + cookbook "solr" + end + end + end +end diff --git a/solr/files/default/authorized_keys b/solr/files/default/authorized_keys new file mode 100644 index 0000000..e69de29 diff --git a/solr/files/default/id_rsa b/solr/files/default/id_rsa new file mode 100644 index 0000000..e69de29 diff --git a/solr/files/default/id_rsa.pub b/solr/files/default/id_rsa.pub new file mode 100644 index 0000000..e69de29 diff --git a/solr/metadata.json b/solr/metadata.json new file mode 100644 index 0000000..643ca4e --- /dev/null +++ b/solr/metadata.json @@ -0,0 +1,96 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Sets up environment for solr instances", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "solr": "" + }, + "suggestions": { + "ruby": [ + + ] + }, + "platforms": { + "ubuntu": [ + + ], + "debian": [ + + ] + }, + "version": "0.7.0", + "name": "solr", + "conflicting": { + + }, + "attributes": { + "solr\/group": { + "default": "solr", + "type": "string", + "multiple_values": false, + "description": "Group for solr instance", + "display_name": "Solr Group", + "recipes": [ + + ], + "required": false + }, + "solr\/uid": { + "default": "551", + "type": "string", + "multiple_values": false, + "description": "UID for solr instance", + "display_name": "Solr UID", + "recipes": [ + + ], + "required": false + }, + "solr\/user": { + "default": "solr", + "type": "string", + "multiple_values": false, + "description": "Username for solr instance", + "display_name": "Solr User", + "recipes": [ + + ], + "required": false + }, + "solr\/gid": { + "default": "551", + "type": "string", + "multiple_values": false, + "description": "GID for solr instance", + "display_name": "Solr GID", + "recipes": [ + + ], + "required": false + } + }, + "providing": { + "solr": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "= DESCRIPTION:\n\nSets up user and environment for running solr instances.\n\n= REQUIREMENTS:\n\n== Platform and Application Environment:\n\nTested on Ubuntu 8.10. May work on other platforms, esp Ubuntu\/Debian.\n\nRequires solr installed, such as a vendor plugin for a Rails application. Assumes 'start.jar' exists. Also requires ssh keys for solr user. See usage.\n\n== Cookbooks:\n\nOpscode cookbooks, http:\/\/github.com\/opscode\/cookbooks\/tree\/master:\n\n* capistrano (capistrano_setup)\n* java\n* runit (runit_service)\n\n= ATTRIBUTES: \n\n* solr[:user] - username for solr process and files\/dirs.\n* solr[:uid] - UID for solr user.\n* solr[:group] - group name for solr files\/dirs.\n* solr[:gid] - GID for solr group.\n\n= USAGE:\n\nTo create a solr instance for an application, use the solr_instance define:\n\n solr_instance \"my_app\" \n\nThe recipe assumes that id_rsa ssh key pair has been created for the solr user. The files should be located in the cookbook where the solr_instance is used (for example a site-cookbook). \n\nAlso create the runit run and log run templates. For now the directory to cd into needs to be specified in the run template. See the sample in this cookbook.\n\n== Parameters:\n\nOptionally specify a cookbook where the ssh keypair is located, otherwise generate keys and put the files in the solr cookbook. Empty files are located there for placeholders.\n\n= LICENSE and AUTHOR:\n \nAuthor:: Joshua Timberman ()\nCopyright:: 2009, Opscode, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http:\/\/www.apache.org\/licenses\/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n", + "replacing": { + + }, + "dependencies": { + "java": [ + + ], + "runit": [ + + ], + "capistrano": [ + + ] + } +} \ No newline at end of file diff --git a/solr/metadata.rb b/solr/metadata.rb new file mode 100644 index 0000000..2ffd700 --- /dev/null +++ b/solr/metadata.rb @@ -0,0 +1,36 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Sets up environment for solr instances" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.7" +suggests "ruby" + +%w{ java capistrano runit }.each do |cb| + depends cb +end + +%w{ debian ubuntu }.each do |os| + supports os +end + +attribute "solr/user", + :display_name => "Solr User", + :description => "Username for solr instance", + :default => "solr" + +attribute "solr/uid", + :display_name => "Solr UID", + :description => "UID for solr instance", + :default => "551" + +attribute "solr/group", + :display_name => "Solr Group", + :description => "Group for solr instance", + :default => "solr" + +attribute "solr/gid", + :display_name => "Solr GID", + :description => "GID for solr instance", + :default => "551" + diff --git a/solr/recipes/default.rb b/solr/recipes/default.rb new file mode 100644 index 0000000..5e7d5c3 --- /dev/null +++ b/solr/recipes/default.rb @@ -0,0 +1,36 @@ +# +# Cookbook Name:: solr +# Recipe:: default +# +# Copyright 2009, Opscode, 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 "java" +include_recipe "capistrano" +include_recipe "runit" + +group node[:solr][:group] do + gid node[:solr][:gid] + action :create +end + +user node[:solr][:user] do + comment "Solr replication" + home "/srv/solr" + shell "/bin/bash" + uid node[:solr][:uid] + gid node[:solr][:gid] + action :create +end diff --git a/solr/templates/default/sv-solr-log-run.erb b/solr/templates/default/sv-solr-log-run.erb new file mode 100644 index 0000000..a79a518 --- /dev/null +++ b/solr/templates/default/sv-solr-log-run.erb @@ -0,0 +1,2 @@ +#!/bin/sh +exec svlogd -tt ./main diff --git a/solr/templates/default/sv-solr-run.erb b/solr/templates/default/sv-solr-run.erb new file mode 100644 index 0000000..ec8662c --- /dev/null +++ b/solr/templates/default/sv-solr-run.erb @@ -0,0 +1,8 @@ +#!/bin/sh + +export JAVA_HOME=/usr/java/jdk +cd # for now need the directory specified. +exec 2>&1 +exec \ + chpst -u <%= @node[:solr][:user] %> /usr/bin/java -Xms128M -Xmx1024M \ + -jar start.jar \ No newline at end of file diff --git a/sqlite/metadata.json b/sqlite/metadata.json new file mode 100644 index 0000000..caabab5 --- /dev/null +++ b/sqlite/metadata.json @@ -0,0 +1,43 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs sqlite", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "sqlite": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "debian": [ + + ] + }, + "version": "0.7.0", + "name": "sqlite", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "sqlite": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/sqlite/metadata.rb b/sqlite/metadata.rb new file mode 100644 index 0000000..4a903c6 --- /dev/null +++ b/sqlite/metadata.rb @@ -0,0 +1,9 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs sqlite" +version "0.7" + +%w{ubuntu debian}.each do |os| + supports os +end diff --git a/sqlite/recipes/default.rb b/sqlite/recipes/default.rb new file mode 100644 index 0000000..f2f9daa --- /dev/null +++ b/sqlite/recipes/default.rb @@ -0,0 +1,26 @@ +# +# Cookbook Name:: sqlite +# Recipe:: default +# +# Copyright 2009, Opscode, 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 "sqlite3" do + action :upgrade +end + +package "sqlite3-doc" do + action :upgrade +end diff --git a/ssh/attributes/ssh.rb b/ssh/attributes/ssh.rb new file mode 100755 index 0000000..d5341a0 --- /dev/null +++ b/ssh/attributes/ssh.rb @@ -0,0 +1,2 @@ +ssh Mash.new unless attribute?(:ssh) +sshd Mash.new unless attribute?(:sshd) diff --git a/ssh/files/default/known_hosts b/ssh/files/default/known_hosts new file mode 100755 index 0000000..10b0873 --- /dev/null +++ b/ssh/files/default/known_hosts @@ -0,0 +1 @@ +# place known_hosts from ssh-keyscan here diff --git a/ssh/metadata.json b/ssh/metadata.json new file mode 100755 index 0000000..99977e6 --- /dev/null +++ b/ssh/metadata.json @@ -0,0 +1,38 @@ +{ + "replacing": { + + }, + "long_description": "", + "attributes": { + + }, + "maintainer": "37signals", + "recommendations": { + + }, + "license": "Apache v2.0", + "recipes": { + "ssh::server": "" + }, + "maintainer_email": "sysadmins@37signals.com", + "suggestions": { + + }, + "dependencies": { + + }, + "conflicting": { + + }, + "platforms": { + + }, + "description": "Configures ssh", + "version": "0.1.0", + "name": "ssh", + "providing": { + "ssh::server": [ + + ] + } +} \ No newline at end of file diff --git a/ssh/metadata.rb b/ssh/metadata.rb new file mode 100755 index 0000000..d40f1e6 --- /dev/null +++ b/ssh/metadata.rb @@ -0,0 +1,4 @@ +maintainer "37signals" +maintainer_email "sysadmins@37signals.com" +description "Configures ssh" +version "0.1" diff --git a/ssh/recipes/server.rb b/ssh/recipes/server.rb new file mode 100755 index 0000000..b34a502 --- /dev/null +++ b/ssh/recipes/server.rb @@ -0,0 +1,29 @@ +service "ssh" do + supports :restart => true, :reload => true + action :enable +end + +remote_file "/etc/ssh/known_hosts" do + source "known_hosts" + mode 0644 +end + +template "/etc/ssh/ssh_config" do + source "ssh_config.erb" + mode 0644 + owner "root" + group "root" +end + +template "/etc/ssh/sshd_config" do + source "sshd_config.erb" + mode 0644 + owner "root" + group "root" + notifies :restart, resources(:service => "ssh") +end + + +service "ssh" do + action :start +end \ No newline at end of file diff --git a/ssh/templates/default/ssh_config.erb b/ssh/templates/default/ssh_config.erb new file mode 100755 index 0000000..b72919f --- /dev/null +++ b/ssh/templates/default/ssh_config.erb @@ -0,0 +1,8 @@ +# +# Dynamically generated by Chef - local modifications will be replaced +# +Host * + SendEnv LANG LC_* + GSSAPIAuthentication yes + GSSAPIDelegateCredentials no + GlobalKnownHostsFile /etc/ssh/known_hosts \ No newline at end of file diff --git a/ssh/templates/default/sshd_config.erb b/ssh/templates/default/sshd_config.erb new file mode 100755 index 0000000..47526c7 --- /dev/null +++ b/ssh/templates/default/sshd_config.erb @@ -0,0 +1,45 @@ +# +# Dynamically generated by Chef - local modifications will be replaced +# + +Port 22 +Protocol 2 +HostKey /etc/ssh/ssh_host_rsa_key +HostKey /etc/ssh/ssh_host_dsa_key + +UsePrivilegeSeparation yes + +KeyRegenerationInterval 3600 +ServerKeyBits 768 + +SyslogFacility AUTH +LogLevel INFO + +LoginGraceTime 120 +PermitRootLogin no +StrictModes yes +RSAAuthentication yes +PubkeyAuthentication yes + +IgnoreRhosts yes +RhostsRSAAuthentication no +HostbasedAuthentication no +PermitEmptyPasswords no +ChallengeResponseAuthentication no +PasswordAuthentication no + +X11Forwarding yes +X11DisplayOffset 10 +PrintMotd no +PrintLastLog yes +TCPKeepAlive yes + +AcceptEnv LANG LC_* + +Subsystem sftp /usr/lib/openssh/sftp-server + +UsePAM yes + +<% if @node[:sshd][:max_startups] %> +MaxStartups <%= @node[:sshd][:max_startups] %> +<% end %> \ No newline at end of file diff --git a/ssh_keys/definitions/add_keys.rb b/ssh_keys/definitions/add_keys.rb new file mode 100755 index 0000000..e49842a --- /dev/null +++ b/ssh_keys/definitions/add_keys.rb @@ -0,0 +1,17 @@ +define :add_keys, :conf => {} do + + config = params[:conf] + name = params[:name] + keys = Mash.new + keys[name] = node[:ssh_keys][name] + + template "/home/#{name}/.ssh/authorized_keys" do + source "authorized_keys.erb" + action :create + cookbook "ssh_keys" + owner name + group config[:group] ? config[:group].to_s : name + variables(:keys => keys) + mode 0600 + end +end \ No newline at end of file diff --git a/ssh_keys/recipes/default.rb b/ssh_keys/recipes/default.rb new file mode 100755 index 0000000..e69de29 diff --git a/ssh_keys/templates/default/authorized_keys.erb b/ssh_keys/templates/default/authorized_keys.erb new file mode 100755 index 0000000..71491f4 --- /dev/null +++ b/ssh_keys/templates/default/authorized_keys.erb @@ -0,0 +1,4 @@ +<% @keys.each do |name, key| %> +# <%= name %> +<%= key %> +<% end %> \ No newline at end of file diff --git a/ssh_known_hosts/README.rdoc b/ssh_known_hosts/README.rdoc new file mode 100644 index 0000000..2b9bc68 --- /dev/null +++ b/ssh_known_hosts/README.rdoc @@ -0,0 +1,29 @@ += DESCRIPTION: + +Build /etc/ssh/known_hosts based on search indexes and build it based on data retrieved by ohai. + += REQUIREMENTS: + +== Platform: Doesn't matter, should work on anything. + += USAGE: + +Generates /etc/ssh/known_hosts based on search indexes for RSA keys. + += LICENSE and AUTHOR: + +Author:: Scott M. Likens () + +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. diff --git a/ssh_known_hosts/metadata.json b/ssh_known_hosts/metadata.json new file mode 100644 index 0000000..a6ebf95 --- /dev/null +++ b/ssh_known_hosts/metadata.json @@ -0,0 +1,53 @@ +{ + "maintainer": "Scott M. Likens", + "description": "Dyanmically generates \/etc\/ssh\/known_hosts based on search indexes", + "recommendations": { + + }, + "maintainer_email": "scott@likens.us", + "recipes": { + "ssh_known_hosts::default": "Dyanmically generates \/etc\/ssh\/known_hosts based on search indexes", + "ssh_known_hosts": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "fedora": [ + + ], + "centos": [ + + ], + "debian": [ + + ], + "redhat": [ + + ] + }, + "version": "0.1.0", + "name": "ssh_known_hosts", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "ssh_known_hosts": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "= DESCRIPTION: \n\nBuild \/etc\/ssh\/known_hosts based on search indexes and build it based on data retrieved by ohai.\n\n= REQUIREMENTS: \n\n== Platform: Doesn't matter, should work on anything.\n\n= USAGE:\n\nGenerates \/etc\/ssh\/known_hosts based on search indexes for RSA keys.\n\n= LICENSE and AUTHOR: \n\nAuthor:: Scott M. Likens ()\n\nCopyright:: 2009, Scott M. Likens\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http:\/\/www.apache.org\/licenses\/LICENSE-2.0\n \n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/ssh_known_hosts/metadata.rb b/ssh_known_hosts/metadata.rb new file mode 100644 index 0000000..dde60b3 --- /dev/null +++ b/ssh_known_hosts/metadata.rb @@ -0,0 +1,11 @@ +maintainer "Scott M. Likens" +maintainer_email "scott@likens.us" +license "Apache 2.0" +description "Dyanmically generates /etc/ssh/known_hosts based on search indexes" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.1" +recipe "ssh_known_hosts::default", "Dyanmically generates /etc/ssh/known_hosts based on search indexes" + +%w{ redhat centos fedora ubuntu debian }.each do |os| + supports os +end diff --git a/ssh_known_hosts/recipes/default.rb b/ssh_known_hosts/recipes/default.rb new file mode 100644 index 0000000..9cdda3c --- /dev/null +++ b/ssh_known_hosts/recipes/default.rb @@ -0,0 +1,31 @@ +# +# Cookbook Name:: ssh_known_hosts +# Recipe:: default +# +# 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. +# + +nodes = [] +search(:node, "*", %w{ keys_ssh_host_rsa_public ipaddress hostname }) {|n| nodes << n} + +template "/etc/ssh/ssh_known_hosts" do + source "known_hosts.erb" + mode 0440 + owner "root" + group "root" + variables( + :nodes => nodes + ) +end diff --git a/ssh_known_hosts/templates/default/known_hosts.erb b/ssh_known_hosts/templates/default/known_hosts.erb new file mode 100644 index 0000000..6dc7439 --- /dev/null +++ b/ssh_known_hosts/templates/default/known_hosts.erb @@ -0,0 +1,6 @@ +# THIS FILE IS MAINTAINED BY CHEF, DO NOT MODIFY AS IT WILL BE OVERWRITTEN +<% @nodes.each do |n| -%> + <% if n.has_key?('keys_ssh_host_rsa_public') && n['keys_ssh_host_rsa_public'].length > 0 -%> +<%= n['hostname'] %>,<%= n['ipaddress'] %> ssh-rsa <%= n['keys_ssh_host_rsa_public'] %> + <% end -%> +<% end -%> diff --git a/ssl_certificates/attributes/ssl_certificates.rb b/ssl_certificates/attributes/ssl_certificates.rb new file mode 100755 index 0000000..0b47245 --- /dev/null +++ b/ssl_certificates/attributes/ssl_certificates.rb @@ -0,0 +1 @@ +default.ssl_certificates[:path] = "/etc/ssl_certs" \ No newline at end of file diff --git a/ssl_certificates/definitions/ssl_certificate.rb b/ssl_certificates/definitions/ssl_certificate.rb new file mode 100755 index 0000000..41efd82 --- /dev/null +++ b/ssl_certificates/definitions/ssl_certificate.rb @@ -0,0 +1,34 @@ +define :ssl_certificate do + + name = params[:name] =~ /\*\.(.+)/ ? "#{$1}_wildcard" : params[:name] + + remote_file "#{node[:ssl_certificates][:path]}/#{name}.crt" do + source "#{name}.crt" + mode "0640" + cookbook "ssl_certificates" + owner "root" + group "www-data" + end + remote_file "#{node[:ssl_certificates][:path]}/#{name}.key" do + source "#{name}.key" + mode "0640" + cookbook "ssl_certificates" + owner "root" + group "www-data" + end + remote_file "#{node[:ssl_certificates][:path]}/#{name}_intermediate.crt" do + source "#{name}_intermediate.crt" + mode "0640" + cookbook "ssl_certificates" + owner "root" + group "www-data" + end + remote_file "#{node[:ssl_certificates][:path]}/#{name}_combined.crt" do + source "#{name}_combined.crt" + mode "0640" + cookbook "ssl_certificates" + owner "root" + group "www-data" + end + +end \ No newline at end of file diff --git a/ssl_certificates/metadata.json b/ssl_certificates/metadata.json new file mode 100755 index 0000000..dc13caf --- /dev/null +++ b/ssl_certificates/metadata.json @@ -0,0 +1,38 @@ +{ + "replacing": { + + }, + "long_description": "", + "attributes": { + + }, + "maintainer": "37signals", + "recommendations": { + + }, + "license": "Apache v2.0", + "recipes": { + "ssl_certificates": "" + }, + "maintainer_email": "sysadmins@37signals.com", + "suggestions": { + + }, + "dependencies": { + + }, + "conflicting": { + + }, + "platforms": { + + }, + "description": "Configures SSL certificate", + "version": "0.1.0", + "name": "ssl_certificates", + "providing": { + "ssl_certificates": [ + + ] + } +} \ No newline at end of file diff --git a/ssl_certificates/metadata.rb b/ssl_certificates/metadata.rb new file mode 100755 index 0000000..9dd92d2 --- /dev/null +++ b/ssl_certificates/metadata.rb @@ -0,0 +1,4 @@ +maintainer "37signals" +maintainer_email "sysadmins@37signals.com" +description "Configures SSL certificate" +version "0.1" diff --git a/ssl_certificates/recipes/default.rb b/ssl_certificates/recipes/default.rb new file mode 100755 index 0000000..d45ff17 --- /dev/null +++ b/ssl_certificates/recipes/default.rb @@ -0,0 +1,5 @@ +directory node[:ssl_certificates][:path] do + mode "0750" + owner "root" + group "www-data" +end \ No newline at end of file diff --git a/stompserver/metadata.json b/stompserver/metadata.json new file mode 100644 index 0000000..bc29116 --- /dev/null +++ b/stompserver/metadata.json @@ -0,0 +1,48 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs stompserver and sets up a runit_service", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "stompserver": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "debian": [ + + ] + }, + "version": "0.7.0", + "name": "stompserver", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "stompserver": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + "packages": [ + + ], + "runit": [ + + ] + } +} \ No newline at end of file diff --git a/stompserver/metadata.rb b/stompserver/metadata.rb new file mode 100644 index 0000000..9640dc9 --- /dev/null +++ b/stompserver/metadata.rb @@ -0,0 +1,13 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs stompserver and sets up a runit_service" +version "0.7" + +%w{ packages runit }.each do |cb| + depends cb +end + +%w{ ubuntu debian }.each do |os| + supports os +end diff --git a/stompserver/recipes/default.rb b/stompserver/recipes/default.rb new file mode 100644 index 0000000..1347421 --- /dev/null +++ b/stompserver/recipes/default.rb @@ -0,0 +1,44 @@ +# +# Author:: Joshua Timberman +# Cookbook Name:: stompserver +# Recipe:: default +# +# Copyright 2008-2009, Opscode, 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 "packages" + +if platform?("centos","redhat","debian","ubuntu") and dist_only? + package value_for_platform( + "centos" => { "default" => "rubygem-stompserver" }, + "redhat" => { "default" => "rubygem-stompserver" }, + "debian" => { "default" => "stompserver" }, + "ubuntu" => { "default" => "stompserver" } + ) + + service "stompserver" do + supports [ :restart, :reload, :status ] + action [ :enable, :start ] + end + + return +end + +include_recipe "runit" + +gem_package "stompserver" do + action :install +end + +runit_service "stompserver" diff --git a/stompserver/templates/default/port_stompserver.erb b/stompserver/templates/default/port_stompserver.erb new file mode 100644 index 0000000..26be7d7 --- /dev/null +++ b/stompserver/templates/default/port_stompserver.erb @@ -0,0 +1,2 @@ +# Stompserver +-A FWR -p tcp -m tcp --dport 61613 -j ACCEPT \ No newline at end of file diff --git a/stompserver/templates/default/sv-stompserver-log-run.erb b/stompserver/templates/default/sv-stompserver-log-run.erb new file mode 100644 index 0000000..9ec4380 --- /dev/null +++ b/stompserver/templates/default/sv-stompserver-log-run.erb @@ -0,0 +1,3 @@ +#!/bin/sh +exec svlogd -tt ./main + diff --git a/stompserver/templates/default/sv-stompserver-run.erb b/stompserver/templates/default/sv-stompserver-run.erb new file mode 100644 index 0000000..5d925cd --- /dev/null +++ b/stompserver/templates/default/sv-stompserver-run.erb @@ -0,0 +1,4 @@ +#!/bin/sh +PATH=/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin<% if @node[:languages][:ruby][:gems_dir] %>:<%= @node[:languages][:ruby][:gems_dir] %>/bin<% end -%> +exec 2>&1 +exec /usr/bin/env stompserver diff --git a/subversion/metadata.json b/subversion/metadata.json new file mode 100644 index 0000000..950207a --- /dev/null +++ b/subversion/metadata.json @@ -0,0 +1,52 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs subversion", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "subversion": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "fedora": [ + + ], + "centos": [ + + ], + "debian": [ + + ], + "redhat": [ + + ] + }, + "version": "0.7.0", + "name": "subversion", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "subversion": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/subversion/metadata.rb b/subversion/metadata.rb new file mode 100644 index 0000000..24916d3 --- /dev/null +++ b/subversion/metadata.rb @@ -0,0 +1,9 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs subversion" +version "0.7" + +%w{ redhat centos fedora ubuntu debian }.each do |os| + supports os +end diff --git a/subversion/recipes/default.rb b/subversion/recipes/default.rb new file mode 100644 index 0000000..814d741 --- /dev/null +++ b/subversion/recipes/default.rb @@ -0,0 +1,39 @@ +# +# Cookbook Name:: subversion +# Recipe:: default +# +# Copyright 2008-2009, Opscode, 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.0c +# +# 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 "subversion" do + action :install +end + +extra_packages = case node[:platform] + when "ubuntu","debian" + if node[:platform_version].to_f < 8.04 + %w{subversion-tools libsvn-core-perl} + else + %w{subversion-tools libsvn-perl} + end + when "centos","redhat","fedora" + %w{subversion-devel subversion-perl} + end + +extra_packages.each do |pkg| + package pkg do + action :install + end +end diff --git a/sudo/attributes/sudoers.rb b/sudo/attributes/sudoers.rb new file mode 100644 index 0000000..717d8a8 --- /dev/null +++ b/sudo/attributes/sudoers.rb @@ -0,0 +1,21 @@ +# +# Cookbook Name:: sudo +# Attribute File:: sudoers +# +# Copyright 2008-2009, Opscode, 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. +# + +set_unless[:authorization][:sudo][:groups] = Array.new +set_unless[:authorization][:sudo][:users] = Array.new diff --git a/sudo/metadata.json b/sudo/metadata.json new file mode 100644 index 0000000..c2de143 --- /dev/null +++ b/sudo/metadata.json @@ -0,0 +1,96 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs and configures sudo", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "sudo": "" + }, + "suggestions": { + + }, + "platforms": { + "freebsd": [ + + ], + "ubuntu": [ + + ], + "fedora": [ + + ], + "centos": [ + + ], + "debian": [ + + ], + "redhat": [ + + ] + }, + "version": "0.7.0", + "name": "sudo", + "conflicting": { + + }, + "attributes": { + "authorization\/sudoers\/groups": { + "default": "", + "type": "array", + "multiple_values": false, + "description": "Groups who are allowed sudo ALL", + "display_name": "Sudo Groups", + "recipes": [ + + ], + "required": false + }, + "authorization\/sudoers\/users": { + "default": "", + "type": "array", + "multiple_values": false, + "description": "Users who are allowed sudo ALL", + "display_name": "Sudo Users", + "recipes": [ + + ], + "required": false + }, + "authorization\/sudoers": { + "type": "hash", + "multiple_values": false, + "description": "Hash of Authorization\/Sudoers attributes", + "display_name": "Authorization Sudoers", + "recipes": [ + + ], + "required": false + }, + "authorization": { + "type": "hash", + "multiple_values": false, + "description": "Hash of Authorization attributes", + "display_name": "Authorization", + "recipes": [ + + ], + "required": false + } + }, + "providing": { + "sudo": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/sudo/metadata.rb b/sudo/metadata.rb new file mode 100644 index 0000000..88e9476 --- /dev/null +++ b/sudo/metadata.rb @@ -0,0 +1,31 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs and configures sudo" +version "0.7" + +%w{redhat centos fedora ubuntu debian freebsd}.each do |os| + supports os +end + +attribute "authorization", + :display_name => "Authorization", + :description => "Hash of Authorization attributes", + :type => "hash" + +attribute "authorization/sudoers", + :display_name => "Authorization Sudoers", + :description => "Hash of Authorization/Sudoers attributes", + :type => "hash" + +attribute "authorization/sudoers/users", + :display_name => "Sudo Users", + :description => "Users who are allowed sudo ALL", + :type => "array", + :default => "" + +attribute "authorization/sudoers/groups", + :display_name => "Sudo Groups", + :description => "Groups who are allowed sudo ALL", + :type => "array", + :default => "" diff --git a/sudo/recipes/default.rb b/sudo/recipes/default.rb new file mode 100644 index 0000000..cbd92f1 --- /dev/null +++ b/sudo/recipes/default.rb @@ -0,0 +1,33 @@ +# +# Cookbook Name:: sudo +# Recipe:: default +# +# Copyright 2008-2009, Opscode, 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 "sudo" do + action :upgrade +end + +template "/etc/sudoers" do + source "sudoers.erb" + mode 0440 + owner "root" + group "root" + variables( + :sudoers_groups => node[:authorization][:sudo][:groups], + :sudoers_users => node[:authorization][:sudo][:users] + ) +end diff --git a/sudo/templates/default/sudoers.erb b/sudo/templates/default/sudoers.erb new file mode 100644 index 0000000..99ce129 --- /dev/null +++ b/sudo/templates/default/sudoers.erb @@ -0,0 +1,22 @@ +# +# /etc/sudoers +# +# Generated by Chef for <%= @node[:fqdn] %> +# + +Defaults !lecture,tty_tickets,!fqdn + +# User privilege specification +root ALL=(ALL) ALL + +<% @sudoers_users.each do |user| -%> +<%= user %> ALL=(ALL) ALL +<% end -%> + +# Members of the sysadmin group may gain root privileges +%sysadmin ALL=(ALL) ALL + +<% @sudoers_groups.each do |group| -%> +# Members of the group '<%= group %>' may gain root privileges +%<%= group %> ALL=(ALL) ALL +<% end -%> \ No newline at end of file diff --git a/sysadmin/files/default/memory_stats b/sysadmin/files/default/memory_stats new file mode 100755 index 0000000..0e8d918 --- /dev/null +++ b/sysadmin/files/default/memory_stats @@ -0,0 +1,279 @@ +#!/usr/bin/env ruby +# Adopted from Phusion Passenger - http://www.modrails.com/ +# Copyright (c) 2008, 2009 Phusion, 37signals +# +# "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# ANSI color codes +RESET = "\e[0m" +BOLD = "\e[1m" +WHITE = "\e[37m" +YELLOW = "\e[33m" +BLUE_BG = "\e[44m" + +# Container for tabular data. +class Table + def initialize(column_names) + @column_names = column_names + @rows = [] + end + + def add_row(values) + @rows << values.to_a + end + + def add_rows(list_of_rows) + list_of_rows.each do |row| + add_row(row) + end + end + + def remove_column(name) + i = @column_names.index(name) + @column_names.delete_at(i) + @rows.each do |row| + row.delete_at(i) + end + end + + def to_s(title = nil) + max_column_widths = [1] * @column_names.size + (@rows + [@column_names]).each do |row| + row.each_with_index do |value, i| + max_column_widths[i] = [value.to_s.size, max_column_widths[i]].max + end + end + + format_string = max_column_widths.map{ |i| "%#{-i}s" }.join(" ") + header = sprintf(format_string, *@column_names).rstrip << "\n" + if title + free_space = header.size - title.size - 2 + if free_space <= 0 + left_bar_size = 3 + right_bar_size = 3 + else + left_bar_size = free_space / 2 + right_bar_size = free_space - left_bar_size + end + result = "#{BLUE_BG}#{BOLD}#{YELLOW}" + result << "#{"-" * left_bar_size} #{title} #{"-" * right_bar_size}\n" + if !@rows.empty? + result << WHITE + result << header + end + else + result = header.dup + end + if @rows.empty? + result << RESET + else + result << ("-" * header.size) << "#{RESET}\n" + @rows.each do |row| + result << sprintf(format_string, *row).rstrip << "\n" + end + end + result + end +end + +class MemoryStats + class Process + attr_accessor :pid + attr_accessor :ppid + attr_accessor :threads + attr_accessor :vm_size # in KB + attr_accessor :rss # in KB + attr_accessor :name + attr_accessor :private_dirty_rss # in KB + + def vm_size_in_mb + return sprintf("%.1f MB", vm_size / 1024.0) + end + + def rss_in_mb + return sprintf("%.1f MB", rss / 1024.0) + end + + def private_dirty_rss_in_mb + if private_dirty_rss.is_a?(Numeric) + return sprintf("%.1f MB", private_dirty_rss / 1024.0) + else + return "?" + end + end + + def to_a + return [pid, ppid, threads, vm_size_in_mb, private_dirty_rss_in_mb, rss_in_mb, name] + end + end + + def start(match = 'rails') + procs = list_processes(:match => match).delete_if {|p| p.pid == ::Process.pid } + if !procs.empty? + if ::Process.uid != 0 && procs.any?{ |p| p.private_dirty_rss.nil? } + puts + puts "*** WARNING: Please run this tool as root. Otherwise the " << + "private dirty RSS of processes cannot be determined." + end + print_process_list("#{match}", procs) + else + puts "No processes found matching '#{match}'" + end + end + + # Returns a list of Process objects that match the given search criteria. + # + # # Search by executable path. + # list_processes(:exe => '/usr/sbin/apache2') + # + # # Search by executable name. + # list_processes(:name => 'ruby1.8') + # + # # Search by process name. + # list_processes(:match => 'Passenger FrameworkSpawner') + def list_processes(options) + if options[:exe] + name = options[:exe].sub(/.*\/(.*)/, '\1') + if RUBY_PLATFORM =~ /linux/ + ps = "ps -C '#{name}'" + else + ps = "ps -A" + options[:match] = Regexp.new(Regexp.escape(name)) + end + elsif options[:name] + if RUBY_PLATFORM =~ /linux/ + ps = "ps -C '#{options[:name]}'" + else + ps = "ps -A" + options[:match] = Regexp.new(" #{Regexp.escape(options[:name])}") + end + elsif options[:match] + ps = "ps -A" + else + raise ArgumentError, "Invalid options." + end + + processes = [] + case RUBY_PLATFORM + when /solaris/ + list = `#{ps} -o pid,ppid,nlwp,vsz,rss,comm`.split("\n") + threads_known = true + when /darwin/ + list = `#{ps} -w -o pid,ppid,vsz,rss,command`.split("\n") + threads_known = false + else + list = `#{ps} -w -o pid,ppid,nlwp,vsz,rss,command`.split("\n") + threads_known = true + end + list.shift + list.each do |line| + line.gsub!(/^ */, '') + line.gsub!(/ *$/, '') + + p = Process.new + if threads_known + p.pid, p.ppid, p.threads, p.vm_size, p.rss, p.name = line.split(/ +/, 6) + else + p.pid, p.ppid, p.vm_size, p.rss, p.name = line.split(/ +/, 5) + p.threads = "?" + end + p.name.sub!(/\Aruby: /, '') + p.name.sub!(/ \(ruby\)\Z/, '') + if p.name !~ /^ps/ && (!options[:match] || p.name.match(options[:match])) + # Convert some values to integer. + [:pid, :ppid, :vm_size, :rss].each do |attr| + p.send("#{attr}=", p.send(attr).to_i) + end + p.threads = p.threads.to_i if threads_known + + if platform_provides_private_dirty_rss_information? + p.private_dirty_rss = determine_private_dirty_rss(p.pid) + end + processes << p + end + end + return processes + end + +private + def platform_provides_private_dirty_rss_information? + return RUBY_PLATFORM =~ /linux/ + end + + # Returns the private dirty RSS for the given process, in KB. + def determine_private_dirty_rss(pid) + total = 0 + File.read("/proc/#{pid}/smaps").split("\n").each do |line| + line =~ /^(Private)_Dirty: +(\d+)/ + if $2 + total += $2.to_i + end + end + if total == 0 + return nil + else + return total + end + rescue Errno::EACCES, Errno::ENOENT + return nil + end + + def print_process_list(title, processes, options = {}) + table = Table.new(%w{PID PPID Threads VMSize Private Resident Name}) + table.add_rows(processes) + if options.has_key?(:show_ppid) && !options[:show_ppid] + table.remove_column('PPID') + end + if platform_provides_private_dirty_rss_information? + table.remove_column('Resident') + else + table.remove_column('Private') + end + puts table.to_s(title) + + if platform_provides_private_dirty_rss_information? + total_private_dirty_rss = 0 + some_private_dirty_rss_cannot_be_determined = false + processes.each do |p| + if p.private_dirty_rss.is_a?(Numeric) + total_private_dirty_rss += p.private_dirty_rss + else + some_private_dirty_rss_cannot_be_determined = true + end + end + puts "### Processes: #{processes.size}" + printf "### Total private dirty RSS: %.2f MB", total_private_dirty_rss / 1024.0 + if some_private_dirty_rss_cannot_be_determined + puts " (?)" + else + puts + end + end + end +end + +if !ARGV[0] + puts "Prints memory usage stats for processes whose title matches " + puts "Usage: memory_stats " + exit 1 +end + +MemoryStats.new.start(ARGV[0]) \ No newline at end of file diff --git a/sysadmin/recipes/default.rb b/sysadmin/recipes/default.rb new file mode 100755 index 0000000..c7bb776 --- /dev/null +++ b/sysadmin/recipes/default.rb @@ -0,0 +1,39 @@ +case node[:platform] +when "debian", "ubuntu" + package "policykit" + package "emacs22-nox" + require_recipe "apt" +else + package "emacs-nox" +end + +package "vim" +package "curl" +package "man-db" +package "strace" +package "host" +package "lsof" +package "gdb" +package "socat" +package "procmail" +package "zsh" +package "ack" + +directory "/u/system" do + owner "root" + group "admin" + mode 0755 +end + +directory "/u/system/bin" do + owner "root" + group "admin" + mode 0755 +end + +%w(memory_stats rotate-email-folders rotate-misc-log rotate-db-backups).each do |file| + remote_file "/usr/local/bin/#{file}" do + source file + mode 0755 + end +end diff --git a/sysctl/attributes/sysctl.rb b/sysctl/attributes/sysctl.rb new file mode 100755 index 0000000..39c86b5 --- /dev/null +++ b/sysctl/attributes/sysctl.rb @@ -0,0 +1 @@ +sysctl Mash.new unless attribute?(:sysctl) diff --git a/sysctl/recipes/default.rb b/sysctl/recipes/default.rb new file mode 100755 index 0000000..0369f1d --- /dev/null +++ b/sysctl/recipes/default.rb @@ -0,0 +1,8 @@ +service "procps" + +if node[:sysctl][:settings] + template "/etc/sysctl.d/60-custom-settings.conf" do + source "60-custom-settings.conf.erb" + notifies :restart, resources(:service => "procps") + end +end \ No newline at end of file diff --git a/sysctl/templates/default/60-custom-settings.conf.erb b/sysctl/templates/default/60-custom-settings.conf.erb new file mode 100755 index 0000000..22f59a4 --- /dev/null +++ b/sysctl/templates/default/60-custom-settings.conf.erb @@ -0,0 +1,6 @@ +# Custom kernel parameter settings +# Automatically generated by chef - local changes will be overwritten +# +<% @node[:sysctl][:settings].each do |k, v| %> +<%= k %> = <%= v %> +<% end %> \ No newline at end of file diff --git a/syslog/attributes/default.rb b/syslog/attributes/default.rb new file mode 100755 index 0000000..e3932e0 --- /dev/null +++ b/syslog/attributes/default.rb @@ -0,0 +1,2 @@ +syslog_ng Mash.new unless attribute?("syslog_ng") +syslog_ng[:root] = "/u/logs" \ No newline at end of file diff --git a/syslog/files/default/logsort b/syslog/files/default/logsort new file mode 100755 index 0000000..0a5ce88 Binary files /dev/null and b/syslog/files/default/logsort differ diff --git a/syslog/libraries/default.rb b/syslog/libraries/default.rb new file mode 100755 index 0000000..e5619a2 --- /dev/null +++ b/syslog/libraries/default.rb @@ -0,0 +1,3 @@ +def root + @node[:syslog_ng][:root] +end \ No newline at end of file diff --git a/syslog/metadata.json b/syslog/metadata.json new file mode 100755 index 0000000..449fa4d --- /dev/null +++ b/syslog/metadata.json @@ -0,0 +1,48 @@ +{ + "replacing": { + + }, + "long_description": "", + "attributes": { + + }, + "maintainer": "37signals", + "recommendations": { + + }, + "license": "Apache v2.0", + "recipes": { + "syslog::client": "", + "syslog::server": "", + "syslog": "" + }, + "maintainer_email": "sysadmins@37signals.com", + "suggestions": { + + }, + "dependencies": { + "logrotate": [ + + ] + }, + "conflicting": { + + }, + "platforms": { + + }, + "description": "Configures syslog", + "version": "0.1.0", + "name": "syslog", + "providing": { + "syslog": [ + + ], + "syslog::client": [ + + ], + "syslog::server": [ + + ] + } +} \ No newline at end of file diff --git a/syslog/metadata.rb b/syslog/metadata.rb new file mode 100755 index 0000000..9abc646 --- /dev/null +++ b/syslog/metadata.rb @@ -0,0 +1,5 @@ +maintainer "37signals" +maintainer_email "sysadmins@37signals.com" +description "Configures syslog" +version "0.1" +depends "logrotate" \ No newline at end of file diff --git a/syslog/recipes/client.rb b/syslog/recipes/client.rb new file mode 100755 index 0000000..a4a8e97 --- /dev/null +++ b/syslog/recipes/client.rb @@ -0,0 +1,10 @@ +require_recipe "syslog" + +template "/etc/syslog-ng/syslog-ng.conf" do + source "syslog-ng-client.conf.erb" + owner "root" + group "root" + mode 0644 + notifies :restart, resources(:service => "syslog-ng") + not_if { @node.recipes.include?("syslog::server") } +end \ No newline at end of file diff --git a/syslog/recipes/default.rb b/syslog/recipes/default.rb new file mode 100755 index 0000000..a056139 --- /dev/null +++ b/syslog/recipes/default.rb @@ -0,0 +1,8 @@ +package "syslog-ng" do + action :install +end + +service "syslog-ng" do + supports :restart => true, :reload => true + action [:enable, :start] +end \ No newline at end of file diff --git a/syslog/recipes/server.rb b/syslog/recipes/server.rb new file mode 100755 index 0000000..87689fe --- /dev/null +++ b/syslog/recipes/server.rb @@ -0,0 +1,51 @@ +require_recipe "syslog" + +template "/etc/syslog-ng/syslog-ng.conf" do + source "syslog-ng-server.conf.erb" + owner "root" + group "root" + mode 0644 + notifies :restart, resources(:service => "syslog-ng") + variables(:applications => node[:applications]) +end + +remote_file "/usr/local/bin/logsort" do + source "logsort" + mode 0755 +end + +if node[:applications] + node[:applications].each do |app, config| + directory node[:syslog_ng][:root] + "/#{app}" do + owner "app" + group "app" + mode 0750 + end + end + logrotate "applications" do + restart_command "/etc/init.d/syslog-ng reload 2>&1 || true" + files node[:applications].keys.collect{|name| root+"/#{name}/*.log" } + frequency "daily" + end +end + +directory node[:syslog_ng][:root] + "/syslog" do + owner "root" + group "app" + mode 0750 +end + +logrotate "syslog-remote" do + restart_command "/etc/init.d/syslog-ng reload 2>&1 || true" + files ['/u/logs/syslog/messages', "/u/logs/syslog/secure", "/u/logs/syslog/maillog", "/u/logs/syslog/cron", "/u/logs/syslog/bluepill"] +end + +node[:applications].each do |app, config| + next unless !config[:syslog_files].nil? && config[:syslog_files][:logsort] + + cron "logsort log rotation: #{app}" do + command "find /u/logs/#{app} -maxdepth 1 -type d -mtime +7 -exec rm -rf {} \\;" + hour "10" + minute "0" + end +end diff --git a/syslog/templates/default/syslog-ng-client.conf.erb b/syslog/templates/default/syslog-ng-client.conf.erb new file mode 100755 index 0000000..f743d8f --- /dev/null +++ b/syslog/templates/default/syslog-ng-client.conf.erb @@ -0,0 +1,29 @@ +# Generic syslog-ng configuration. Logs everything to noc. + +options { + chain_hostnames(off); + sync(0); + stats(43200); + log_msg_size(65534); +}; + +source src { + unix-stream("/dev/log" max-connections(256)); + internal(); + pipe("/proc/kmsg"); +}; + +destination d_loghost { tcp("192.168.1.153", port(5140)); }; +destination d_null { file("/dev/null.syslog"); }; +destination messages { file("/var/log/messages"); }; + +# Block SyslogNG message overflow warnings +filter f_syslog_overflow { program("syslog-ng") and match("length overflow"); }; +log { source(src); filter(f_syslog_overflow); destination(d_null); flags(final); }; + +# Block Postfix entries related to the loadbalancer +filter f_smtp_health { program("postfix") and match("192.168.1.153"); }; +log { source(src); filter(f_smtp_health); destination(d_null); flags(final); }; + +# Log everything through the log host so we can centralize Xen monitoring. +log { source(src); destination(d_loghost); }; diff --git a/syslog/templates/default/syslog-ng-server.conf.erb b/syslog/templates/default/syslog-ng-server.conf.erb new file mode 100755 index 0000000..45e3305 --- /dev/null +++ b/syslog/templates/default/syslog-ng-server.conf.erb @@ -0,0 +1,152 @@ +# syslog-ng configuration file. +# + +options { + time_reopen (10); + log_fifo_size (5000); + long_hostnames (off); + use_dns (yes); + use_fqdn (no); + create_dirs (no); + keep_hostname (yes); + flush_lines (1); + stats_freq (600); +}; + +source s_sys { + file ("/proc/kmsg" log_prefix("kernel: ")); + unix-stream ("/dev/log"); + internal(); +}; + +source s_remote { + udp(ip(0.0.0.0) port(514)); + tcp(ip(0.0.0.0) port(5140) max-connections(256) so_rcvbuf(8192) so_keepalive(yes)); +}; + +destination d_cons { file("/dev/console"); }; +destination d_mesg { file("/var/log/messages"); }; +destination d_auth { file("/var/log/secure"); }; +destination d_mail { file("/var/log/maillog" sync(10)); }; +destination d_spol { file("/var/log/spooler"); }; +destination d_boot { file("/var/log/boot.log"); }; +destination d_cron { file("/var/log/cron"); }; +destination d_mlal { usertty("*"); }; + +#filter f_filter1 { facility(kern); }; +filter f_filter2 { level(info..emerg) and not facility(mail,authpriv,cron); }; +filter f_filter3 { facility(authpriv); }; +filter f_filter4 { facility(mail); }; +filter f_filter5 { level(emerg); }; +filter f_filter6 { facility(uucp) or (facility(news) and level(crit..emerg)); }; +filter f_filter7 { facility(local7); }; +filter f_filter8 { facility(cron); }; +filter f_local0 { facility(local0); }; +filter f_local1 { facility(local1); }; +filter f_local2 { facility(local2); }; +filter f_local3 { facility(local3); }; +filter f_local4 { facility(local4); }; +filter f_local5 { facility(local5); }; +filter f_local6 { facility(local6); }; +filter f_local7 { facility(local7); }; + +filter f_exceptions { match("System Notifier"); }; +destination exceptions { file("/u/logs/exceptions.log", owner(app), group(app), perm(0640)); }; +log { source(s_remote); filter(f_exceptions); destination(exceptions); }; + +# filter HAProxy logs +filter f_haproxy { program("haproxy"); }; + +# filter passenger monitor logs +filter f_passenger { program("passenger"); }; +destination passenger_monitor { file("/u/logs/passenger_monitor.log", owner(app), group(app), perm(0640)); }; +log { source(s_remote); filter(f_passenger); destination(passenger_monitor); flags(final); }; + +# filter Rails apps +filter f_completed_in { match("Completed in"); }; +filter f_thumbnail_build { match("thumbnail\.build"); }; +filter f_memcache { match("MemCacheStore"); }; +filter f_uploader { match("Uploader"); }; + +<% @applications.each do |app, config| %> + +<% if config[:syslog_send_to_host] && @node[:ipaddress] != config[:syslog_send_to_host] %> +# send <%= app %> logs to another host +destination loghost_<%= app %> { tcp("<%= config[:syslog_send_to_host] %>", port(5140)); }; +log { source(s_remote); filter(f_<%= app %>); destination(loghost_<%= app %>); }; +<% end %> + +<% config[:syslog_files] ||= Mash.new %> +<% if config[:syslog_files][:haproxy] %> +destination d_<%= app %>_haproxy { file("/u/logs/<%= app %>/haproxy.log", owner(app), group(app), perm(0640)); }; +filter f_<%= app %>_haproxy { program("haproxy") and match("<%= app %>"); }; +log { source(s_remote); filter(f_local1); filter(f_haproxy); filter(f_<%= app %>_haproxy); destination(d_<%= app %>_haproxy); flags(final); }; +<% end %> + +filter f_<%= app %> { program("<%= app %>"); }; + +<% if config[:syslog_files][:completed] %> +destination <%= app %>_completed { file("/u/logs/<%= app %>/completed.log", owner(app), group(app), perm(0640)); }; +log { source(s_remote); filter(f_<%= app %>); filter(f_completed_in); destination(<%= app %>_completed); }; +<% end %> + +<% if config[:syslog_files][:thumbnails] %> +destination <%= app %>_thumbnails { file("/u/logs/<%= app %>/thumbnails.log", owner(app), group(app), perm(0640)); }; +log { source(s_remote); filter(f_<%= app %>); filter(f_thumbnail_build); destination(<%= app %>_thumbnails); }; +<% end %> + +<% if config[:syslog_files][:memcache] %> +destination <%= app %>_memcache { file("/u/logs/<%= app %>/memcache.log", owner(app), group(app), perm(0640)); }; +log { source(s_remote); filter(f_<%= app %>); filter(f_memcache); destination(<%= app %>_memcache); }; +<% end %> + +<% if config[:syslog_files][:uploader] %> +destination <%= app %>_uploader { file("/u/logs/<%= app %>/uploader.log", owner(app), group(app), perm(0640)); }; +log { source(s_remote); filter(f_<%= app %>); filter(f_uploader); destination(<%= app %>_uploader); }; +<% end %> + +<% if config[:syslog_files][:logsort] %> +destination <%= app %>_logsort { program("/u/apps/<%= app %>/shared/bin/logsort", log_fifo_size(30000)); }; +log { source(s_remote); filter(f_<%= app %>); destination(<%= app %>_logsort); flags(final); }; +<% else %> +destination <%= app %> { file("/u/logs/<%= app %>/rails.log", owner(app), group(app), perm(0640)); }; +log { source(s_remote); filter(f_<%= app %>); destination(<%= app %>); flags(final); }; +<% end %> + +<% end %> + + +# Standard system logging +log { source(s_sys); filter(f_filter2); destination(d_mesg); }; +log { source(s_sys); filter(f_filter3); destination(d_auth); }; +log { source(s_sys); filter(f_filter4); destination(d_mail); }; +log { source(s_sys); filter(f_filter5); destination(d_mlal); }; +log { source(s_sys); filter(f_filter6); destination(d_spol); }; +log { source(s_sys); filter(f_filter7); destination(d_boot); }; +log { source(s_sys); filter(f_filter8); destination(d_cron); }; + +# Bluepill Monitors +filter f_bluepill { program("bluepilld"); }; +destination d_bluepill { file("/u/logs/syslog/bluepill", owner(root), group(app), perm(0640)); }; +log { source(s_remote); filter(f_local6); filter(f_bluepill); destination(d_bluepill); flags(final); }; + +# Cisco Load Balancer +destination d_cisco { file("/u/logs/syslog/cisco", owner(root), group(app), perm(0640)); }; +log { source(s_remote); filter(f_local6); destination(d_cisco); flags(final); }; + + +# Remote system logging +destination d_mesg_remote { file("/u/logs/syslog/messages", owner(root), group(app), perm(0640)); }; +destination d_auth_remote { file("/u/logs/syslog/secure", owner(root), group(app), perm(0640)); }; +destination d_mail_remote { file("/u/logs/syslog/maillog", owner(root), group(app), perm(0640), sync(10)); }; +destination d_spol_remote { file("/u/logs/syslog/spooler", owner(root), group(app), perm(0640)); }; +destination d_boot_remote { file("/u/logs/syslog/boot.log", owner(root), group(app), perm(0640)); }; +destination d_cron_remote { file("/u/logs/syslog/cron", owner(root), group(app), perm(0640)); }; + +log { source(s_remote); filter(f_filter2); destination(d_mesg_remote); }; +log { source(s_remote); filter(f_filter3); destination(d_auth_remote); }; +log { source(s_remote); filter(f_filter4); destination(d_mail_remote); }; +log { source(s_remote); filter(f_filter6); destination(d_spol_remote); }; +log { source(s_remote); filter(f_filter7); destination(d_boot_remote); }; +log { source(s_remote); filter(f_filter8); destination(d_cron_remote); }; + diff --git a/teamspeak/metadata.json b/teamspeak/metadata.json new file mode 100644 index 0000000..8473b23 --- /dev/null +++ b/teamspeak/metadata.json @@ -0,0 +1,42 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs teamspeak and enables service", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "teamspeak": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ] + }, + "version": "0.8.0", + "name": "teamspeak", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "teamspeak": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + "php": [ + + ] + } +} \ No newline at end of file diff --git a/teamspeak/metadata.rb b/teamspeak/metadata.rb new file mode 100644 index 0000000..d7c95c2 --- /dev/null +++ b/teamspeak/metadata.rb @@ -0,0 +1,7 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs teamspeak and enables service" +version "0.8" +depends "php" +supports "ubuntu" diff --git a/teamspeak/recipes/default.rb b/teamspeak/recipes/default.rb new file mode 100644 index 0000000..12100f4 --- /dev/null +++ b/teamspeak/recipes/default.rb @@ -0,0 +1,73 @@ +# +# Author:: Joshua Timberman +# Cookbook Name:: teamspeak +# Recipe:: default +# +# Copyright 2008-2009, Joshua Timberman +# +# 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 "teamspeak-server" + +service "teamspeak-server" do + action :enable +end + +ts_server = "teamspeak.#{node[:domain]}" + +template "/etc/teamspeak-server/server.ini" do + source "server.ini.erb" + owner "teamspeak-server" + group "teamspeak-server" + mode "0600" +end + +include_recipe "php::php5" +include_recipe "apache2::mod_php5" + +directory "/srv/www/tsdisplay" do + action :create + recursive true + owner "www-data" + group "www-data" + mode "755" +end + +bash "install tsdisplay" do + cwd "/srv/www/tsdisplay" + code <<-EOH +wget http://softlayer.dl.sourceforge.net/sourceforge/tsdisplay/TeamspeakDisplay-PR3.zip +unzip TeamSpeakDisplay-PR3.zip +EOH + not_if { File.exists?("/srv/www/tsdisplay/TeamspeakDisplay-PR3.zip") } +end + +template "/srv/www/tsdisplay/demo.php" do + source "demo.php.erb" + owner "www-data" + group "www-data" + mode "644" + variables :ts_server => ts_server +end + +template "/etc/apache2/sites-available/teamspeak.conf" do + source "teamspeak.conf.erb" + owner "root" + group "root" + mode "644" + variables :virtual_host_name => ts_server, :docroot => "/srv/www/tsdisplay" +end + +apache_site "teamspeak.conf" do + enable :true +end diff --git a/teamspeak/templates/default/demo.php.erb b/teamspeak/templates/default/demo.php.erb new file mode 100644 index 0000000..3d15680 --- /dev/null +++ b/teamspeak/templates/default/demo.php.erb @@ -0,0 +1,94 @@ + + + + Teamspeak Display Demo + + + +\n"); + } +?> + + +

Demo:

+Error reporting "); + //echo("is currently on. Turn it off in live environments !

\n"); + //error_reporting(E_ALL); + //ini_set("display_errors", "1"); + //ini_set("display_startup_errors", "1"); + //ini_set("ignore_repeated_errors", "0"); + //ini_set("ignore_repeated_source", "0"); + //ini_set("report_memleaks", "1"); + //ini_set("track_errors", "1"); + //ini_set("html_errors", "1"); + //ini_set("warn_plus_overloading", "1"); + //================== END OF ERROR REPORTING CODE ====================== + + // Load the Teamspeak Display: + require("teamspeakdisplay/teamspeakdisplay.php"); + + // Get the default settings + $settings = $teamspeakDisplay->getDefaultSettings(); + + //================== BEGIN OF CONFIGURATION CODE ====================== + + // Set the teamspeak server IP or Hostname below (DO NOT INCLUDE THE + // PORT NUMBER): + $settings["serveraddress"] = "<%= @ts_server %>"; + + // If your you use another port than 8767 to connect to your teamspeak + // server using a teamspeak client, then uncomment the line below and + // set the correct teamspeak port: + //$settings["serverudpport"] = 8767; + + // If your teamspeak server uses another query port than 51234, then + // uncomment the line below and set the teamspeak query port of your + // server (look in the server.ini of your teamspeak server for this + // portnumber): + //$settings["serverqueryport"] = 51234; + + // If you want to limit the display to only one channel including it's + // players and subchannels, uncomment the following line and set the + // exact name of the channel. This feature is case-sensitive! + //$settings["limitchannel"] = ""; + + // If your teamspeak server uses another set of forbidden nickname + // characters than "()[]{}" (look in your server.ini for this setting), + // then uncomment the following line and set the correct set of + // forbidden nickname characters: + //$settings["forbiddennicknamechars"] = "()[]{}"; + + //================== END OF CONFIGURATION CODE ======================== + + // Is the script improperly configured? + if ($settings["serveraddress"] == "") { die("You need to configure this script as described inside the CONFIGURATION CODE block in " . $_SERVER["PHP_SELF"] . "
\n"); } + + // Display the Teamspeak server + $teamspeakDisplay->displayTeamspeakEx($settings); + + // Display autorefresh status and control link: + echo("
\n"); + if ($autorefresh == 0) { + echo("Autorefresh: Off (Turn on)
\n"); + } else if ($autorefresh == 1) { + echo("Autorefresh: On (Turn off)
\n"); + } +?> +
+ Powered by Teamspeak Display
+ + \ No newline at end of file diff --git a/teamspeak/templates/default/port_teamspeak.erb b/teamspeak/templates/default/port_teamspeak.erb new file mode 100644 index 0000000..942570e --- /dev/null +++ b/teamspeak/templates/default/port_teamspeak.erb @@ -0,0 +1,4 @@ +# Teamspeak +-A FWR -p udp -m udp --dport 8767 -j ACCEPT +-A FWR -p tcp -m tcp --dport 51234 -j ACCEPT +-A FWR -p tcp -m tcp --dport 14534 -j ACCEPT \ No newline at end of file diff --git a/teamspeak/templates/default/server.ini.erb b/teamspeak/templates/default/server.ini.erb new file mode 100644 index 0000000..9c000b2 --- /dev/null +++ b/teamspeak/templates/default/server.ini.erb @@ -0,0 +1,38 @@ +[Main Config] +BoundToIp1= +ExternalIPDectection=1 +HTTPServer Port=<%= @node[:teamspeak][:http_port] %> +HTTPServer Enabled=1 +DateTimeFormat=dd-mm-yyyy hh:nn:ss +TCPQueryPort=<%= @node[:teamspeak][:query_port] %> +AllowedClientNameChars= +DisAllowedClientNameChars=()[]{} + +[debug] +MessageTypes=LMTALL +MessageDepths=LMDALL + +[WebPost] +AdminEmail=gaming@housepub.org +ISPLinkURL=na +ISPName=Private +ISPCountryNumber=0 +Enabled=1 +PostURL= +ListPublic=0 +UserAgent=teamspeak + +[log] +access_r=0 +access_u=0 +channel_registerred=0 +channel_unregisterred=0 +sa=0 +chat=0 +kick_server=0 +kick_channel=0 + +[Spam] +max_commands=10 +in_seconds=2 + diff --git a/teamspeak/templates/default/teamspeak.conf.erb b/teamspeak/templates/default/teamspeak.conf.erb new file mode 100644 index 0000000..3027e30 --- /dev/null +++ b/teamspeak/templates/default/teamspeak.conf.erb @@ -0,0 +1,30 @@ + + + DocumentRoot <%= @docroot %> + + ServerName <%= @virtual_host_name %> + ServerAlias <%= @virtual_host_name.split('.')[0] %> + + + Options FollowSymLinks + AllowOverride None + + + LogLevel info + ErrorLog /var/log/apache2/teamspeak-error.log + CustomLog /var/log/apache2/teamspeak-access.log combined + + RewriteEngine On + RewriteLog /var/log/apache2/teamspeak-rewrite.log + RewriteLogLevel 0 + + > + Options Indexes FollowSymLinks MultiViews + AllowOverride All + Order allow,deny + allow from all + + + AddOutputFilterByType DEFLATE text/html text/plain text/xml + + diff --git a/thin/attributes/thin.rb b/thin/attributes/thin.rb new file mode 100755 index 0000000..2089a82 --- /dev/null +++ b/thin/attributes/thin.rb @@ -0,0 +1,2 @@ +default.thin[:version] = "1.2.5" +default.thin[:persistent_connections] = true \ No newline at end of file diff --git a/thin/metadata.rb b/thin/metadata.rb new file mode 100755 index 0000000..404f071 --- /dev/null +++ b/thin/metadata.rb @@ -0,0 +1,7 @@ +maintainer "thin" +maintainer_email "sysadmins@37signals.com" +description "Configures thin, a Ruby web server" +version "0.1" +depends "ruby" +depends "nginx" +depends "apache2" diff --git a/thin/recipes/default.rb b/thin/recipes/default.rb new file mode 100755 index 0000000..d1e7101 --- /dev/null +++ b/thin/recipes/default.rb @@ -0,0 +1,3 @@ +gem_package "thin" do + version node[:thin][:version] +end \ No newline at end of file diff --git a/thin/templates/default/bluepill.conf.erb b/thin/templates/default/bluepill.conf.erb new file mode 100755 index 0000000..3bd2926 --- /dev/null +++ b/thin/templates/default/bluepill.conf.erb @@ -0,0 +1,36 @@ +require 'yaml' +config_path = "<%= @rails_root %>/config/thin/<%= @rails_env %>.yml" +config = YAML.load_file(config_path) +num_servers = config["servers"] ||= 1 + +Bluepill.application("<%= @name %>", :log_file => "<%= @rails_root %>/log/thin_bluepill.log") do |app| + + (0...num_servers).each do |i| + + # UNIX socket cluster use number 0 to 2 (for 3 servers) + # and tcp cluster use port number 3000 to 3002. + number = config['socket'] ? i : (config['port'] + i) + + app.process("<%= @name %>-#{number}") do |process| + process.group = "thins" + process.start_command = "<%= "#{@node[:ruby][:bin_dir]}/thin" %> start -C #{config_path} -o #{number}" + <% if @node[:thin][:persistent_connections] %> + # since we use persistent connections, we must forcefully kill these processes that would otherwise receive a QUIT for graceful killing + process.stop_command = "kill -TERM {{PID}}" + <% else %> + process.stop_command = "<%= "#{@node[:ruby][:bin_dir]}/thin" %> stop -C #{config_path} -o #{number}" + process.restart = "<%= "#{@node[:ruby][:bin_dir]}/thin" %> restart -C #{config_path} -o #{number}" + <% end %> + process.stdout = process.stderr = "<%= @rails_root %>/log/thin.log" + process.pid_file = "<%= @rails_root %>/tmp/pids/thin.#{number}.pid" + process.checks :mem_usage, :every => 10.seconds, :below => <%= @memory_limit %>.megabytes, :times => [3, 5] + process.uid = "<%= @user %>" + process.gid = "<%= @group %>" + + process.start_grace_time = 10.seconds + process.restart_grace_time = 10.seconds + + process.checks :flapping, :times => 2, :within => 30.seconds, :retry_in => 7.seconds + end + end +end \ No newline at end of file diff --git a/thrift/README.rdoc b/thrift/README.rdoc new file mode 100644 index 0000000..f4a8de9 --- /dev/null +++ b/thrift/README.rdoc @@ -0,0 +1,42 @@ += DESCRIPTION: + +Installs Thrift from source. + += REQUIREMENTS: + +== Platform: + +Only tested on Ubuntu 9.04. + +== Cookbooks: + +Opscode cookbooks: + +* build-essential +* java +* subversion +* boost + += USAGE: + +Include the Thrift recipe to install Thrift from source on your systems. + + include_recipe "thrift" + += LICENSE and AUTHOR: + + +Author:: Joshua Timberman () +Copyright:: 2009, Opscode, 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/thrift/metadata.json b/thrift/metadata.json new file mode 100644 index 0000000..fbead44 --- /dev/null +++ b/thrift/metadata.json @@ -0,0 +1,51 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs\/Configures thrift", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "thrift": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ] + }, + "version": "0.1.0", + "name": "thrift", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "thrift": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "= DESCRIPTION:\n\nInstalls Thrift from source.\n\n= REQUIREMENTS:\n\n== Platform:\n\nOnly tested on Ubuntu 9.04.\n\n== Cookbooks:\n\nOpscode cookbooks:\n\n* build-essential\n* java\n* subversion\n* boost\n\n= USAGE:\n\nInclude the Thrift recipe to install Thrift from source on your systems.\n\n include_recipe \"thrift\"\n\n= LICENSE and AUTHOR:\n\n\nAuthor:: Joshua Timberman ()\nCopyright:: 2009, Opscode, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http:\/\/www.apache.org\/licenses\/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n", + "replacing": { + + }, + "dependencies": { + "subversion": [ + + ], + "java": [ + + ], + "boost": [ + + ], + "build-essential": [ + + ] + } +} \ No newline at end of file diff --git a/thrift/metadata.rb b/thrift/metadata.rb new file mode 100644 index 0000000..99557f3 --- /dev/null +++ b/thrift/metadata.rb @@ -0,0 +1,12 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs/Configures thrift" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.1" + +supports "ubuntu" + +%w{ build-essential boost java subversion }.each do |cb| + depends cb +end diff --git a/thrift/recipes/default.rb b/thrift/recipes/default.rb new file mode 100644 index 0000000..d6cc343 --- /dev/null +++ b/thrift/recipes/default.rb @@ -0,0 +1,40 @@ +# +# Cookbook Name:: thrift +# Recipe:: default +# +# Copyright 2009, Opscode, 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 "build-essential" +include_recipe "boost" +include_recipe "java" +include_recipe "subversion" + +%w{ flex bison libtool autoconf pkg-config }.each do |pkg| + package pkg +end + +bash "install_thrift" do + user "root" + cwd "/tmp" + code <<-EOH + svn co http://svn.apache.org/repos/asf/incubator/thrift thrift + cd thrift/trunk; + cp /usr/share/aclocal/pkg.m4 ./aclocal + sh bootstrap.sh + ./configure --with-boost=/usr/local --with-libevent=/usr/local --prefix=/usr/local + make install + EOH + not_if { FileTest.exists?("/usr/local/bin/thrift") } +end diff --git a/timezone/attributes/timezone.rb b/timezone/attributes/timezone.rb new file mode 100755 index 0000000..76140e2 --- /dev/null +++ b/timezone/attributes/timezone.rb @@ -0,0 +1,2 @@ +timezone Mash.new unless attribute?("timezone") +timezone "UTC" \ No newline at end of file diff --git a/timezone/metadata.json b/timezone/metadata.json new file mode 100755 index 0000000..095a65b --- /dev/null +++ b/timezone/metadata.json @@ -0,0 +1,38 @@ +{ + "replacing": { + + }, + "long_description": "", + "attributes": { + + }, + "maintainer": "37signals", + "recommendations": { + + }, + "license": "Apache v2.0", + "recipes": { + "timezone": "" + }, + "maintainer_email": "sysadmins@37signals.com", + "suggestions": { + + }, + "dependencies": { + + }, + "conflicting": { + + }, + "platforms": { + + }, + "description": "Configures timezone", + "version": "0.1.0", + "name": "timezone", + "providing": { + "timezone": [ + + ] + } +} \ No newline at end of file diff --git a/timezone/metadata.rb b/timezone/metadata.rb new file mode 100755 index 0000000..7c7d949 --- /dev/null +++ b/timezone/metadata.rb @@ -0,0 +1,4 @@ +maintainer "37signals" +maintainer_email "sysadmins@37signals.com" +description "Configures timezone" +version "0.1" diff --git a/timezone/recipes/default.rb b/timezone/recipes/default.rb new file mode 100755 index 0000000..b3765fb --- /dev/null +++ b/timezone/recipes/default.rb @@ -0,0 +1,5 @@ +link "/etc/localtime" do + filename = "/usr/share/zoneinfo/#{node[:timezone]}" + to filename + only_if { File.exists? filename } +end \ No newline at end of file diff --git a/tomcat/attributes/default.rb b/tomcat/attributes/default.rb new file mode 100755 index 0000000..301cf52 --- /dev/null +++ b/tomcat/attributes/default.rb @@ -0,0 +1,6 @@ +tomcat Mash.new unless attribute?(:tomcat) +tomcat[:user] = "tomcat6" unless tomcat.has_key?(:user) +tomcat[:port] = "8080" unless tomcat.has_key?(:port) +tomcat[:java_home] = "/usr/lib/jvm/java-6-sun" unless tomcat.has_key?(:java_home) +tomcat[:heap_size] = "128M" unless tomcat.has_key?(:heap_size) +tomcat[:stack_size] = "16M" unless tomcat.has_key?(:stack_size) diff --git a/tomcat/metadata.json b/tomcat/metadata.json new file mode 100755 index 0000000..8cef216 --- /dev/null +++ b/tomcat/metadata.json @@ -0,0 +1,40 @@ +{ + "replacing": { + + }, + "long_description": "", + "attributes": { + + }, + "maintainer": "37signals", + "recommendations": { + + }, + "license": "Apache v2.0", + "recipes": { + "tomcat": "" + }, + "maintainer_email": "sysadmins@37signals.com", + "suggestions": { + + }, + "dependencies": { + "java": [ + + ] + }, + "conflicting": { + + }, + "platforms": { + + }, + "description": "Configures tomcat", + "version": "0.1.0", + "name": "tomcat", + "providing": { + "tomcat": [ + + ] + } +} \ No newline at end of file diff --git a/tomcat/metadata.rb b/tomcat/metadata.rb new file mode 100755 index 0000000..6dd914c --- /dev/null +++ b/tomcat/metadata.rb @@ -0,0 +1,5 @@ +maintainer "37signals" +maintainer_email "sysadmins@37signals.com" +description "Configures tomcat" +version "0.1" +depends "java" diff --git a/tomcat/recipes/default.rb b/tomcat/recipes/default.rb new file mode 100755 index 0000000..98ba463 --- /dev/null +++ b/tomcat/recipes/default.rb @@ -0,0 +1,29 @@ +require_recipe "java" + +return unless ["ubuntu", "debian"].include?(node[:platform]) + +package "tomcat6" +service "tomcat6" + +template "/etc/default/tomcat6" do + source "default.tomcat6.erb" + owner "root" + group "root" + mode 0644 + + notifies :restart, resources(:service => "tomcat6") +end + +template "/etc/tomcat6/server.xml" do + source "server.xml.erb" + owner "app" + group "admin" + mode 0644 + + notifies :restart, resources(:service => "tomcat6") +end + +execute "fix_permissions" do + command "chown -R #{node[:tomcat][:user]}:admin /etc/tomcat6 /var/log/tomcat6 /var/lib/tomcat6 /var/cache/tomcat6 && touch /etc/tomcat6/perms.ok" + creates "/etc/tomcat6/perms.ok" +end diff --git a/tomcat/templates/default/default.tomcat6.erb b/tomcat/templates/default/default.tomcat6.erb new file mode 100755 index 0000000..ad7f737 --- /dev/null +++ b/tomcat/templates/default/default.tomcat6.erb @@ -0,0 +1,30 @@ +# Run Tomcat as this user ID. Not setting this or leaving it blank will use the +# default of tomcat6. +TOMCAT6_USER=<%= @node[:tomcat][:user] %> + +# The home directory of the Java development kit (JDK). You need at least +# JDK version 1.5. If JAVA_HOME is not set, some common directories for +# OpenJDK, the Sun JDK, and various J2SE 1.5 versions are tried. +<% if @node[:tomcat].has_key?(:java_home) -%> +JAVA_HOME=<%= @node[:tomcat][:java_home] %> +<% end -%> + +# Directory for per-instance configuration files and webapps. It contains the +# directories conf, logs, webapps, work and temp. See RUNNING.txt for details. +# Default: /var/lib/tomcat6 +#CATALINA_BASE=/var/lib/tomcat6 + +# Arguments to pass to the Java virtual machine (JVM). +JAVA_OPTS="-Djava.awt.headless=true -Xmx<%= @node[:tomcat][:heap_size] %> -Xss<%= @node[:tomcat][:stack_size] %>" + +# Java compiler to use for translating JavaServer Pages (JSPs). You can use all +# compilers that are accepted by Ant's build.compiler property. +#JSP_COMPILER=jikes + +# Use the Java security manager? (yes/no, default: yes) +# WARNING: Do not disable the security manager unless you understand +# the consequences! +TOMCAT6_SECURITY=no + +# Number of days to keep logfiles in /var/log/tomcat6. Default is 14 days. +#LOGFILE_DAYS=14 diff --git a/tomcat/templates/default/server.xml.erb b/tomcat/templates/default/server.xml.erb new file mode 100755 index 0000000..455d6ef --- /dev/null +++ b/tomcat/templates/default/server.xml.erb @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + diff --git a/tomcat6/README.rdoc b/tomcat6/README.rdoc new file mode 100644 index 0000000..50a65ef --- /dev/null +++ b/tomcat6/README.rdoc @@ -0,0 +1,38 @@ += DESCRIPTION: + +Installs Tomcat6 + += REQUIREMENTS: + +== Platform and Application Environment: + +Tested on Centos 5.2 8.10. May work on other platforms, esp Redhat. +Needs Java at least Java 5 + +== Cookbooks: + +Opscode cookbooks, http://github.com/opscode/cookbooks/tree/master: + +* java + += ATTRIBUTES: + += USAGE: + + += LICENSE and AUTHOR: + +Author:: Edmund Haselwanter () +Copyright:: 2009, Edmund Haselwanter + +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/tomcat6/attributes/tomcat6.rb b/tomcat6/attributes/tomcat6.rb new file mode 100644 index 0000000..a656490 --- /dev/null +++ b/tomcat6/attributes/tomcat6.rb @@ -0,0 +1,41 @@ +# Where the various parts of tomcat6 are +case platform +when "centos" + set[:tomcat6][:start] = "/etc/init.d/tomcat6 start" + set[:tomcat6][:stop] = "/etc/init.d/tomcat6 stop" + set[:tomcat6][:restart] = "/etc/init.d/tomcat6 restart" + set[:tomcat6][:home] = "/usr/share/tomcat6" #don't use trailing slash. it breaks init script + set[:tomcat6][:dir] = "/etc/tomcat6/" + set[:tomcat6][:conf] = "/etc/tomcat6" + set[:tomcat6][:temp] = "/var/tmp/tomcat6" + set[:tomcat6][:logs] = "/var/log/tomcat6" + set[:tomcat6][:webapp_base_dir] = "/srv/tomcat6/" + set[:tomcat6][:webapps] = File.join(tomcat6[:webapp_base_dir],"webapps") + set[:tomcat6][:user] = "tomcat" + set[:tomcat6][:manager_dir] = File.join(tomcat6[:home],"webapps/manager") + set[:tomcat6][:port] = 8080 + set[:tomcat6][:ssl_port] = 8433 +else + set[:tomcat6][:start] = "/etc/init.d/tomcat6 start" + set[:tomcat6][:stop] = "/etc/init.d/tomcat6 stop" + set[:tomcat6][:restart] = "/etc/init.d/tomcat6 restart" + set[:tomcat6][:home] = "/usr/share/tomcat6" #don't use trailing slash. it breaks init script + set[:tomcat6][:dir] = "/etc/tomcat" + set[:tomcat6][:conf] = "/etc/tomcat6" + set[:tomcat6][:temp] = "/var/tmp/tomcat6" + set[:tomcat6][:logs] = "/var/log/tomcat6" + set[:tomcat6][:webapp_base_dir] = "/srv/tomcat6/" + set[:tomcat6][:webapps] = File.join(tomcat6[:webapp_base_dir],"webapps") + set[:tomcat6][:user] = "tomcat" + set[:tomcat6][:manager_dir] = "/usr/share/tomcat6/webapps/manager" + set[:tomcat6][:port] = 8080 + set[:tomcat6][:ssl_port] = 8433 +end + +set_unless[:tomcat6][:version] = "6.0.18" +set_unless[:tomcat6][:with_native] = false +set_unless[:tomcat6][:java_home] = "/usr/lib/jvm/java" +set_unless[:tomcat6][:java_opts] = "" +set_unless[:tomcat6][:manager_user] = "manager" +set_unless[:tomcat6][:manager_password] = "manager" +set_unless[:tomcat6][:permgen_min_free_in_mb] = 24 diff --git a/tomcat6/definitions/tomcat_app.rb b/tomcat6/definitions/tomcat_app.rb new file mode 100644 index 0000000..139597f --- /dev/null +++ b/tomcat6/definitions/tomcat_app.rb @@ -0,0 +1,2 @@ + + diff --git a/tomcat6/files/centos/rightscale.repo b/tomcat6/files/centos/rightscale.repo new file mode 100644 index 0000000..c17ba19 --- /dev/null +++ b/tomcat6/files/centos/rightscale.repo @@ -0,0 +1,15 @@ +[rightscale] +name=RightScale Packages for Enterprise Linux 5 +baseurl=http://mirror.rightscale.com/rightscale_software/centos/5/i386 + http://mirror1.rightscale.com/rightscale_software/centos/5/i386 + http://mirror2.rightscale.com/rightscale_software/centos/5/i386 + http://mirror1-int.rightscale.com/rightscale_software/centos/5/i386 + http://mirror2-int.rightscale.com/rightscale_software/centos/5/i386 + http://mirror3-int.rightscale.com/rightscale_software/centos/5/i386 +failovermethod=priority +enabled=1 +gpgcheck=0 +gpgkey= +# set metadata to expire faster then main +metadata_expire=30 + diff --git a/tomcat6/files/default/JVM-MANAGEMENT-MIB.mib b/tomcat6/files/default/JVM-MANAGEMENT-MIB.mib new file mode 100644 index 0000000..87c27bf --- /dev/null +++ b/tomcat6/files/default/JVM-MANAGEMENT-MIB.mib @@ -0,0 +1,3246 @@ +-- +-- @(#)JVM-MANAGEMENT-MIB.mib 1.32 04/07/16 +-- +-- Copyright 2004 Sun Microsystems, Inc. All rights reserved. +-- This software is the proprietary information of Sun Microsystems, Inc. +-- Use is subject to license terms. +-- +-- The JVM-MANAGEMENT-MIB Module +-- +-- See jvmManagementMIB MODULE-IDENTITY for a description overview. +-- See conformance statements for mandatory objects +-- + +JVM-MANAGEMENT-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE, Counter32, Gauge32, + Integer32, Counter64, enterprises + FROM SNMPv2-SMI + DisplayString, TEXTUAL-CONVENTION, RowPointer + FROM SNMPv2-TC + MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP + FROM SNMPv2-CONF; + +-- Module Identity +------------------ + +jvmMgtMIB MODULE-IDENTITY + LAST-UPDATED "200403041800Z" + -- Format is "YYYYMMDDhhmmZ" + ORGANIZATION "Sun Microsystems, Inc." + CONTACT-INFO "Sun Microsystems, Inc. + 4150 Network Circle + Santa Clara, CA 95054 + 1-800-555-9SUN or + 1-650-960-1300 + http://www.sun.com + or contact your local support representative" + DESCRIPTION + "Copyright 2004 Sun Microsystems, Inc. All rights reserved. + + This module defines the MIB that provides access to the + Java[tm] Virtual Machine monitoring data. + This module is derived from the Java[tm] programming language APIs + described in the java.lang.management package of + Java[tm] 2, Standard Edition, 5.0. + + See the Java programming language APIs of JSR 163 for + 'Monitoring and Management of the Java[TM] Virtual Machine' + for more details. + + Where the Java programming language API uses long, or int, + the MIB often uses the corresponding unsigned quantity - + which is closer to the object semantics. + + In those cases, it often happens that the -1 value that might + be used by the API to indicate an unknown/unimplemented + value cannot be used. Instead the MIB uses the value 0, which + stricly speaking cannot be distinguished from a valid value. + In many cases however, a running system will have non-zero + values, so using 0 instead of -1 to indicate an unknown + quantity does not lose any functionality. + " + REVISION "200403041800Z" + -- Format is "YYYYMMDDhhmmZ" + DESCRIPTION + " + JVM-MANAGEMENT-MIB - JSR 163 Final Release 1.0 + " + + ::= { standard jsr163(163) 1 } + + +-- Enterprise OIDs +------------------ + +-- internet OBJECT IDENTIFIER ::= { iso(1) org(3) dod(6) 1 } +-- private OBJECT IDENTIFIER ::= { internet 4 } +-- enterprises OBJECT IDENTIFIER ::= { private 1 } + sun OBJECT IDENTIFIER ::= { enterprises 42 } + jmgt OBJECT IDENTIFIER ::= { sun products(2) 145 } + -- experimental OBJECT IDENTIFIER ::= { jmgt 1 } + standard OBJECT IDENTIFIER ::= { jmgt 3 } + +---------------------------------------------------------------------------- +-- Textual Conventions +---------------------- +-- +-- Note: Some of the TEXTUAL-CONVENTIONs defined in this module are +-- OCTET STRING with a 1023 size limitation (SIZE(0..1023)). +-- +-- As per RFC2578, section 7.1.2. OCTET STRING: +-- +-- "The OCTET STRING type represents arbitrary binary or textual data. +-- Although the SMI-specified size limitation for this type is 65535 +-- octets, MIB designers should realize that there may be +-- implementation and interoperability limitations for sizes in +-- excess of 255 octets." +-- +-- As a consequence an agent implementing this MIB may decide to +-- restrict this maximum size to a lesser value than 1023, provided that +-- it makes it clear in an AGENT-CAPABILITY statement. +-- +---------------------------------------------------------------------------- + +JvmUnsigned64TC ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "A non-negative 64-bit bit integer, without counter + semantics." + -- We have cloned the Unsigned64TC defined in RFC 2564 rather + -- than importing it because the JVM-MANAGEMENT-MIB and the + -- APPLICATION-MIB are not related. + -- + REFERENCE "RFC 2564 - APPLICATION-MIB, Unsigned64TC." + SYNTAX Counter64 + + +JvmJavaObjectNameTC ::= TEXTUAL-CONVENTION + DISPLAY-HINT "255a" + STATUS current + DESCRIPTION + "An Object Name, as implemented by the java.lang.management API, + which identify a runtime Object (e.g. a Class Loader, a + Memory Manager, etc...). + The name is assumed to be unique in the scope of the object's + class. + + This object syntax is equivalent to a DisplayString, but with a + a 1023 bytes size limits (instead of 255 for a DisplayString). + + Note that the SNMP agent may have to truncate the string returned + by the underlying API if it does not fit in this type. + (1023 bytes max). + " + SYNTAX OCTET STRING (SIZE (0..1023)) + +JvmPathElementTC ::= TEXTUAL-CONVENTION + DISPLAY-HINT "255a" + STATUS current + DESCRIPTION + "A file or directory element in a PATH/CLASSPATH/LIBRARY_PATH + structure. + + This object syntax is equivalent to a DisplayString, but with a + a 1023 bytes size limits (instead of 255 for a DisplayString). + + Note that the SNMP agent may have to truncate the string returned + by the underlying API if it does not fit in this type. + (1023 bytes max). + " + SYNTAX OCTET STRING (SIZE (0..1023)) + +JvmArgValueTC ::= TEXTUAL-CONVENTION + DISPLAY-HINT "255a" + STATUS current + DESCRIPTION + "A string representing an input argument. + + This object syntax is equivalent to a DisplayString, but with a + a 1023 bytes size limits (instead of 255 for a DisplayString). + + Note that the SNMP agent may have to truncate the string returned + by the underlying API if it does not fit in this type. + (1023 bytes max). + " + SYNTAX OCTET STRING (SIZE (0..1023)) + +JvmVerboseLevelTC ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "Defines whether the verbose flag for a feature is active. + verbose: the flag is on. + silent: the flag is off. + " + SYNTAX INTEGER { silent(1), verbose(2) } + + +JvmImplSupportStateTC ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "Defines whether a feature is supported or not. + " + SYNTAX INTEGER { unsupported(1), supported(2) } + +JvmImplOptFeatureStateTC ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "Defines whether an optional feature is supported, enabled, + or disabled. + + An optional feature can be: + + unsupported: The JVM does not support this feature. + enabled : The JVM supports this feature, and it + is enabled. + disabled : The JVM supports this feature, and it + is disabled. + + Only enabled(3) and disabled(4) may be supplied as values to a + SET request. unsupported(1) can only be set internally by the + agent. + " + SYNTAX INTEGER { unsupported(1), enabled(3), disabled(4) } + +JvmTimeMillis64TC ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "An elapsed time, expressed in milli-seconds. + This type is based on Counter64, but without its specific + semantics. + " + SYNTAX Counter64 + +JvmTimeNanos64TC ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "An elapsed time, expressed in nano-seconds. + This type is based on Counter64, but without its specific + semantics. + " + SYNTAX Counter64 + +JvmPositive32TC ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "A positive Integer32. In Java that would be a number + in [0..Integer.MAX_VALUE]. + " + -- We use Integer32 (0..2147483647) rather than Unsigned32 because + -- Unsigned32 (0..2147483647) because Unsigned32 is based on + -- Gauge32 - which has a specific ASN.1 tag and a specific semantics. + -- In principle you cannot use a Gauge32 as base type for an index + -- in a table. + -- Note also that Unsigned32 is (0..2^32-1) + -- while Positive32 is (0..2^31-1) + -- + SYNTAX Integer32 (0..2147483647) + +JvmManagedMemoryTypeTC ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + " + Defines the type of memory contained in a memory pool. + The pool may contain, heap memory or non-heap memory. + " + SYNTAX INTEGER { nonheap(1), heap(2) } + + +JvmValidityStateTC ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + " + Defines whether an object is still valid. + " + SYNTAX INTEGER { invalid(1), valid(2) } + + +JvmThreadStateTC ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "Defines the possible states of a thread running in the + Java virtual machine. They are virtual machine thread states + and do not reflect any operating system thread states. + + The first two bits: inNative(1) and suspended(2) can be + combined together and with any other bits. The remaining + bits 3-9, are mutually exclusive. Bits 10-16 are reserved + for future evolution of this MIB. + + An agent MUST always return a thread state with one of the + bits in the range 3-9 set to 1. The other(9) bit should only + be set to 1 if new thread states which are mutally exclusive + with bits 3-8 are defined. An implementation can define + additional implementation dependant states and uses bits + from bit 17. + + See java.lang.Thread.State, + java.lang.management.ThreadInfo. + " + -- + -- Take care that in SNMP bits are numbered starting at 1, from + -- left to right (1 is the highest bit). A bitmap defined by the + -- BITS construct is thus a byte array where bit 1 is the highest bit + -- of the first byte. + -- + SYNTAX BITS { -- Bits 1-2 may be specified in any combination + inNative(1), + suspended(2), + + -- Bits 3-9 are mutually exclusive. Attempting to + -- set more than a single bit to 1 will result in + -- a returned error-status of inconsistentValue. + newThread(3), + runnable(4), + blocked(5), + terminated(6), + waiting(7), + timedWaiting(8), + other(9) + -- Bits 10-16 are reserved for future use by + -- this MIB + } + + +JvmIndex64TC ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "A 64 bits string mapping an unsigned 64 bits integer value + in big-endian ordering (i.e: 1 is encoded as 0x0000000000000001). + + This type can be used when an unsigned 64 bits integer needs + to be used inside a table index. + " + SYNTAX OCTET STRING (SIZE(8)) + + +-- OBJECT-TYPE OID tree +----------------------- + +jvmMgtMIBObjects + OBJECT IDENTIFIER ::= { jvmMgtMIB 1 } +jvmMgtMIBNotifications + OBJECT IDENTIFIER ::= { jvmMgtMIB 2 } +jvmMgtMIBConformance + OBJECT IDENTIFIER ::= { jvmMgtMIB 3 } + +----------------------------------------------------------------------- +-- +-- The JVM Class Loading group +-- +-- A collection of objects used to monitor Class Loading in the +-- Java Virtual Machine. These objects define the SNMP management +-- interface for the class loading system of the Java virtual machine. +-- +-- This group only contains a few scalar object and no tables. The objects +-- from this group are mapped from the java.lang.management.ClassLoadingMXBean +-- interface. +-- +-- See J2SE 5.0 API Specification, +-- java.lang.management.ClassLoadingMXBean +----------------------------------------------------------------------- + +-- Root OBJECT IDENTIFIER for ClassLoading group. +-- +jvmClassLoading OBJECT IDENTIFIER ::= { jvmMgtMIBObjects 1 } + +-- The following objects are mapped from the ClassLoadingMXBean interface. +----------------------------------------------------------------------- + +jvmClassesLoadedCount OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of classes currently loaded in the JVM. + + See java.lang.management.ClassLoadingMXBean.getLoadedClassCount() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.ClassLoadingMXBean" + ::= { jvmClassLoading 1 } + +jvmClassesTotalLoadedCount OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of classes that have been loaded since + the JVM has started execution. + + See java.lang.management.ClassLoadingMXBean. + getTotalLoadedClassCount() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.ClassLoadingMXBean" + ::= { jvmClassLoading 2 } + +jvmClassesUnloadedCount OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of classes that have been unloaded since + the JVM has started execution. + + See java.lang.management.ClassLoadingMXBean.getUnloadedClassCount() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.ClassLoadingMXBean" + ::= { jvmClassLoading 3 } + +jvmClassesVerboseLevel OBJECT-TYPE + SYNTAX JvmVerboseLevelTC + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Enables or disables the verbose output for the class loading + system. The verbose output information and the output stream + to which the verbose information is emitted are implementation + dependent. Typically, a Java virtual machine implementation + prints a message each time a class file is loaded. + + verbose: if the verbose output is enabled. + silent: otherwise. + + See java.lang.management.ClassLoadingMXBean.isVerbose(), + java.lang.management.ClassLoadingMXBean.setVerbose() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.ClassLoadingMXBean" + DEFVAL { silent } + ::= { jvmClassLoading 4 } + + +----------------------------------------------------------------------- +-- +-- The JVM Memory group +-- +-- A collection of objects used to monitor memory management in the +-- Java Virtual Machine. These objects define management interface for +-- the memory system of the Java virtual machine. +-- +-- Memory: +-- +-- The memory system of the Java virtual machine manages the following +-- kinds of memory: heap, and non-heap. More information on these types +-- of memory can be obtained from the J2SE 5.0 API Specification, +-- java.lang.management.MemoryMXBean. +-- +-- Memory Pools and Memory Managers: +-- +-- Memory pools and memory managers are the abstract entities that monitor +-- and manage the memory system of the Java virtual machine. +-- +-- Memory managers are represented by the jvmMemManagerTable, which contains +-- one row per Memory manager. +-- The garbage collector is one type of memory manager responsible for +-- reclaiming memory occupied by unreachable objects. +-- The jvmMemGCTable is an extension of the jvmMemManagerTable, which contains +-- the attribute specific to garbage collectors. A garbage collector entity +-- is thus represented by one row in the jvmMemManagerTable, and one +-- extension row in the jvmMemGCTable. +-- +-- Memory Pools are represented by the jvmMemPoolTable, which contains one +-- row per memory pool. A Java virtual machine may create or remove +-- memory pools during execution. A memory pool can belong to either the +-- heap or the non-heap memory. +-- +-- A memory manager is responsible for managing one or more memory pools. +-- A memory pool can be managed by more than one memory manager. +-- The jvmMemMgrRelPoolTable represents this managing/managed relationship. +-- +-- A Java virtual machine may add or remove memory managers during execution. +-- +-- See J2SE 5.0 API Specification, java.lang.management.MemoryMXBean for +-- more information on memory types, memory managers, memory pools, +-- and the memory subsystem. +-- +----------------------------------------------------------------------- + +-- Root OBJECT IDENTIFIER for the JVM Memory group. +-- +jvmMemory OBJECT IDENTIFIER ::= { jvmMgtMIBObjects 2 } + +-- The following objects are mapped from the MemoryMXBean interface. +----------------------------------------------------------------------- + +jvmMemoryPendingFinalCount OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The approximate number objects that are pending for finalization. + + See java.lang.management.MemoryMXBean. + getObjectPendingFinalizationCount() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryMXBean" + ::= { jvmMemory 1 } + +jvmMemoryGCVerboseLevel OBJECT-TYPE + SYNTAX JvmVerboseLevelTC + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Enables or disables verbose output for the memory system. + The verbose output information and the output stream to which + the verbose information is emitted are implementation dependent. + Typically, a Java virtual machine implementation prints a + message whenever it frees memory at garbage collection. + + verbose: if the verbose output is enabled, + silent: otherwise. + + See java.lang.management.MemoryMXBean.isVerbose(), + java.lang.management.MemoryMXBean.setVerbose() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryMXBean" + ::= { jvmMemory 2 } + +jvmMemoryGCCall OBJECT-TYPE + SYNTAX INTEGER { unsupported(1), supported(2), start(3), + started(4), failed(5) } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "This object makes it possible to remotelly trigger the + Garbage Collector in the JVM. + + This object's syntax is an enumeration which defines: + + * Two state values, that can be returned from a GET request: + + unsupported(1): means that remote invocation of gc() is not + supported by the SNMP agent. + supported(2) : means that remote invocation of gc() is supported + by the SNMP agent. + + * One action value, that can be provided in a SET request to + trigger the garbage collector: + + start(3) : means that a manager wishes to trigger + garbage collection. + + * Two result value, that will be returned in the response to a + SET request when remote invocation of gc is supported + by the SNMP agent: + + started(4) : means that garbage collection was + successfully triggered. It does not mean + however that the action was successfullly + completed: gc might still be running when + this value is returned. + failed(5) : means that garbage collection couldn't be + triggered. + + * If remote invocation is not supported by the SNMP agent, then + unsupported(1) will always be returned as a result of either + a GET request, or a SET request with start(3) as input value. + + * If a SET request with anything but start(3) is received, then + the agent will return a wrongValue error. + + See java.lang.management.MemoryMXBean.gc() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryMXBean" + ::= { jvmMemory 3 } + +-- The object identifiers in the range jvmMemory.[4-9] are reserved for future +-- evolution of this MIB. +-- +-- We use the range jvmMemory.[10..19] for objects related to global JVM +-- heap memory usage, as returned by +-- java.lang.management.MemoryMXBean.getHeapMemoryUsage(). +-- Object identifiers in the range jvmMemory.[14..19] are not used but +-- reserved for future evolution of this MIB. +-- +jvmMemoryHeapInitSize OBJECT-TYPE + SYNTAX JvmUnsigned64TC + UNITS "bytes" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " + Total amount of memory (in bytes) that the Java virtual machine + initially requests from the operating system for memory management + for heap memory pools. + + See java.lang.management.MemoryMXBean.getHeapMemoryUsage().getInit() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryMXBean, + java.lang.management.MemoryUsage" + ::= { jvmMemory 10 } + + +jvmMemoryHeapUsed OBJECT-TYPE + SYNTAX JvmUnsigned64TC + UNITS "bytes" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " + Total amount of used memory (in bytes) from heap memory pools. + + See java.lang.management.MemoryMXBean.getHeapMemoryUsage().getUsed() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryMXBean, + java.lang.management.MemoryUsage" + ::= { jvmMemory 11 } + +jvmMemoryHeapCommitted OBJECT-TYPE + SYNTAX JvmUnsigned64TC + UNITS "bytes" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " + Total amount of memory (in bytes) committed by heap memory pools. + + See java.lang.management.MemoryMXBean.getHeapMemoryUsage(). + getCommitted() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryMXBean, + java.lang.management.MemoryUsage" + ::= { jvmMemory 12 } + +jvmMemoryHeapMaxSize OBJECT-TYPE + SYNTAX JvmUnsigned64TC + UNITS "bytes" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " + Total maximum size of memory (in bytes) for all heap memory pools. + + See java.lang.management.MemoryMXBean.getHeapMemoryUsage().getMax() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryMXBean, + java.lang.management.MemoryUsage" + ::= { jvmMemory 13 } + +-- We use the range jvmMemory.[20..29] for objects related to global JVM +-- heap memory usage, as returned by +-- lang.management.MemoryMXBean.getNonHeapMemoryUsage(). +-- Object identifiers in the range jvmMemory.[24..29] are not used but are +-- reserved for future evolution of this MIB. +-- +jvmMemoryNonHeapInitSize OBJECT-TYPE + SYNTAX JvmUnsigned64TC + UNITS "bytes" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " + Total amount of memory (in bytes) that the Java virtual machine + initially requests from the operating system for memory management + for non heap memory pools. + + See java.lang.management.MemoryMXBean.getNonHeapMemoryUsage().getInit() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryMXBean, + java.lang.management.MemoryUsage" + ::= { jvmMemory 20 } + + +jvmMemoryNonHeapUsed OBJECT-TYPE + SYNTAX JvmUnsigned64TC + UNITS "bytes" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " + Total amount of used memory (in bytes) from non heap memory pools. + + See java.lang.management.MemoryMXBean.getNonHeapMemoryUsage().getUsed() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryMXBean, + java.lang.management.MemoryUsage" + ::= { jvmMemory 21 } + +jvmMemoryNonHeapCommitted OBJECT-TYPE + SYNTAX JvmUnsigned64TC + UNITS "bytes" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " + Total amount of memory (in bytes) committed by non heap memory pools. + + See java.lang.management.MemoryMXBean. + getNonHeapMemoryUsage().getCommitted() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryMXBean, + java.lang.management.MemoryUsage" + ::= { jvmMemory 22 } + +jvmMemoryNonHeapMaxSize OBJECT-TYPE + SYNTAX JvmUnsigned64TC + UNITS "bytes" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " + Total maximum size of memory (in bytes) for all non heap memory pools. + + See java.lang.management.MemoryMXBean.getNonHeapMemoryUsage().getMax() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryMXBean, + java.lang.management.MemoryUsage" + ::= { jvmMemory 23 } + +-- The object identifiers in the range jvmMemory.[30-99] are not used but are +-- reserved for future evolution of this MIB. +-- +-- The JVM Memory Manager Table +-- +-- The jvmMemManagerTable represent memory manager abstract entities. +-- The jvmMemManagerTable contains one row per memory manager. In +-- addition, those memory managers which are also garbage collectors have +-- an extension row in the jvmMemGCTable. +-- +-- See J2SE 5.0 API Specification, java.lang.management.MemoryMXBean for +-- a detailed description of the memory subsystem. +-- +-- See J2SE 5.0 API Specification, java.lang.management.MemoryManagerMXBean +-- for more information on memory managers. +-- +----------------------------------------------------------------------- +-- +-- We use the range jvmMemory.[100..109] for objects related to memory +-- managers. +-- Object identifiers in the range jvmMemory.[102-109] are not used +-- but are reserved for future evolution of this MIB. +-- +jvmMemManagerTable OBJECT-TYPE + SYNTAX SEQUENCE OF JvmMemManagerEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The Memory Manager Table contains the whole list of Memory + Managers as returned by ManagementFactory.getMemoryManagerMXBeans(). + + When a MemoryManagerMXBean object is an instance of + GarbageCollectorMXBean, then additional information specific to + the GarbageCollectorMXBean class will be found in the + jvmGCTable, at the same index. + + Relationships between MemoryManagers and MemoryPools are shown + by the Memory Manager-Pool Relation table (jvmMemMgrPoolRelTable). + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryManagerMXBean" + ::= { jvmMemory 100 } + +jvmMemManagerEntry OBJECT-TYPE + SYNTAX JvmMemManagerEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A jvmMemManagerEntry conceptual row represent an instance of the + java.lang.management.MemoryManagerMXBean interface. If that instance + is also an instance of java.lang.management.GarbageCollectorMXBean, + then additional information will be found in the jvmGCTable, at the + same index. + + Columnar objects in this table are mapped from attributes of + the MemoryManagerMXBean interface. + + See java.lang.management.MemoryManagerMXBean + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryManagerMXBean" + INDEX { jvmMemManagerIndex } + ::= { jvmMemManagerTable 1 } + +JvmMemManagerEntry ::= SEQUENCE { + jvmMemManagerIndex JvmPositive32TC, + jvmMemManagerName JvmJavaObjectNameTC, + jvmMemManagerState JvmValidityStateTC +} + +jvmMemManagerIndex OBJECT-TYPE + SYNTAX JvmPositive32TC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An index opaquely computed by the agent and which uniquely + identifies a Memory Manager. + + The jvmMemManagerIndex index is opaquely computed by the agent, + from e.g the hash code of the MemoryManager (or MemoryManager name). + The agent is responsible for allocating a free index when it needs + one (e.g. if two objects have the same hash, then it may increment + one of the values until the conflict is resolved). As a result a + manager must not depend on the value of that index across, + e.g. reboot of the agent, as this value is not guaranteed to + stay identical after the agent restarts. + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryManagerMXBean" + ::= { jvmMemManagerEntry 1 } + +jvmMemManagerName OBJECT-TYPE + SYNTAX JvmJavaObjectNameTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name of this memory manager, as returned by + MemoryManagerMXBean.getName(). + + See java.mangement.MemoryManagerMXBean.getName(). + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryManagerMXBean" + ::= { jvmMemManagerEntry 2 } + +jvmMemManagerState OBJECT-TYPE + SYNTAX JvmValidityStateTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " + Indicates whether this memory manager is valid in the Java + virtual machine. A memory manager becomes invalid once the + Java virtual machine removes it from the memory system. + + See java.lang.management.MemoryManagerMXBean.isValid() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryManagerMXBean" + ::= { jvmMemManagerEntry 3 } + + +-- The JVM Garbage Collector Table +-- +-- The jvmMemGCTable is an extension of the jvmMemManagerTable. +-- It represents garbage collector abstract entities. A garbage collector +-- is a memory manager responsible for reclaiming memory occupied by +-- unreachable objects. +-- +-- A garbage collector is thus represented by one row in the +-- jvmMemManagerTable, plus an extension row in the jvmMemGCTable. +-- The extension row in the jvmMemGCTable contains those attributes which +-- are specific to garbage collectors. +-- +-- See J2SE 5.0 API Specification, java.lang.management.MemoryMXBean for +-- a detailed description of the memory subsystem. +-- +-- See J2SE 5.0 API Specification, java.lang.management.MemoryManagerMXBean +-- for more information on memory managers, and +-- java.lang.management.GarbageCollectorMXBean for more information on +-- garbage collectors. +-- +----------------------------------------------------------------------- + +jvmMemGCTable OBJECT-TYPE + SYNTAX SEQUENCE OF JvmMemGCEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The Garbage Collector table provides additional information + on those MemoryManagers which are also GarbageCollectors. + This table extends the jvmMemManagerTable table. The index + used in the jvmMemGCTable table is imported from the + jvmMemManagerTable table. If a row from the jvmMemManagerTable + table is deleted, and if it has an extension in the jvmMemGCTable + table, then the extension row will also be deleted. + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.GarbageCollectorMXBean" + ::= { jvmMemory 101 } + +jvmMemGCEntry OBJECT-TYPE + SYNTAX JvmMemGCEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Provide additional information on Garbage Collectors. + + Columnar objects in this table are mapped from the + GarbageCollectorMXBean interface. + + See java.lang.management.GarbageCollectorMXBean + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.GarbageCollectorMXBean" + INDEX { jvmMemManagerIndex } + ::= {jvmMemGCTable 1 } + +JvmMemGCEntry ::= SEQUENCE { + jvmMemGCCount Counter64, + jvmMemGCTimeMs JvmTimeMillis64TC +} + +jvmMemGCCount OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of collections that have occurred, + as returned by GarbageCollectorMXBean.getCollectionCount(). + + If garbage collection statistics are not available, this + object is set to 0. + + See java.lang.management.GarbageCollectorMXBean.getCollectionCount() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.GarbageCollectorMXBean" + ::= { jvmMemGCEntry 2 } + +jvmMemGCTimeMs OBJECT-TYPE + SYNTAX JvmTimeMillis64TC + UNITS "milliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The approximate accumulated collection elapsed time in + milliseconds, since the Java virtual machine has started. + This object is set to 0 if the collection elapsed time is + undefined for this collector. + + See java.lang.management.GarbageCollectorMXBean.getCollectionTime() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.GarbageCollectorMXBean" + DEFVAL { 0 } + ::= { jvmMemGCEntry 3 } + +-- The JVM Memory Pool Table +-- +-- The jvmMemPoolTable represent memory pool abstract entities. +-- The jvmMemPoolTable contains one row per memory pool. +-- +-- See J2SE 5.0 API Specification, java.lang.management.MemoryMXBean for +-- a detailed description of the memory subsystem. +-- +-- See J2SE 5.0 API Specification, java.lang.management.MemoryPoolMXBean +-- for more information on memory pool. +-- +----------------------------------------------------------------------- +-- +-- We use the range jvmMemory.[110..119] for objects related to memory pools. +-- Object identifiers in the range jvmMemory.[111-119] are not used but +-- are reserved for future evolution of this MIB. +-- +jvmMemPoolTable OBJECT-TYPE + SYNTAX SEQUENCE OF JvmMemPoolEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The Memory Pool Table contains the whole list of MemoryPools + as returned by ManagementFactory.getMemoryPoolMXBeans(). + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryPoolMXBean" + ::= { jvmMemory 110 } + +jvmMemPoolEntry OBJECT-TYPE + SYNTAX JvmMemPoolEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + " + Represents a memory pool. The pool may contain heap memory or + non-heap memory. A row in this table represents + an instance of MemoryPoolMXBean. + + See java.lang.management.MemoryPoolMXBean + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryPoolMXBean" + INDEX { jvmMemPoolIndex } + ::= { jvmMemPoolTable 1 } + +JvmMemPoolEntry ::= SEQUENCE { + jvmMemPoolIndex JvmPositive32TC, + jvmMemPoolName JvmJavaObjectNameTC, + jvmMemPoolType JvmManagedMemoryTypeTC, + jvmMemPoolState JvmValidityStateTC, + jvmMemPoolPeakReset JvmTimeMillis64TC, + + jvmMemPoolInitSize JvmUnsigned64TC, + jvmMemPoolUsed JvmUnsigned64TC, + jvmMemPoolCommitted JvmUnsigned64TC, + jvmMemPoolMaxSize JvmUnsigned64TC, + + jvmMemPoolPeakUsed JvmUnsigned64TC, + jvmMemPoolPeakCommitted JvmUnsigned64TC, + jvmMemPoolPeakMaxSize JvmUnsigned64TC, + + jvmMemPoolCollectUsed JvmUnsigned64TC, + jvmMemPoolCollectCommitted JvmUnsigned64TC, + jvmMemPoolCollectMaxSize JvmUnsigned64TC, + + jvmMemPoolThreshold JvmUnsigned64TC, + jvmMemPoolThreshdCount Counter64, + jvmMemPoolThreshdSupport JvmImplSupportStateTC, + jvmMemPoolCollectThreshold JvmUnsigned64TC, + jvmMemPoolCollectThreshdCount Counter64, + jvmMemPoolCollectThreshdSupport JvmImplSupportStateTC + +} + +jvmMemPoolIndex OBJECT-TYPE + SYNTAX JvmPositive32TC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An index value opaquely computed by the agent which uniquely + identifies a row in the jvmMemPoolTable. + + The jvmMemPoolIndex index is opaquely computed by the agent, + from e.g the hash code of the MemoryPool (or MemoryPool name). + The agent is responsible for allocating a free index when it + needs one (e.g. if two objects have the same hash, then it may + increment one of the values until the conflict is resolved). + As a result a manager must not depend on the value of that + index across, e.g. reboot of the agent, as this value is not + guaranteed to stay identical after the agent restarts. + " + ::= { jvmMemPoolEntry 1 } + +jvmMemPoolName OBJECT-TYPE + SYNTAX JvmJavaObjectNameTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name of this memory pool, as returned by + MemoryPoolMXBean.getName(). + + See java.lang.management.MemoryPoolMXBean.getName() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryPoolMXBean" + ::= { jvmMemPoolEntry 2 } + +jvmMemPoolType OBJECT-TYPE + SYNTAX JvmManagedMemoryTypeTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The type of memory managed in this pool. This pool may be used for + heap memory or non-heap memory. + + See java.lang.management.MemoryPoolMXBean.getMemoryType() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryPoolMXBean" + ::= { jvmMemPoolEntry 3 } + +jvmMemPoolState OBJECT-TYPE + SYNTAX JvmValidityStateTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " + Indicates whether this memory pool is valid in the Java + virtual machine. A memory pool becomes invalid once the + Java virtual machine removes it from the memory system. + + See java.lang.management.MemoryPoolMXBean.isValid() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryPoolMXBean" + ::= { jvmMemPoolEntry 4 } + +jvmMemPoolPeakReset OBJECT-TYPE + SYNTAX JvmTimeMillis64TC + UNITS "milliseconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + " + This object indicates the last time - in milliseconds - at which + the peak memory usage statistic of this memory pool was reset + to the current memory usage. This corresponds to a time stamp + as returned by java.lang.System.currentTimeMillis(); + + Setting this object to a time earlier than its current time value + has no effect. Setting this object to a time later than its current + time value causes the peak memory usage statistic of this memory + pool to be reset to the current memory usage. The new value of this + object will be the time at which the reset operation is triggered. + + There could be a delay between the time at which the reset operation + is triggered and the time at which the actual resetting happens, so + this value is only indicative. + + See java.lang.management.MemoryPoolMXBean.resetPeakUsage() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryPoolMXBean" + ::= { jvmMemPoolEntry 5 } + + +-- The object identifier arcs in the range jvmMemPoolEntry.[6-9] are +-- reserved for future evolution of this MIB. +-- +-- We use the range jvmMemPoolEntry.[10..19] for objects related to this +-- pool memory usage, as returned by +-- java.lang.management.MemoryPoolMXBean.getUsage(). +-- Object identifiers in the range jvmMemPoolEntry.[14..19] are not +-- used but are reserved for future evolution of this MIB. +-- +jvmMemPoolInitSize OBJECT-TYPE + SYNTAX JvmUnsigned64TC + UNITS "bytes" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " + Initial size of this memory pool. + + See java.lang.management.MemoryPoolMXBean.getUsage().getInit() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryPoolMXBean, + java.lang.management.MemoryUsage" + ::= { jvmMemPoolEntry 10 } + + +jvmMemPoolUsed OBJECT-TYPE + SYNTAX JvmUnsigned64TC + UNITS "bytes" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " + Amount of used memory in this memory pool. + + See java.lang.management.MemoryPoolMXBean.getUsage().getUsed() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryPoolMXBean, + java.lang.management.MemoryUsage" + ::= { jvmMemPoolEntry 11 } + +jvmMemPoolCommitted OBJECT-TYPE + SYNTAX JvmUnsigned64TC + UNITS "bytes" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " + Amount of committed memory in this memory pool. + + See java.lang.management.MemoryPoolMXBean.getUsage().getCommitted() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryPoolMXBean, + java.lang.management.MemoryUsage" + ::= { jvmMemPoolEntry 12 } + +jvmMemPoolMaxSize OBJECT-TYPE + SYNTAX JvmUnsigned64TC + UNITS "bytes" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " + Maximal size of this memory pool. + + See java.lang.management.MemoryPoolMXBean.getUsage().getMax() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryPoolMXBean, + java.lang.management.MemoryUsage" + ::= { jvmMemPoolEntry 13 } + +-- We use the range jvmMemPoolEntry.[20..29] for objects related to +-- this pool peak memory usage, as returned by +-- java.lang.management.MemoryPoolMXBean.getPeakUsage(). +-- The object identifier arc jvmMemPoolEntry.20 which would have been +-- used for the initial size is not used because the notion of initial +-- size in the context of peak usage is meaningless. +-- Therefore, we start numbering objects at 21. +-- Object identifiers in the range jvmMemPoolEntry.[24..29] are not +-- used but are reserved for future evolution of this MIB. +-- +jvmMemPoolPeakUsed OBJECT-TYPE + SYNTAX JvmUnsigned64TC + UNITS "bytes" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " + Amount of used memory in this memory pool when the peak usage + was reached. + + See java.lang.management.MemoryPoolMXBean.getPeakUsage().getUsed() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryPoolMXBean, + java.lang.management.MemoryUsage" + ::= { jvmMemPoolEntry 21 } + +jvmMemPoolPeakCommitted OBJECT-TYPE + SYNTAX JvmUnsigned64TC + UNITS "bytes" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " + Amount of committed memory in this memory pool when the peak usage + was reached. + + See java.lang.management.MemoryPoolMXBean.getPeakUsage().getCommitted() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryPoolMXBean, + java.lang.management.MemoryUsage" + ::= { jvmMemPoolEntry 22 } + +jvmMemPoolPeakMaxSize OBJECT-TYPE + SYNTAX JvmUnsigned64TC + UNITS "bytes" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " + Maximal size of this memory pool when the peak usage + was reached. + + See java.lang.management.MemoryPoolMXBean.getPeakUsage().getMax() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryPoolMXBean, + java.lang.management.MemoryUsage" + ::= { jvmMemPoolEntry 23 } + +-- We use the range jvmMemPoolEntry.[30..39] for objects related to this +-- pool collection memory usage, as returned by +-- java.lang.management.MemoryPoolMXBean.getCollectionUsage(). +-- The object identifier arc jvmMemPoolEntry.30 which would have been used +-- for the initial size is not used because the notion of initial size in the +-- context of collection usage is meaningless. +-- Therefore, we start numbering objects at 31. +-- Object identifiers in the range jvmMemPoolEntry.[34..39] are not used +-- but are reserved for future evolution of this MIB. +-- +jvmMemPoolCollectUsed OBJECT-TYPE + SYNTAX JvmUnsigned64TC + UNITS "bytes" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " + The amount of used memory at the most recent time that the + Java virtual machine has expended effort in recycling unused objects + in this memory pool. + + See java.lang.management.MemoryPoolMXBean.getCollectionUsage().getUsed() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryPoolMXBean, + java.lang.management.MemoryUsage" + ::= { jvmMemPoolEntry 31 } + +jvmMemPoolCollectCommitted OBJECT-TYPE + SYNTAX JvmUnsigned64TC + UNITS "bytes" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " + The amount of committed memory at the most recent time that the + Java virtual machine has expended effort in recycling unused objects + in this memory pool. + + See java.lang.management.MemoryPoolMXBean.getCollectionUsage(). + getCommitted() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryPoolMXBean, + java.lang.management.MemoryUsage" + ::= { jvmMemPoolEntry 32 } + +jvmMemPoolCollectMaxSize OBJECT-TYPE + SYNTAX JvmUnsigned64TC + UNITS "bytes" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " + The value of the maximum amount of memory at the most recent time + that the Java virtual machine has expended effort in recycling + unused objects in this memory pool. + + See java.lang.management.MemoryPoolMXBean.getCollectionUsage().getMax() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryPoolMXBean, + java.lang.management.MemoryUsage" + ::= { jvmMemPoolEntry 33 } + +-- Object identifiers in the range jvmMemPoolEntry.[40-109] are reserved +-- for future evolution of this MIB. +-- +-- We use the range jvmMemPoolEntry.[110..119] for objects related to this +-- pool memory usage thresholds (range jvmMemPoolEntry.[10..19] was used for +-- this pool memory usage). +-- Object identifier arcs in the range jvmMemPoolEntry.[113..119] are not +-- used but are reserved for future evolution of this MIB. +-- +jvmMemPoolThreshold OBJECT-TYPE + SYNTAX JvmUnsigned64TC + UNITS "bytes" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The threshold value for the memory usage of this memory pool, + in bytes. A zero value (0) indicates that no threshold value is + configured. + When the amount of used memory crosses over this threshold + value the JVM will trigger a usage memory threshold exceeded + notification, and the jvmMemPoolThreshdCount increases. + + If memory usage threshold is not supported, then this object, if + implemented, will always be equals to 0. In that case, attempting + to set this object will trigger an inconsistentValue error. + + See also jvmMemPoolThreshdSupport. + + See java.lang.management.MemoryPoolMXBean.getUsageThreshold(), + java.lang.management.MemoryPoolMXBean.setUsageThreshold(long), + java.lang.management.MemoryPoolMXBean.getUsageThresholdCount(), + java.lang.management.MemoryPoolMXBean.isUsageThresholdSupported() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryPoolMXBean" + DEFVAL { 0 } + ::= { jvmMemPoolEntry 110 } + +jvmMemPoolThreshdCount OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times that the memory usage has crossed + the usage threshold, as detected by the Java virtual machine. + + If memory usage threshold is not supported, then this object, if + implemented, will always be equals to 0. + + See also jvmMemPoolThresholdSupport. + + See java.lang.management.MemoryPoolMXBean.getUsageThresholdCount(), + java.lang.management.MemoryPoolMXBean.isUsageThresholdSupported() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryPoolMXBean" + ::= { jvmMemPoolEntry 111 } + +jvmMemPoolThreshdSupport OBJECT-TYPE + SYNTAX JvmImplSupportStateTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Tells whether this memory pool supports usage threshold. + + See java.lang.management.MemoryPoolMXBean.isUsageThresholdSupported() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryPoolMXBean" + ::= { jvmMemPoolEntry 112 } + +-- Object identifiers in the range jvmMemPoolEntry.[120-129] are reserved +-- for future evolution of this MIB. +-- +-- We use the range jvmMemPoolEntry.[130..139] for objects related to +-- this pool memory collection usage thresholds (range +-- jvmMemPoolEntry.[30..39] was used for this pool collection memory usage). +-- Object identifiers in the range jvmMemPoolEntry.[133..139] are not used +-- but are reserved for future evolution of this MIB. +-- +jvmMemPoolCollectThreshold OBJECT-TYPE + SYNTAX JvmUnsigned64TC + UNITS "bytes" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The threshold value for the collection usage of this memory pool, + in bytes. A zero value (0) indicates that no threshold value is + configured. + When the amount of used memory crosses over this threshold + value the JVM will trigger a collection memory threshold exceeded + notification, and the jvmMemPoolCollectThreshdCount increases. + + If collection usage threshold is not supported, then this object, if + implemented, will always be equals to 0. In that case, attempting + to set this object will trigger an inconsistentValue error. + + See also jvmMemPoolCollectThreshdSupport. + + See java.lang.management.MemoryPoolMXBean. + getCollectionUsageThreshold(), + java.lang.management.MemoryPoolMXBean. + setCollectionUsageThreshold(long), + java.lang.management.MemoryPoolMXBean. + isCollectionUsageThresholdSupported(), + java.lang.management.MemoryPoolMXBean. + getCollectionUsageThresholdCount() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryPoolMXBean" + DEFVAL { 0 } + ::= { jvmMemPoolEntry 131 } + +jvmMemPoolCollectThreshdCount OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times that the memory usage has crossed + the collection usage threshold, as detected by the Java virtual + machine. + + If memory usage threshold is not supported, then this object, if + implemented, will always be equals to 0. + + See also jvmMemPoolCollectThreshdSupport. + + See java.lang.management.MemoryPoolMXBean. + getCollectionUsageThresholdCount(), + java.lang.management.MemoryPoolMXBean. + isCollectionUsageThresholdSupported() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryPoolMXBean" + ::= { jvmMemPoolEntry 132 } + +jvmMemPoolCollectThreshdSupport OBJECT-TYPE + SYNTAX JvmImplSupportStateTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Tells whether this memory pool supports collection usage threshold. + + See java.lang.management.MemoryPoolMXBean. + isCollectionUsageThresholdSupported() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryPoolMXBean" + ::= { jvmMemPoolEntry 133 } + +-- The JVM Memory Manager-Pool Relation Table +----------------------------------------------------------------------- +-- The JVM Memory Pool Table +-- +-- The jvmMemPoolTable represent memory pool abstract entities. +-- The jvmMemPoolTable contains one row per memory pool. +-- +-- See J2SE 5.0 API Specification, java.lang.management.MemoryMXBean for +-- a detailed description of the memory subsystem. +-- +-- See J2SE 5.0 API Specification, java.lang.management.MemoryPoolMXBean +-- for more information on memory pool. +-- +----------------------------------------------------------------------- +-- +-- We use the range jvmMemory.[110..119] for objects related to memory pools. +-- Object identifier arcs in the range jvmMemory.[111-119] are not used +-- but are reserved for future evolution of this MIB. +-- + +jvmMemMgrPoolRelTable OBJECT-TYPE + SYNTAX SEQUENCE OF JvmMemMgrPoolRelEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The Memory Manager-Pool Relation Table shows the + Memory Manager / Memory Pool relations, as returned by + MemoryPoolMXBean.getMemoryManagerNames() and + MemoryManagerMXBean.getMemoryPoolNames(). + This table imports the indexes from the jvmMemManagerTable table + and jvmMemPoolTable table. The jvmMemMgrRelManagerName and + jvmMemMgrRelPoolName objects are not actually necessary since + the indexes are self-sufficient to express the relationship - + but the names will make the table more understandable when displayed + in a management console. + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryPoolMXBean, + java.lang.management.MemoryManagerMXBean" + ::= { jvmMemory 120 } + +jvmMemMgrPoolRelEntry OBJECT-TYPE + SYNTAX JvmMemMgrPoolRelEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A row in this table indicates that the Memory Manager identified + by jvmMemManagerIndex manages the Memory Pool identified by + jvmMemPoolIndex. Note that a pool may be managed by several + memory managers, and a memory manager can manage several + memory pool. + + See java.lang.management.MemoryManagerMXBean.getMemoryPoolNames(), + java.lang.management.MemoryPoolMXBean.getMemoryManagerNames() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryPoolMXBean, + java.lang.management.MemoryManagerMXBean" + INDEX { jvmMemManagerIndex, jvmMemPoolIndex } + ::= { jvmMemMgrPoolRelTable 1 } + +JvmMemMgrPoolRelEntry ::= SEQUENCE { + jvmMemMgrRelManagerName JvmJavaObjectNameTC, + jvmMemMgrRelPoolName JvmJavaObjectNameTC +} + +jvmMemMgrRelManagerName OBJECT-TYPE + SYNTAX JvmJavaObjectNameTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name of the memory manager. + + See java.manangement.MemoryManagerMXBean.getName(); + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryManagerMXBean" + ::= { jvmMemMgrPoolRelEntry 2 } + +jvmMemMgrRelPoolName OBJECT-TYPE + SYNTAX JvmJavaObjectNameTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name of the memory pool. + + See java.manangement.MemoryPoolMXBean.getName(); + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryPoolMXBean" + ::= { jvmMemMgrPoolRelEntry 3 } + + +----------------------------------------------------------------------- +-- +-- The JVM Thread group +-- +-- A collection of objects used to monitor threads in the +-- Java Virtual Machine. These objects define the SNMP management +-- interface for the thread system of the Java virtual machine. +-- +-- The jvmThreadInstanceTable represents the threads which are currently +-- alive in the system. The representation of a thread is derived from the +-- set of methods in the ThreadMXBean that return information about a +-- given thread. +-- +-- See J2SE 5.0 API Specification, java.lang.management.ThreadMXBean for +-- a detailed description of the threading subsystem. +-- +----------------------------------------------------------------------- + +-- +----------------------------------------------------------------------- + +jvmThreading OBJECT IDENTIFIER ::= { jvmMgtMIBObjects 3 } + +-- The following objects are mapped from the ThreadMXBean interface. +----------------------------------------------------------------------- + +jvmThreadCount OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The current number of live threads. + + See java.lang.management.ThreadMXBean.getThreadCount() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.ThreadMXBean" + ::= { jvmThreading 1 } + +jvmThreadDaemonCount OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The current number of daemon threads. + + See java.lang.management.ThreadMXBean.getDaemonThreadCount() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.ThreadMXBean" + ::= { jvmThreading 2 } + +jvmThreadPeakCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The peak thread count since the execution of the application. + + See java.lang.management.ThreadMXBean.getPeakThreadCount() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.ThreadMXBean" + ::= { jvmThreading 3 } + +jvmThreadTotalStartedCount OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of threads created and started since the Java + Virtual Machine started. + + See java.lang.management.ThreadMXBean.getTotalStartedThreadCount() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.ThreadMXBean" + ::= { jvmThreading 4 } + +jvmThreadContentionMonitoring OBJECT-TYPE + SYNTAX JvmImplOptFeatureStateTC + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The state of the Thread Contention Monitoring feature. + This feature can be: + + unsupported: The JVM does not support Thread Contention Monitoring. + enabled : The JVM supports Thread Contention Monitoring, and it + is enabled. + disabled : The JVM supports Thread Contention Monitoring, and it + is disabled. + + Only enabled(3) and disabled(4) may be supplied as values to a + SET request. unsupported(1) can only be set internally by the + agent. + + When the feature is unsupported(1), any attempt to change + that value will fail: trying to set this object to + enabled(3) or disabled(4) will result in an `inconsistentValue' + error. Trying to set it to any other value will result in an + `wrongValue' error. + + See java.lang.management.ThreadMXBean. + isThreadContentionMonitoringSupported(), + java.lang.management.ThreadMXBean. + isThreadContentionMonitoringEnabled(), + java.lang.management.ThreadMXBean. + setThreadContentionMonitoringEnabled() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.ThreadMXBean" + ::= { jvmThreading 5 } + +jvmThreadCpuTimeMonitoring OBJECT-TYPE + SYNTAX JvmImplOptFeatureStateTC + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The state of the Thread CPU Time Monitoring feature. + This feature can be: + + unsupported: The JVM does not support Thread CPU Time Monitoring. + enabled : The JVM supports Thread CPU Time Monitoring, and it + is enabled. + disabled : The JVM supports Thread CPU Time Monitoring, and it + is disabled. + + Only enabled(3) and disabled(4) may be supplied as values to a + SET request. unsupported(1) can only be set internally by the + agent. + + When the feature is unsupported(1), any attempt to change + that value will fail: trying to set this object to + enabled(3) or disabled(4) will result in an `inconsistentValue' + error. Trying to set it to any other value will result in an + `wrongValue' error. + + See java.lang.management.ThreadMXBean. + isThreadCpuTimeSupported(), + java.lang.management.ThreadMXBean. + isThreadCpuTimeEnabled(), + java.lang.management.ThreadMXBean. + setThreadCpuTimeEnabled() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.ThreadMXBean" + ::= { jvmThreading 6 } + +jvmThreadPeakCountReset OBJECT-TYPE + SYNTAX JvmTimeMillis64TC + UNITS "milliseconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + " + This object indicates the last time - in milliseconds - at which + the peak thread count was reset to the current thread count. + This corresponds to a time stamp as returned by + java.lang.System.currentTimeMillis(). + + Setting this object to a time earlier than its current time value + has no effect. Setting this object to a time later than its current + time value causes the peak thread count statistic to be reset to + the current thread count. The new value of this object will be + the time at which the reset operation is triggered. + + There could be a delay between the time at which the reset operation + is triggered and the time at which the actual resetting happens, so + this value is only indicative. + + See java.lang.management.ThreadMXBean.resetPeakThreadCount() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.ThreadMXBean" + ::= { jvmThreading 7 } + + +-- Object identifiers in the range jvmThreading.[8-10] are reserved +-- for future evolution of this MIB. +-- +----------------------------------------------------------------------- +-- The JVM Thread Instance Table +-- +-- The jvmThreadInstanceTable represents the threads which are currently +-- alive in the system. The representation of a thread is derived from the +-- set of methods in the ThreadMXBean that return information about a +-- given thread. +-- +-- See J2SE 5.0 API Specification, java.lang.management.ThreadMXBean for +-- a detailed description of the threading subsystem. +-- See also J2SE 5.0 API Specification, java.lang.management.ThreadInfo, +-- and java.lang.Thread +-- +----------------------------------------------------------------------- + +jvmThreadInstanceTable OBJECT-TYPE + SYNTAX SEQUENCE OF JvmThreadInstanceEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The Thread Instance Table is built from all the methods of + ThreadMXBean that take a ThreadID as parameter. + + See java.lang.management.ThreadMXBean.getAllThreadIds() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.ThreadMXBean" + ::= { jvmThreading 10 } + +jvmThreadInstanceEntry OBJECT-TYPE + SYNTAX JvmThreadInstanceEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A row in this table represents a live thread. + Attributes in this row are built from all the methods of + ThreadMXBean that take a ThreadID as parameter. + + See java.lang.management.ThreadMXBean + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.ThreadMXBean" + INDEX { jvmThreadInstIndex } + ::= { jvmThreadInstanceTable 1 } + +JvmThreadInstanceEntry ::= SEQUENCE { + jvmThreadInstIndex JvmIndex64TC, + jvmThreadInstId JvmUnsigned64TC, + jvmThreadInstState JvmThreadStateTC, + jvmThreadInstBlockCount Counter64, + jvmThreadInstBlockTimeMs JvmTimeMillis64TC, + jvmThreadInstWaitCount Counter64, + jvmThreadInstWaitTimeMs JvmTimeMillis64TC, + jvmThreadInstCpuTimeNs JvmTimeNanos64TC, + jvmThreadInstLockName JvmJavaObjectNameTC, + jvmThreadInstLockOwnerPtr RowPointer, + jvmThreadInstName JvmJavaObjectNameTC +} + +jvmThreadInstIndex OBJECT-TYPE + SYNTAX JvmIndex64TC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An index uniquely identifying a live thread, and directly + derived from the value of jvmThreadInstId. The jvmThreadInstId + cannot be used directly as index in the table, because integer + indexes cannot exceed an unsigned 32 int. + + The jvmThreadInstIndex index is an 8 byte octet string as + defined by the JvmIndex64TC TEXTUAL-CONVENTION. Its value is + directly derived from the value of the corresponding ThreadID + returned by jvmThreadInstId. + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.ThreadMXBean, java.lang.Thread" + ::= { jvmThreadInstanceEntry 1 } + +jvmThreadInstId OBJECT-TYPE + SYNTAX JvmUnsigned64TC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The thread ID, as returned by Thread.getId(). + + See java.lang.management.ThreadMXBean.getThreadInfo(long,boolean). + getThreadId() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.ThreadMXBean, java.lang.Thread" + ::= { jvmThreadInstanceEntry 2 } + +jvmThreadInstState OBJECT-TYPE + SYNTAX JvmThreadStateTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The state of this thread instance. + + See java.lang.management.ThreadMXBean.getThreadInfo(long,boolean). + getThreadState() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.ThreadMXBean" + ::= { jvmThreadInstanceEntry 3 } + +jvmThreadInstBlockCount OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of times that this thread has blocked to enter + or re-enter a monitor.. + + See java.lang.management.ThreadMXBean.getThreadInfo(long,boolean). + getBlockedCount() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.ThreadMXBean" + ::= { jvmThreadInstanceEntry 4 } + +jvmThreadInstBlockTimeMs OBJECT-TYPE + SYNTAX JvmTimeMillis64TC + UNITS "milliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The approximate accumulated elapsed time (in millisecond) + that a thread has blocked to enter or re-enter a monitor since + it has started - or since thread contention monitoring was + enabled. + + This object is always set to 0 if thread contention monitoring + is disabled or not supported. + + See java.lang.management.ThreadMXBean.getThreadInfo(long,boolean). + getBlockedTime() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.ThreadMXBean" + ::= { jvmThreadInstanceEntry 5 } + +jvmThreadInstWaitCount OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of times that this thread has waited for + notification. + + See java.lang.management.ThreadMXBean.getThreadInfo(long,boolean). + getWaitedCount() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.ThreadMXBean" + ::= { jvmThreadInstanceEntry 6 } + +jvmThreadInstWaitTimeMs OBJECT-TYPE + SYNTAX JvmTimeMillis64TC + UNITS "milliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The approximate accumulated elapsed time (in millisecond) + that a thread has waited on a monitor through a + java.lang.Object.wait method since it has started - or since + thread contention monitoring wasenabled. + + This object is always set to 0 if thread contention monitoring + is disabled or not supported. + + See java.lang.management.ThreadMXBean.getThreadInfo(long,boolean). + getWaitedTime() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.ThreadMXBean" + ::= { jvmThreadInstanceEntry 7 } + +jvmThreadInstCpuTimeNs OBJECT-TYPE + SYNTAX JvmTimeNanos64TC + UNITS "nanoseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The approximate accumulated CPU time (in nanosecond) for a thread + since it has started - or since thread CPU time monitoring was + enabled. + + If the thread of the specified ID is not alive or does not exist, + or the CPU time measurement is disabled or not supported, + this object is set to 0. + + See java.lang.management.ThreadMXBean.getThreadCpuTime(long), + java.lang.management.ThreadMXBean.isThreadCpuTimeSupported(), + java.lang.management.ThreadMXBean.isThreadCpuTimeEnabled() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.ThreadMXBean" + ::= { jvmThreadInstanceEntry 8 } + +jvmThreadInstName OBJECT-TYPE + SYNTAX JvmJavaObjectNameTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "This thread name - as returned by Thread.getThreadName(). + + See java.lang.management.ThreadInfo.getThreadName() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.ThreadMXBean, + java.lang.management.ThreadInfo" + ::= { jvmThreadInstanceEntry 9 } + +jvmThreadInstLockName OBJECT-TYPE + SYNTAX JvmJavaObjectNameTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The string representation of the monitor lock that this thread + is blocked to enter or waiting to be notified through the + Object.wait method. + + See J2SE 5.0 API Specification, + java.lang.management.ThreadInfo.getLockName() + for more information on the format of this string. + + If this thread is not blocked then a zero-length string is returned. + + Note that the SNMP agent may have to truncate the string returned + by the underlying API if it does not fit in the JvmJavaObjectNameTC + (1023 bytes max). + + See java.lang.management.ThreadInfo.getLockName() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.ThreadMXBean, + java.lang.management.ThreadInfo" + ::= { jvmThreadInstanceEntry 10 } + +jvmThreadInstLockOwnerPtr OBJECT-TYPE + SYNTAX RowPointer + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A pointer to the thread which owns the monitor of the + object on which this thread instance is blocked. + This object will point to jvmThreadInstId of the + lock owner thread. + + If this thread is not blocked then 0.0 is returned. + + See java.lang.management.ThreadInfo.getLockOwnerId() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.ThreadMXBean, + java.lang.management.ThreadInfo" + ::= { jvmThreadInstanceEntry 11 } + +----------------------------------------------------------------------- +-- +-- The JVM Runtime group +-- +-- A collection of objects used to monitor the Java Virtual Machine +-- Runtime. These objects define the SNMP management interface for the +-- runtime system of the Java virtual machine. +-- +-- The JVM Runtime group defines object mapped from the +-- java.lang.management.RuntimeMXBean interface. +-- +-- See J2SE 5.0 API Specification, java.lang.management.RuntimeMXBean for +-- a detailed description of the runtime system. +-- +----------------------------------------------------------------------- + +jvmRuntime OBJECT IDENTIFIER ::= { jvmMgtMIBObjects 4 } + +-- The following objects are mapped from the RuntimeMXBean interface. +----------------------------------------------------------------------- + +jvmRTName OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name representing the running Java virtual machine. + + Note that the SNMP agent may have to truncate the name returned + by the underlying API if it does not fit in the DisplayString + (255 bytes max). + + See java.lang.management.RuntimeMXBean.getName() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + ::= { jvmRuntime 1 } + +jvmRTVMName OBJECT-TYPE + SYNTAX JvmJavaObjectNameTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Java virtual machine implementation name. + + See java.lang.management.RuntimeMXBean.getVmName() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + ::= { jvmRuntime 2 } + +jvmRTVMVendor OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Java virtual machine implementation vendor. + + Note that the SNMP agent may have to truncate the string returned + by the underlying API if it does not fit in the DisplayString + (255 bytes max). + + See java.lang.management.RuntimeMXBean.getVmVendor() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + ::= { jvmRuntime 3 } + +jvmRTVMVersion OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Java virtual machine implementation version. + + Note that the SNMP agent may have to truncate the string returned + by the underlying API if it does not fit in the DisplayString + (255 bytes max). + + See java.lang.management.RuntimeMXBean.getVmVersion() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + ::= { jvmRuntime 4 } + +jvmRTSpecName OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Java virtual machine specification name. + + Note that the SNMP agent may have to truncate the string returned + by the underlying API if it does not fit in the DisplayString + (255 bytes max). + + See java.lang.management.RuntimeMXBean.getSpecName() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + ::= { jvmRuntime 5 } + +jvmRTSpecVendor OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Java virtual machine specification vendor. + + Note that the SNMP agent may have to truncate the string returned + by the underlying API if it does not fit in the DisplayString + (255 bytes max). + + See java.lang.management.RuntimeMXBean.getSpecVendor() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + ::= { jvmRuntime 6 } + +jvmRTSpecVersion OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Java virtual machine specification version. + + Note that the SNMP agent may have to truncate the string returned + by the underlying API if it does not fit in the DisplayString + (255 bytes max). + + See java.lang.management.RuntimeMXBean.getSpecVersion() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + ::= { jvmRuntime 7 } + +jvmRTManagementSpecVersion OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The version of the management specification for the Java virtual + machine implementation. + + Note that the SNMP agent may have to truncate the string returned + by the underlying API if it does not fit in the DisplayString + (255 bytes max). + + See java.lang.management.RuntimeMXBean.getManagementSpecVersion() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + ::= { jvmRuntime 8 } + +jvmRTBootClassPathSupport OBJECT-TYPE + SYNTAX JvmImplSupportStateTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Indicates whether the Java virtual machine supports the + boot class path mechanism used by the bootstrap class loader + to search for class files. + + See java.lang.management.RuntimeMXBean.isBootClassPathSupported() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + ::= { jvmRuntime 9 } + +jvmRTInputArgsCount OBJECT-TYPE + SYNTAX JvmPositive32TC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of input arguments passed to the Java Virtual Machine. + + See java.lang.management.RuntimeMXBean.getInputArguments() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + ::= { jvmRuntime 10 } + +jvmRTUptimeMs OBJECT-TYPE + SYNTAX JvmTimeMillis64TC + UNITS "milliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Uptime of the Java virtual machine, in milliseconds. This is + equivalent to ( System.currentTimeMillis() - jvmStartTimeMs ). + + See also jvmRTStartTimeMs. + + See java.lang.management.RuntimeMXBean.getUptime() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + ::= { jvmRuntime 11 } + +jvmRTStartTimeMs OBJECT-TYPE + SYNTAX JvmTimeMillis64TC + UNITS "milliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The approximate time when the Java virtual machine started, in + milliseconds. This is a time stamp as returned by + System.currentTimeMillis(). This time will not change unless + the Java Virtual Machine is restarted. + + See also jvmRTUptimeMs. + + See java.lang.management.RuntimeMXBean.getStartTime() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + ::= { jvmRuntime 12 } + + +-- Object identifiers in the range jvmRuntime.[13-19] are reserved +-- for future evolution of this MIB. +-- +----------------------------------------------------------------------- +-- +-- The JVM Input Argument Table +-- +-- The jvmRTInputArgsTable contains one row per input argument given on +-- the Java command line. +-- +-- See J2SE 5.0 API Specification, +-- java.lang.management.RuntimeMXBean.getInputArguments() +-- for more information. +----------------------------------------------------------------------- + +jvmRTInputArgsTable OBJECT-TYPE + SYNTAX SEQUENCE OF JvmRTInputArgsEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The Input Argument Table lists the input arguments passed + to the Java Virtual Machine. + + The jvmRTInputArgsIndex is the index of the argument in + the array returned by RuntimeMXBean.getInputArguments(). + + See java.lang.management.RuntimeMXBean.getInputArguments() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + ::= { jvmRuntime 20 } + +jvmRTInputArgsEntry OBJECT-TYPE + SYNTAX JvmRTInputArgsEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Represent an input argument passed to the Java Virtual Machine. + + See java.lang.management.RuntimeMXBean.getInputArguments() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + INDEX { jvmRTInputArgsIndex } + ::= { jvmRTInputArgsTable 1 } + +JvmRTInputArgsEntry ::= SEQUENCE { + jvmRTInputArgsIndex JvmPositive32TC, + jvmRTInputArgsItem JvmArgValueTC +} + +jvmRTInputArgsIndex OBJECT-TYPE + SYNTAX JvmPositive32TC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The index of the input argument, as in the array returned + by RuntimeMXBean.getInputArguments(). + + See java.lang.management.RuntimeMXBean.getInputArguments() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + ::= { jvmRTInputArgsEntry 1 } + +jvmRTInputArgsItem OBJECT-TYPE + SYNTAX JvmArgValueTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "An input argument at index jvmRTInputArgsIndex, as in the array + returned by RuntimeMXBean.getInputArguments(). + + Note that the SNMP agent may have to truncate the string returned + by the underlying API if it does not fit in the JvmArgValueTC + (1023 bytes max). + + See java.lang.management.RuntimeMXBean.getInputArguments() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + ::= { jvmRTInputArgsEntry 2 } + + +----------------------------------------------------------------------- +-- +-- The JVM Boot Class Path Table +-- +-- The jvmRTBootClassPathTable contains one row per path element in the +-- bootclasspath. This table may not be implemented (or may be empty) if +-- the bootclasspath feature is not supported by the underlying +-- implementation. +-- +-- See J2SE 5.0 API Specification, +-- java.lang.management.RuntimeMXBean.getBootClassPath() +-- java.lang.management.RuntimeMXBean.isBootClassPathSupported() +-- for more information. +----------------------------------------------------------------------- + +jvmRTBootClassPathTable OBJECT-TYPE + SYNTAX SEQUENCE OF JvmRTBootClassPathEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The boot class path that is used by the bootstrap class loader + to search for a class file for loading. + + Note that the SNMP agent may have to truncate the bootclasspath + elements contained in the string returned by the underlying API + if it does not fit in the JvmPathElementTC (1023 bytes max). + + This table is not implemented (or empty) if jvmRTBootClassPathSupport + is unsupported(1). + + See java.lang.management.RuntimeMXBean.getBootClassPath() + java.lang.management.RuntimeMXBean.isBootClassPathSupported() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + ::= { jvmRuntime 21 } + +jvmRTBootClassPathEntry OBJECT-TYPE + SYNTAX JvmRTBootClassPathEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Represent a path element in the Java Virtual Machine bootclasspath. + + See java.lang.management.RuntimeMXBean.getBootClassPath() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + INDEX { jvmRTBootClassPathIndex } + ::= { jvmRTBootClassPathTable 1 } + +JvmRTBootClassPathEntry ::= SEQUENCE { + jvmRTBootClassPathIndex JvmPositive32TC, + jvmRTBootClassPathItem JvmPathElementTC +} + +jvmRTBootClassPathIndex OBJECT-TYPE + SYNTAX JvmPositive32TC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The index of the path element, as in the array obtained + by splitting RuntimeMXBean.getBootClassPath() in its elementary path + constituents. + + See java.lang.management.RuntimeMXBean.getBootClassPath() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + ::= { jvmRTBootClassPathEntry 1 } + +jvmRTBootClassPathItem OBJECT-TYPE + SYNTAX JvmPathElementTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "An path element at index jvmRTBootClassPathIndex, as in the + array obtained by splitting RuntimeMXBean.getBootClassPath() in + its elementary path constituents. + + Note that the SNMP agent may have to truncate the string returned + by the underlying API if it does not fit in the JvmPathElementTC + (1023 bytes max). + + See java.lang.management.RuntimeMXBean.getBootClassPath() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + ::= { jvmRTBootClassPathEntry 2 } + +----------------------------------------------------------------------- +-- +-- The JVM Class Path Table +-- +-- The jvmRTClassPathTable contains one row per path element in the +-- classpath. +-- +-- See J2SE 5.0 API Specification, +-- java.lang.management.RuntimeMXBean.getClassPath() +-- for more information. +----------------------------------------------------------------------- + +jvmRTClassPathTable OBJECT-TYPE + SYNTAX SEQUENCE OF JvmRTClassPathEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The class path that is used by the system class loader + to search for a class file. + + Note that the SNMP agent may have to truncate the classpath + elements contained in the string returned by the underlying API + if it does not fit in the JvmPathElementTC (1023 bytes max). + + See java.lang.management.RuntimeMXBean.getClassPath() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + ::= { jvmRuntime 22 } + +jvmRTClassPathEntry OBJECT-TYPE + SYNTAX JvmRTClassPathEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Represent a path element in the Java Virtual Machine classpath. + + See java.lang.management.RuntimeMXBean.getClassPath() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + INDEX { jvmRTClassPathIndex } + ::= { jvmRTClassPathTable 1 } + +JvmRTClassPathEntry ::= SEQUENCE { + jvmRTClassPathIndex JvmPositive32TC, + jvmRTClassPathItem JvmPathElementTC +} + +jvmRTClassPathIndex OBJECT-TYPE + SYNTAX JvmPositive32TC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The index of the path element, as in the array obtained + by splitting RuntimeMXBean.getClassPath() in its elementary + path constituents. + + See java.lang.management.RuntimeMXBean.getClassPath() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + ::= { jvmRTClassPathEntry 1 } + +jvmRTClassPathItem OBJECT-TYPE + SYNTAX JvmPathElementTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "An path element at index jvmRTClassPathIndex, as in the array + obtained by splitting RuntimeMXBean.getClassPath() in its elementary + path constituents. + + Note that the SNMP agent may have to truncate the string returned + by the underlying API if it does not fit in the JvmPathElementTC + (1023 bytes max). + + See java.lang.management.RuntimeMXBean.getClassPath() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + ::= { jvmRTClassPathEntry 2 } + +----------------------------------------------------------------------- +-- +-- The JVM Library Path Table +-- +-- The jvmRTLibraryPathTable contains one row per path element in the +-- librarypath. +-- +-- See J2SE 5.0 API Specification, +-- java.lang.management.RuntimeMXBean.getLibraryPath() +-- for more information. +----------------------------------------------------------------------- + +jvmRTLibraryPathTable OBJECT-TYPE + SYNTAX SEQUENCE OF JvmRTLibraryPathEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The library path. + + Note that the SNMP agent may have to truncate the librarypath + elements contained in the string returned by the underlying API + if it does not fit in the JvmPathElementTC (1023 bytes max). + + See java.lang.management.RuntimeMXBean.getLibraryPath() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + ::= { jvmRuntime 23 } + +jvmRTLibraryPathEntry OBJECT-TYPE + SYNTAX JvmRTLibraryPathEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Represent a path element in the Java Virtual Machine librarypath. + + See java.lang.management.RuntimeMXBean.getLibraryPath() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + INDEX { jvmRTLibraryPathIndex } + ::= { jvmRTLibraryPathTable 1 } + +JvmRTLibraryPathEntry ::= SEQUENCE { + jvmRTLibraryPathIndex JvmPositive32TC, + jvmRTLibraryPathItem JvmPathElementTC +} + +jvmRTLibraryPathIndex OBJECT-TYPE + SYNTAX JvmPositive32TC + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The index of the path element, as in the array obtained + by splitting RuntimeMXBean.getLibraryPath() in its elementary + constituents. + + See java.lang.management.RuntimeMXBean.getLibraryPath() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + ::= { jvmRTLibraryPathEntry 1 } + +jvmRTLibraryPathItem OBJECT-TYPE + SYNTAX JvmPathElementTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "An path element at index jvmRTLibraryPathIndex, as in the array + obtained by splitting RuntimeMXBean.getLibraryPath() in its elementary + path constituents. + + Note that the SNMP agent may have to truncate the string returned + by the underlying API if it does not fit in the JvmPathElementTC + (1023 bytes max). + + See java.lang.management.RuntimeMXBean.getLibraryPath() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.RuntimeMXBean" + ::= { jvmRTLibraryPathEntry 2 } + +----------------------------------------------------------------------- +-- +-- The JVM Compilation group +-- +-- A collection of objects used to monitor the Java Virtual Machine +-- Runtime Compiler (JIT). These objects define the SNMP management +-- interface for the compilation system of the Java virtual machine. +-- +-- The JVM Compilation group defines object mapped from the +-- java.lang.management.CompilationMXBean interface. +-- +-- See J2SE 5.0 API Specification, java.lang.management.CompilationMXBean for +-- a detailed description of the runtime system. +-- +----------------------------------------------------------------------- + +jvmCompilation OBJECT IDENTIFIER ::= { jvmMgtMIBObjects 5 } + +-- The following objects are mapped from the CompilationMXBean interface. +----------------------------------------------------------------------- + +jvmJITCompilerName OBJECT-TYPE + SYNTAX JvmJavaObjectNameTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name of the Just-in-time (JIT) compiler. + + See java.lang.management.CompilationMXBean.getName() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.CompilationMXBean" + ::= { jvmCompilation 1 } + +jvmJITCompilerTimeMs OBJECT-TYPE + SYNTAX JvmTimeMillis64TC + UNITS "milliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Gets the approximate accumulated elapsed time (in milliseconds) + spent in compilation since the Java virtual machine has started. + If multiple threads are used for compilation, this value is + the summation of the approximate time that each thread + spent in compilation. + + If compiler time monitoring is not supported, then this object + remains set to 0. + + See java.lang.management.CompilationMXBean.getTotalCompilationTime() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.CompilationMXBean" + ::= { jvmCompilation 2 } + + +jvmJITCompilerTimeMonitoring OBJECT-TYPE + SYNTAX JvmImplSupportStateTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Indicates whether the Java virtual machine supports + compilation time monitoring. + + See java.lang.management.CompilationMXBean. + isCompilationTimeMonitoringSupported() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.CompilationMXBean" + ::= { jvmCompilation 3 } + +----------------------------------------------------------------------- +-- +-- The JVM Operating System group +-- +-- A collection of objects used to monitor some resource of the +-- Operating System the Java Virtual Machine is running on. These objects +-- define the SNMP management interface offered by the Java virtual machine +-- for the operating system on which it is running. +-- +-- The JVM Operating System group defines object mapped from the +-- java.lang.management.OperatingSystemMXBean interface. +-- +-- See J2SE 5.0 API Specification, java.lang.management.OperatingSystemMXBean +-- for a detailed description of the operating system. +-- +----------------------------------------------------------------------- + +jvmOS OBJECT IDENTIFIER ::= { jvmMgtMIBObjects 6 } + +-- The following objects are mapped from the OperatingSystemMXBean interface. +----------------------------------------------------------------------- + +jvmOSName OBJECT-TYPE + SYNTAX JvmJavaObjectNameTC + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The operating system name. + + See java.lang.management.OperatingSystemMXBean.getName() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.OperatingSystemMXBean" + ::= { jvmOS 1 } + +jvmOSArch OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The operating system architecture. + + Note that the SNMP agent may have to truncate the string returned + by the underlying API if it does not fit in the DisplayString + (255 bytes max). + + See java.lang.management.OperatingSystemMXBean.getArch() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.OperatingSystemMXBean" + ::= { jvmOS 2 } + +jvmOSVersion OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The operating system version. + + Note that the SNMP agent may have to truncate the string returned + by the underlying API if it does not fit in the DisplayString + (255 bytes max). + + See java.lang.management.OperatingSystemMXBean.getVersion() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.OperatingSystemMXBean" + ::= { jvmOS 3 } + +jvmOSProcessorCount OBJECT-TYPE + + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of processors available to the Java virtual machine. + + See java.lang.management.OperatingSystemMXBean.getAvailableProcessors() + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.OperatingSystemMXBean" + ::= { jvmOS 4 } + +-- +-- NOTIFICATIONS +-- +----------------------------------------------------------------------- + +-- +-- Low Memory Notifications +-- + +jvmMgtMIBMemoryNotifs OBJECT IDENTIFIER ::= { jvmMgtMIBNotifications 2 } +jvmMgtMIBLowMemoryNotifs OBJECT IDENTIFIER ::= { jvmMgtMIBMemoryNotifs 1 } + +jvmLowMemoryPrefix OBJECT IDENTIFIER + ::= { jvmMgtMIBLowMemoryNotifs 0 } + +-- Not used at this time, but reserved for future evolution of this MIB: +-- +-- jvmLowMemoryData OBJECT IDENTIFIER +-- ::= { jvmMgtMIBLowMemoryNotifs 1 } +-- + +jvmLowMemoryPoolUsageNotif NOTIFICATION-TYPE + OBJECTS { jvmMemPoolName, jvmMemPoolUsed, jvmMemPoolThreshdCount } + STATUS current + DESCRIPTION + "This notification is sent when the memory usage threshold of + a memory pool is exceeded. + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryNotification, + java.lang.management.MemoryPoolMXBean" + ::= { jvmLowMemoryPrefix 1 } + +jvmLowMemoryPoolCollectNotif NOTIFICATION-TYPE + OBJECTS { jvmMemPoolName, jvmMemPoolCollectUsed, + jvmMemPoolCollectThreshdCount } + STATUS current + DESCRIPTION + "This notification is sent when the collection memory usage + threshold of a memory pool is exceeded. + " + REFERENCE "J2SE 5.0 API Specification, + java.lang.management.MemoryNotification, + java.lang.management.MemoryPoolMXBean" + ::= { jvmLowMemoryPrefix 2 } + +-- +-- Conformance Section +-- +----------------------------------------------------------------------- + +-- conformance information + +jvmMgtMIBCompliances + OBJECT IDENTIFIER ::= { jvmMgtMIBConformance 1 } +jvmMgtMIBGroups + OBJECT IDENTIFIER ::= { jvmMgtMIBConformance 2 } + + +-- compliance statements + +jvmManagementCompliance MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement for SNMP entities which + implement this MIB." + MODULE -- this module + MANDATORY-GROUPS { + jvmClassLoadingBasicGroup, + jvmClassLoadingSetGroup, + jvmMemoryBasicGroup, + jvmMemoryHeapUsageGroup, + jvmMemoryNonHeapUsageGroup, + jvmMemorySetGroup, + jvmMemManagerGroup, + jvmMemGCGroup, + jvmMemPoolBasicGroup, + jvmMemPoolUsageGroup, + jvmMemPoolPeakUsageGroup, + jvmMemPoolCollectUsageGroup, + jvmMemMgrPoolRelationGroup, + jvmThreadBasicGroup, + jvmThreadInstanceBasicGroup, + jvmRuntimeBasicGroup, + jvmOSGroup + } + + -- optional/conditional groups + GROUP jvmMemPoolMonitoringGroup + DESCRIPTION + "This group may not be implemented if the Java virtual + machine does not support low memory detection in memory usage. + " + GROUP jvmMemPoolCollectMonitoringGroup + DESCRIPTION + "This group may not be implemented if the Java virtual + machine does not support low memory detection in collection + memory usage. + " + GROUP jvmLowMemoryUsageNotifGroup + DESCRIPTION + "This group may not be implemented if the Java virtual + machine does not support low memory usage detection. + " + GROUP jvmLowMemoryCollectNotifGroup + DESCRIPTION + "This group may not be implemented if the Java virtual + machine does not support low collection memory usage detection. + " + GROUP jvmThreadInstanceCpuGroup + DESCRIPTION + "This group may not be implemented if the Java virtual + machine does not support CPU time measurement for other threads. + " + GROUP jvmThreadInstanceBlockGroup + DESCRIPTION + "This group may not be implemented if the Java virtual + machine does not support thread contention monitoring. + " + GROUP jvmRuntimeBootCPGroup + DESCRIPTION + "This group may not be implemented if the underlying + implementation does not support the bootclasspath feature. + " + GROUP jvmJITCompilerBasicGroup + DESCRIPTION + "This group may not be implemented if the Java virtual + machine has no compilation system. + " + GROUP jvmJITCompilerTimeStatGroup + DESCRIPTION + "This group may not be implemented if the Java virtual + machine has no compilation system, or does not support + JIT Compiler time statistics. + " + ::= { jvmMgtMIBCompliances 1 } + + +-- units of conformance + +jvmClassLoadingGroups OBJECT IDENTIFIER ::= { jvmMgtMIBGroups 1 } + +jvmClassLoadingBasicGroup OBJECT-GROUP + OBJECTS { + jvmClassesLoadedCount, + jvmClassesTotalLoadedCount, + jvmClassesUnloadedCount + } + STATUS current + DESCRIPTION + "A collection of objects that are mapped from JSR 163 + java.lang.management.ClassLoadingMXBean interface. + " + ::= { jvmClassLoadingGroups 1 } + +jvmClassLoadingSetGroup OBJECT-GROUP + OBJECTS { + jvmClassesVerboseLevel + } + STATUS current + DESCRIPTION + "A collection of writable scalar objects that are mapped from JSR 163 + java.lang.management.ClassLoadingMXBean interface, and make it possible + to act on class loading. Accessing these objects may + require special permissions - the agent implementation is + responsible for puting in place the appropriate access control + if needed. + " + ::= { jvmClassLoadingGroups 2 } + +jvmMemoryGroups OBJECT IDENTIFIER ::= { jvmMgtMIBGroups 2 } + +jvmMemoryBasicGroup OBJECT-GROUP + OBJECTS { + jvmMemoryPendingFinalCount + } + STATUS current + DESCRIPTION + "A collection of columnar objects that are mapped from JSR 163 + java.lang.management.MemoryManagerMXBean interface. + " + ::= { jvmMemoryGroups 1 } + +jvmMemoryHeapUsageGroup OBJECT-GROUP + OBJECTS { + jvmMemoryHeapInitSize, + jvmMemoryHeapUsed, + jvmMemoryHeapCommitted, + jvmMemoryHeapMaxSize + } + STATUS current + DESCRIPTION + "A collection of objects that are mapped from JSR 163 + java.lang.management.MemoryMXBean.getHeapMemoryUsage(). + When several of these objects are requested within a single + SNMP request, the agent must ensure that + java.lang.management.MemoryPoolMXBean.getHeapMemoryUsage() is + called only once, in order to guarantee that the set of + values returned for these objects remain coherent and give + a consistent snapshot of the heap memory usage made by + Heap Memory Pools. + " + ::= { jvmMemoryGroups 2 } + +jvmMemoryNonHeapUsageGroup OBJECT-GROUP + OBJECTS { + jvmMemoryNonHeapInitSize, + jvmMemoryNonHeapUsed, + jvmMemoryNonHeapCommitted, + jvmMemoryNonHeapMaxSize + } + STATUS current + DESCRIPTION + "A collection of objects that are mapped from JSR 163 + java.lang.management.MemoryMXBean.getNonHeapMemoryUsage(). + When several of these objects are requested within a single + SNMP request, the agent must ensure that + java.lang.management.MemoryPoolMXBean.getNonHeapMemoryUsage() is + called only once, in order to guarantee that the set of + values returned for these objects remain coherent and give + a consistent snapshot of the non heap memory usage made by + Non Heap Memory Pools. + " + ::= { jvmMemoryGroups 3 } + +jvmMemorySetGroup OBJECT-GROUP + OBJECTS { + jvmMemoryGCVerboseLevel, + jvmMemoryGCCall + } + STATUS current + DESCRIPTION + "A collection of writable scalar objects that are mapped from JSR 163 + java.lang.management.MemoryMXBean interface, and make it possible + to act on the Garbage Collector. Accessing these objects may + require special permissions - the agent implementation is + responsible for puting in place the appropriate access control + if needed. + " + ::= { jvmMemoryGroups 4 } + +jvmMemManagerGroup OBJECT-GROUP + OBJECTS { + jvmMemManagerName, + jvmMemManagerState + } + STATUS current + DESCRIPTION + "A collection of columnar objects that are mapped from JSR 163 + java.lang.management.MemoryManagerMXBean interface. + " + ::= { jvmMemoryGroups 5 } + +jvmMemGCGroup OBJECT-GROUP + OBJECTS { + jvmMemGCCount, + jvmMemGCTimeMs + } + STATUS current + DESCRIPTION + "A collection of columnar objects that are mapped from JSR 163 + java.lang.management.GarbageCollectorMXBean interface, and are + specific to GarbageCollector MXBeans. + These objects are used to model the inheritence link between + GarbageCollectorMXBean and its super interface - MemoryManagerMXBean. + " + ::= { jvmMemoryGroups 6 } + +jvmMemPoolGroups OBJECT IDENTIFIER ::= { jvmMemoryGroups 7 } + +jvmMemPoolBasicGroup OBJECT-GROUP + OBJECTS { + jvmMemPoolName, + jvmMemPoolType, + jvmMemPoolState, + jvmMemPoolPeakReset, + jvmMemPoolThreshdSupport, + jvmMemPoolCollectThreshdSupport + } + STATUS current + DESCRIPTION + "A collection of columnar objects that are mapped from JSR 163 + java.lang.management.MemoryPoolMXBean interface. + " + ::= { jvmMemPoolGroups 1 } + +jvmMemPoolMonitoringGroup OBJECT-GROUP + OBJECTS { + jvmMemPoolThreshold, + jvmMemPoolThreshdCount + } + STATUS current + DESCRIPTION + "Memory usage threshold objects mapped from + JSR 163 java.lang.management.MemoryPoolMXBean interface, which makes + it possible to configure low memory detection. + Accessing this object may require special permissions - the agent + implementation is responsible for puting in place the appropriate + access control if needed. + " + ::= { jvmMemPoolGroups 2 } + +jvmMemPoolUsageGroup OBJECT-GROUP + OBJECTS { + jvmMemPoolInitSize, + jvmMemPoolUsed, + jvmMemPoolCommitted, + jvmMemPoolMaxSize + } + STATUS current + DESCRIPTION + "A collection of objects that are mapped from JSR 163 + java.lang.management.MemoryPoolMXBean.getUsage(). + When several of these objects are requested within a single + SNMP request, the agent must ensure that + java.lang.management.MemoryPoolMXBean.getUsage() is + called only once, in order to guarantee that the set of + values returned for these objects remain coherent and give + a consistent snapshot of the memory used by this Memory + Pool. + " + ::= { jvmMemPoolGroups 3 } + +jvmMemPoolPeakUsageGroup OBJECT-GROUP + OBJECTS { + jvmMemPoolPeakUsed, + jvmMemPoolPeakCommitted, + jvmMemPoolPeakMaxSize + } + STATUS current + DESCRIPTION + "A collection of objects that are mapped from JSR 163 + java.lang.management.MemoryPoolMXBean.getPeakUsage(). + When several of these objects are requested within a single + SNMP request, the agent must ensure that + java.lang.management.MemoryPoolMXBean.getPeakUsage() is + called only once, in order to guarantee that the set of + values returned for these objects remain coherent and give + a consistent snapshot of the peak memory usage made by + this Memory Pool. + " + ::= { jvmMemPoolGroups 4 } + +jvmMemPoolCollectUsageGroup OBJECT-GROUP + OBJECTS { + jvmMemPoolCollectUsed, + jvmMemPoolCollectCommitted, + jvmMemPoolCollectMaxSize + } + STATUS current + DESCRIPTION + "A collection of objects that are mapped from JSR 163 + java.lang.management.MemoryPoolMXBean.getCollectionUsage(). + When several of these objects are requested within a single + SNMP request, the agent must ensure that + java.lang.management.MemoryPoolMXBean.getCollectionUsage() is + called only once, in order to guarantee that the set of + values returned for these objects remain coherent and give + a consistent snapshot of the collection memory usage made by + this Memory Pool. + " + ::= { jvmMemPoolGroups 5 } + +jvmMemPoolCollectMonitoringGroup OBJECT-GROUP + OBJECTS { + jvmMemPoolCollectThreshold, + jvmMemPoolCollectThreshdCount + } + STATUS current + DESCRIPTION + "Memory collection usage threshold objects mapped from JSR 163 + java.lang.management.MemoryPoolMXBean interface, which makes + it possible to configure low memory detection. + Accessing this object may require special permissions - the agent + implementation is responsible for putting in place the appropriate + access control if needed. + " + ::= { jvmMemPoolGroups 6 } + + +jvmMemMgrPoolRelationGroup OBJECT-GROUP + OBJECTS { + jvmMemMgrRelManagerName, + jvmMemMgrRelPoolName + } + STATUS current + DESCRIPTION + "A collection of columnar objects that are mapped from JSR 163 + java.lang.management.MemoryPoolMXBean and + java.lang.management.MemoryManagerMXBean interface, and show the + relationship between Memory Managers and Memory Pools. + " + ::= { jvmMemoryGroups 8 } + +jvmThreadGroups OBJECT IDENTIFIER ::= { jvmMgtMIBGroups 3 } + +jvmThreadBasicGroup OBJECT-GROUP + OBJECTS { + jvmThreadCount, + jvmThreadDaemonCount, + jvmThreadPeakCount, + jvmThreadTotalStartedCount, + jvmThreadContentionMonitoring, + jvmThreadCpuTimeMonitoring, + jvmThreadPeakCountReset + } + STATUS current + DESCRIPTION + "A collection of scalar objects that are mapped from JSR 163 + java.lang.management.ThreadMXBean interface. + " + ::= { jvmThreadGroups 1 } + +jvmThreadInstanceGroups OBJECT IDENTIFIER ::= { jvmThreadGroups 2 } + +jvmThreadInstanceBasicGroup OBJECT-GROUP + OBJECTS { + jvmThreadInstId, + jvmThreadInstState, + jvmThreadInstName, + jvmThreadInstLockName, + jvmThreadInstLockOwnerPtr + } + STATUS current + DESCRIPTION + "A collection of columnar objects that are mapped from JSR 163 + java.lang.management.ThreadMXBean interface, and are + relative to an instance of java.lang.Thread. + " + ::= { jvmThreadInstanceGroups 1} + +jvmThreadInstanceCpuGroup OBJECT-GROUP + OBJECTS { + jvmThreadInstCpuTimeNs + } + STATUS current + DESCRIPTION + "A columnar object mapped from JSR 163 + java.lang.management.ThreadMXBean interface which provides CPU + time statistics about an instance of java.lang.Thread. + " + ::= { jvmThreadInstanceGroups 2 } + + +jvmThreadInstanceBlockGroup OBJECT-GROUP + OBJECTS { + jvmThreadInstBlockCount, + jvmThreadInstBlockTimeMs, + jvmThreadInstWaitCount, + jvmThreadInstWaitTimeMs + } + STATUS current + DESCRIPTION + "A collection of columnar objects that are mapped from JSR 163 + java.lang.management.ThreadMXBean interface, and which provide + synchronization statistics about an instance of java.lang.Thread. + " + ::= { jvmThreadInstanceGroups 3 } + + +jvmRuntimeGroups OBJECT IDENTIFIER ::= { jvmMgtMIBGroups 4 } + +jvmRuntimeBasicGroup OBJECT-GROUP + OBJECTS { + jvmRTName, + jvmRTVMName, + jvmRTVMVendor, + jvmRTVMVersion, + jvmRTSpecName, + jvmRTSpecVendor, + jvmRTSpecVersion, + jvmRTManagementSpecVersion, + jvmRTUptimeMs, + jvmRTStartTimeMs, + jvmRTBootClassPathSupport, + jvmRTInputArgsCount, + jvmRTInputArgsItem, + jvmRTClassPathItem, + jvmRTLibraryPathItem + } + STATUS current + DESCRIPTION + "A collection of objects that are mapped from JSR 163 + java.lang.management.RuntimeMXBean interface. + " + ::= { jvmRuntimeGroups 1 } + + +jvmRuntimeBootCPGroup OBJECT-GROUP + OBJECTS { + jvmRTBootClassPathItem + } + STATUS current + DESCRIPTION + "A columnar object that is mapped from JSR 163 + java.lang.management.RuntimeMXBean.getBootClassPath() interface, + and provide information about bootclasspath elements. + " + ::= { jvmRuntimeGroups 2 } + +jvmJITCompilerGroups OBJECT IDENTIFIER ::= { jvmMgtMIBGroups 5 } + +jvmJITCompilerBasicGroup OBJECT-GROUP + OBJECTS { + jvmJITCompilerName, + jvmJITCompilerTimeMonitoring + } + STATUS current + DESCRIPTION + "A collection of objects that are mapped from JSR 163 + java.lang.management.CompilationMXBean interface. + " + ::= { jvmJITCompilerGroups 1 } + +jvmJITCompilerTimeStatGroup OBJECT-GROUP + OBJECTS { + jvmJITCompilerTimeMs + } + STATUS current + DESCRIPTION + "A collection of objects that are mapped from JSR 163 + java.lang.management.CompilationMXBean interface and provide + time statistic about the JIT Compiler. + " + ::= { jvmJITCompilerGroups 2 } + +jvmOSGroup OBJECT-GROUP + OBJECTS { + jvmOSName, + jvmOSArch, + jvmOSVersion, + jvmOSProcessorCount + } + STATUS current + DESCRIPTION + "A collection of objects that are mapped from JSR 163 + java.lang.management.OperatingSystemMXBean interface. + " + ::= { jvmMgtMIBGroups 6 } + +jvmLowMemoryUsageNotifGroup NOTIFICATION-GROUP + NOTIFICATIONS { + jvmLowMemoryPoolUsageNotif + } + STATUS current + DESCRIPTION + "A collection of notifications emitted when low + memory usage conditions are detected. + " + ::= { jvmMgtMIBGroups 7 } + +jvmLowMemoryCollectNotifGroup NOTIFICATION-GROUP + NOTIFICATIONS { + jvmLowMemoryPoolCollectNotif + } + STATUS current + DESCRIPTION + "A collection of notifications emitted when low + collection memory usage conditions are detected. + " + ::= { jvmMgtMIBGroups 8 } + +END diff --git a/tomcat6/files/default/dtomcat6 b/tomcat6/files/default/dtomcat6 new file mode 100755 index 0000000..e79fd5e --- /dev/null +++ b/tomcat6/files/default/dtomcat6 @@ -0,0 +1,81 @@ +#!/bin/bash + +# Get the tomcat config (use this for environment specific settings) +if [ -z "${TOMCAT_CFG}" ]; then + TOMCAT_CFG="/etc/tomcat6/tomcat6.conf" +fi + +if [ -r "$TOMCAT_CFG" ]; then + . $TOMCAT_CFG +fi + +# CLASSPATH munging +if [ -n "$JSSE_HOME" ]; then + CLASSPATH="${CLASSPATH}:$(build-classpath jcert jnet jsse 2>/dev/null)" +fi +CLASSPATH="${CLASSPATH}:${CATALINA_HOME}/bin/bootstrap.jar" +CLASSPATH="${CLASSPATH}:${CATALINA_HOME}/bin/tomcat-juli.jar" +CLASSPATH="${CLASSPATH}:$(build-classpath commons-daemon 2>/dev/null)" + +if [ "$1" = "start" ]; then + ${JAVA_HOME}/bin/java $JAVA_OPTS $CATALINA_OPTS \ + -classpath "$CLASSPATH" \ + -Dcatalina.base="$CATALINA_BASE" \ + -Dcatalina.home="$CATALINA_HOME" \ + -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" \ + -Djava.io.tmpdir="$CATALINA_TMPDIR" \ + -Djava.util.logging.config.file="${CATALINA_BASE}/conf/logging.properties" \ + -Djava.util.logging.manager="org.apache.juli.ClassLoaderLogManager" \ + org.apache.catalina.startup.Bootstrap start \ + >> ${CATALINA_BASE}/logs/catalina.out 2>&1 & + if [ ! -z "$CATALINA_PID" ]; then + echo $! > $CATALINA_PID + fi +elif [ "$1" = "start-security" ]; then + ${JAVA_HOME}/bin/java $JAVA_OPTS $CATALINA_OPTS \ + -classpath "$CLASSPATH" \ + -Dcatalina.base="$CATALINA_BASE" \ + -Dcatalina.home="$CATALINA_HOME" \ + -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" \ + -Djava.io.tmpdir="$CATALINA_TMPDIR" \ + -Djava.security.manager \ + -Djava.security.policy="${CATALINA_BASE}/conf/catalina.policy" \ + -Djava.util.logging.config.file="${CATALINA_BASE}/conf/logging.properties" \ + -Djava.util.logging.manager="org.apache.juli.ClassLoaderLogManager" \ + org.apache.catalina.startup.Bootstrap start \ + >> ${CATALINA_BASE}/logs/catalina.out 2>&1 & + if [ ! -z "$CATALINA_PID" ]; then + echo $! > $CATALINA_PID + fi +elif [ "$1" = "start-jdpa" ]; then + ${JAVA_HOME}/bin/java $JAVA_OPTS $CATALINA_OPTS \ + -agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n\ + -classpath "$CLASSPATH" \ + -Dcatalina.base="$CATALINA_BASE" \ + -Dcatalina.home="$CATALINA_HOME" \ + -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" \ + -Djava.io.tmpdir="$CATALINA_TMPDIR" \ + -Djava.util.logging.config.file="${CATALINA_BASE}/conf/logging.properties" \ + -Djava.util.logging.manager="org.apache.juli.ClassLoaderLogManager" \ + org.apache.catalina.startup.Bootstrap start \ + >> ${CATALINA_BASE}/logs/catalina.out 2>&1 & + if [ ! -z "$CATALINA_PID" ]; then + echo $! > $CATALINA_PID + fi +elif [ "$1" = "stop" ]; then + ${JAVA_HOME}/bin/java $CATALINA_OPTS \ + -classpath "$CLASSPATH" \ + -Dcatalina.base="$CATALINA_BASE" \ + -Dcatalina.home="$CATALINA_HOME" \ + -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" \ + -Djava.io.tmpdir="$CATALINA_TMPDIR" \ + org.apache.catalina.startup.Bootstrap stop \ + >> ${CATALINA_BASE}/logs/catalina.out 2>&1 +elif [ "$1" = "version" ]; then + ${JAVA_HOME}/bin/java -classpath ${CATALINA_HOME}/lib/catalina.jar \ + org.apache.catalina.util.ServerInfo +else + echo "Usage: $0 {start|start-security|stop|version}" + exit 1 +fi + diff --git a/tomcat6/files/default/logging.properties b/tomcat6/files/default/logging.properties new file mode 100644 index 0000000..f9bdd00 --- /dev/null +++ b/tomcat6/files/default/logging.properties @@ -0,0 +1,73 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. + +#handlers = 1catalina.org.apache.juli.FileHandler, 2localhost.org.apache.juli.FileHandler, 3manager.org.apache.juli.FileHandler, 4admin.org.apache.juli.FileHandler, 5host-manager.org.apache.juli.FileHandler, java.util.logging.ConsoleHandler +handlers = java.util.logging.ConsoleHandler + +#.handlers = 1catalina.org.apache.juli.FileHandler, java.util.logging.ConsoleHandler +.handlers = java.util.logging.ConsoleHandler + +############################################################# +## Handler specific properties. +## Describes specific configuration info for Handlers. +############################################################# + +#1catalina.org.apache.juli.FileHandler.level = FINE +#1catalina.org.apache.juli.FileHandler.directory = ${catalina.base}/logs +#1catalina.org.apache.juli.FileHandler.prefix = catalina. + +#2localhost.org.apache.juli.FileHandler.level = FINE +#2localhost.org.apache.juli.FileHandler.directory = ${catalina.base}/logs +#2localhost.org.apache.juli.FileHandler.prefix = localhost. + +#3manager.org.apache.juli.FileHandler.level = FINE +#3manager.org.apache.juli.FileHandler.directory = ${catalina.base}/logs +#3manager.org.apache.juli.FileHandler.prefix = manager. + +#4admin.org.apache.juli.FileHandler.level = FINE +#4admin.org.apache.juli.FileHandler.directory = ${catalina.base}/logs +#4admin.org.apache.juli.FileHandler.prefix = admin. + +#5host-manager.org.apache.juli.FileHandler.level = FINE +#5host-manager.org.apache.juli.FileHandler.directory = ${catalina.base}/logs +#5host-manager.org.apache.juli.FileHandler.prefix = host-manager. + +java.util.logging.ConsoleHandler.level = INFO +java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter + + +############################################################# +## Facility specific properties. +## Provides extra control for each logger. +############################################################# + +org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = INFO +org.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers = java.util.logging.ConsoleHandler + +#org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].level = INFO +#org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].handlers = 3manager.org.apache.juli.FileHandler + +#org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/admin].level = INFO +#org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/admin].handlers = 4admin.org.apache.juli.FileHandler + +#org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].level = INFO +#org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].handlers = 5host-manager.org.apache.juli.FileHandler + +## For example, set the com.xyz.foo logger to only log SEVERE +## messages: +##org.apache.catalina.startup.ContextConfig.level = FINE +##org.apache.catalina.startup.HostConfig.level = FINE +##org.apache.catalina.session.ManagerBase.level = FINE +##org.apache.catalina.core.AprLifecycleListener.level=FINE \ No newline at end of file diff --git a/tomcat6/files/default/tomcat6 b/tomcat6/files/default/tomcat6 new file mode 100644 index 0000000..e39819e --- /dev/null +++ b/tomcat6/files/default/tomcat6 @@ -0,0 +1,321 @@ +#!/bin/bash +# +# tomcat6 This shell script takes care of starting and stopping Tomcat +# +# chkconfig: - 80 20 +# +### BEGIN INIT INFO +# Provides: tomcat6 +# Required-Start: $network $syslog +# Required-Stop: $network $syslog +# Default-Start: +# Default-Stop: +# Description: Release implementation for Servlet 2.5 and JSP 2.1 +# Short-Description: start and stop tomcat +### END INIT INFO +# +# - originally written by Henri Gomez, Keith Irwin, and Nicolas Mailhot +# - heavily rewritten by Deepak Bhole and Jason Corley +# + +ulimit -n 4096 + +# set a minimalist PATH +PATH="/bin:/sbin" + +NAME="$(basename $0)" +unset ISBOOT +if [ "${NAME:0:1}" = "S" -o "${NAME:0:1}" = "K" ]; then + NAME="${NAME:3}" + ISBOOT="1" +fi + +# For SELinux we need to use 'runuser' not 'su' +if [ -x "/sbin/runuser" ]; then + SU="/sbin/runuser" +else + SU="/bin/su" +fi + +# Get the tomcat config (use this for environment specific settings) +TOMCAT_CFG="/etc/tomcat6/tomcat6.conf" +if [ -r "$TOMCAT_CFG" ]; then + . $TOMCAT_CFG +fi + +# Get instance specific config file +if [ -r "/etc/sysconfig/${NAME}" ]; then + . /etc/sysconfig/${NAME} +fi + +# Define which connector port to use +CONNECTOR_PORT="${CONNECTOR_PORT:-8080}" + +# Path to the tomcat launch script +TOMCAT_SCRIPT="/usr/bin/dtomcat6" + +# Tomcat program name +TOMCAT_PROG="$NAME" + +# Define the tomcat username +TOMCAT_USER="${TOMCAT_USER:-tomcat}" + +# Define the tomcat log file +TOMCAT_LOG="${TOMCAT_LOG:-/var/log/tomcat6/catalina.out}" + +touch $TOMCAT_LOG +chown ${TOMCAT_USER}:${TOMCAT_USER} $TOMCAT_LOG + +RETVAL="0" + +# pulled from RHEL4 /etc/rc.d/init.d/functions +function checkpid() { + local i + for i in $* ; do + if [ -d "/proc/${i}" ]; then + return 0 + fi + done + return 1 +} + +# pulled from RHEL4 /etc/rc.d/init.d/functions +function echo_failure() { + echo -en "\\033[60G" + echo -n "[ " + echo -n $"FAILED" + echo -n " ]" + echo -ne "\r" + return 1 +} + +# pulled from RHEL4 /etc/rc.d/init.d/functions +function echo_success() { + echo -en "\\033[60G" + echo -n "[ " + echo -n $"OK" + echo -n " ]" + echo -ne "\r" + return 0 +} + +# Look for open ports, as the function name might imply +function findFreePorts() { + local isSet1="false" + local isSet2="false" + local isSet3="false" + local lower="8000" + randomPort1="0" + randomPort2="0" + randomPort3="0" + local -a listeners="( $( + netstat -ntl | \ + awk '/^tcp/ {gsub("(.)*:", "", $4); print $4}' + ) )" + while [ "$isSet1" = "false" ] || \ + [ "$isSet2" = "false" ] || \ + [ "$isSet3" = "false" ]; do + let port="${lower}+${RANDOM:0:4}" + if [ -z `expr " ${listeners[*]} " : ".*\( $port \).*"` ]; then + if [ "$isSet1" = "false" ]; then + export randomPort1="$port" + isSet1="true" + elif [ "$isSet2" = "false" ]; then + export randomPort2="$port" + isSet2="true" + elif [ "$isSet3" = "false" ]; then + export randomPort3="$port" + isSet3="true" + fi + fi + done +} + +function makeHomeDir() { + if [ ! -d "$CATALINA_HOME" ]; then + echo "$CATALINA_HOME does not exist, creating" + if [ ! -d "/usr/share/${NAME}" ]; then + mkdir /usr/share/${NAME} + cp -pLR /usr/share/tomcat6/* /usr/share/${NAME} + fi + mkdir -p /var/log/${NAME} \ + /var/cache/${NAME} \ + /var/tmp/${NAME} + ln -fs /var/cache/${NAME} ${CATALINA_HOME}/work + ln -fs /var/tmp/${NAME} ${CATALINA_HOME}/temp + cp -pLR /usr/share/${NAME}/bin $CATALINA_HOME + cp -pLR /usr/share/${NAME}/conf $CATALINA_HOME + ln -fs /usr/share/java/tomcat6 ${CATALINA_HOME}/lib + ln -fs /usr/share/tomcat6/webapps ${CATALINA_HOME}/webapps + chown ${TOMCAT_USER}:${TOMCAT_USER} /var/log/${NAME} + fi +} + +function parseOptions() { + options="" + options="$options $( + awk '!/^#/ && !/^$/ { ORS=" "; print "export ", $0, ";" }' \ + $TOMCAT_CFG + )" + if [ -r "/etc/sysconfig/${NAME}" ]; then + options="$options $( + awk '!/^#/ && !/^$/ { ORS=" "; + print "export ", $0, ";" }' \ + /etc/sysconfig/${NAME} + )" + fi + TOMCAT_SCRIPT="$options $TOMCAT_SCRIPT" +} + +# See how we were called. +function start() { + echo -n "Starting ${TOMCAT_PROG}: " + if [ -f "/var/lock/subsys/${NAME}" ] ; then + if [ -f "/var/run/${NAME}.pid" ]; then + read kpid < /var/run/${NAME}.pid + if checkpid $kpid 2>&1; then + echo "$NAME process already running" + return -1 + else + echo "lock file found but no process running for" + echo "pid $kpid, continuing" + fi + fi + fi + # fix permissions on the log and pid files + export CATALINA_PID="/var/run/${NAME}.pid" + touch $CATALINA_PID + chown ${TOMCAT_USER}:${TOMCAT_USER} $CATALINA_PID + touch $TOMCAT_LOG + chown ${TOMCAT_USER}:${TOMCAT_USER} $TOMCAT_LOG + if [ "$CATALINA_HOME" != "/usr/share/tomcat6" ]; then + # Create a tomcat directory if it doesn't exist + makeHomeDir + # If CATALINA_HOME doesn't exist modify port number so that + # multiple instances don't interfere with each other + findFreePorts + sed -i -e "s/8005/${randomPort1}/g" -e "s/8080/${CONNECTOR_PORT}/g" \ + -e "s/8009/${randomPort2}/g" -e "s/8443/${randomPort3}/g" \ + ${CATALINA_HOME}/conf/server.xml + fi + if [ "$JDPA" = "true" ]; then + START="start-jdpa" + else + START="start" + fi + if [ "$SECURITY_MANAGER" = "true" ]; then + $SU - $TOMCAT_USER -c "$TOMCAT_SCRIPT start-security" \ + >> $TOMCAT_LOG 2>&1 + else + $SU - $TOMCAT_USER -c "$TOMCAT_SCRIPT $START" >> $TOMCAT_LOG 2>&1 + fi + RETVAL="$?" + if [ "$RETVAL" -eq 0 ]; then + echo_success + touch /var/lock/subsys/${NAME} + else + echo_failure + fi + echo + return $RETVAL +} + +function status() { + RETVAL="1" + if [ -f "/var/run/${NAME}.pid" ]; then + read kpid < /var/run/${NAME}.pid + if checkpid $kpid 2>&1; then + echo "$0 is already running (${kpid})" + RETVAL="0" + else + echo "lock file found but no process running for pid $kpid" + fi + else + pid="$(/usr/bin/pgrep -u tomcat java)" + if [ -n "$pid" ]; then + echo "$0 running (${pid}) but no PID file exists" + RETVAL="0" + else + echo "$0 is stopped" + fi + fi + return $RETVAL +} + +function stop() { + echo -n "Stopping $TOMCAT_PROG: " + if [ -f "/var/lock/subsys/${NAME}" ]; then + $SU - $TOMCAT_USER -c "$TOMCAT_SCRIPT stop" >> $TOMCAT_LOG 2>&1 + RETVAL="$?" + if [ "$RETVAL" -eq "0" ]; then + count="0" + if [ -f "/var/run/${NAME}.pid" ]; then + read kpid < /var/run/${NAME}.pid + until [ "$(ps --pid $kpid | grep -c $kpid)" -eq "0" ] || \ + [ "$count" -gt "$SHUTDOWN_WAIT" ]; do + if [ "$SHUTDOWN_VERBOSE" = "true" ]; then + echo -n -e "\nwaiting for processes $kpid to exit" + fi + sleep 1 + let count="${count}+1" + done + if [ "$count" -gt "$SHUTDOWN_WAIT" ]; then + if [ "$SHUTDOWN_VERBOSE" = "true" ]; then + echo -n -e "\nkilling processes which didn't stop" + echo -n -e "after " + echo -n "$SHUTDOWN_WAIT seconds" + fi + kill -9 $kpid + fi + echo_success + if [ "$count" -gt "0" ]; then + echo -n -e "\n" + fi + fi + rm -f /var/lock/subsys/${NAME} /var/run/${NAME}.pid + else + echo_failure + fi + fi +} + + +# See how we were called. +case "$1" in + start) + parseOptions + start + ;; + start-jdpa) + parseOptions + JDPA="true" + start + ;; + stop) + parseOptions + stop + ;; + restart) + parseOptions + stop + sleep 2 + start + ;; + condrestart) + if [ -f "/var/run/${NAME}.pid" ]; then + restart + fi + ;; + status) + status + ;; + version) + $TOMCAT_SCRIPT version + ;; + *) + echo -n "Usage: $TOMCAT_PROG " + echo "{start|start-jdpa|stop|restart|condrestart|status|version}" + exit 1 +esac + +exit $RETVAL diff --git a/tomcat6/libraries/tomcat.rb b/tomcat6/libraries/tomcat.rb new file mode 100644 index 0000000..cfe6cf8 --- /dev/null +++ b/tomcat6/libraries/tomcat.rb @@ -0,0 +1,58 @@ +require 'net/http' +require 'net/https' + +class Tomcat + # wrapper arount tomcat manager http api + + def initialize(opts={}) + @configuration = opts + end + + def configuration + @configuration + end + + def install + tag_param = (@configuration[:tag])?"&tag=#{@configuration[:tag]}":"" + get("/manager/deploy?path=#{@configuration[:path]}&war=file:#{@configuration[:war]}") + end + + def update + tag_param = (@configuration[:tag])?"&tag=#{@configuration[:tag]}":"" + get("/manager/deploy?path=#{@configuration[:path]}&war=file:#{@configuration[:war]}&update=true") + end + + def undeploy + get("/manager/undeploy?path=#{@configuration[:path]}") + end + + def reload + get("/manager/reload?path=#{@configuration[:path]}") + end + + def start + get("/manager/start?path=#{@configuration[:path]}") + end + + def stop + get("/manager/stop?path=#{@configuration[:path]}") + end + + def status + get("/manager/status") + end + + def get(url) + site = Net::HTTP.new(@configuration[:host], @configuration[:port]) + site.use_ssl = false + site.read_timeout=180 + result = nil + begin + result = site.get2( url, 'Authorization' => 'Basic ' + ["#{@configuration[:admin]}:#{@configuration[:password]}"].pack('m').strip) + rescue Timeout::Error => e + raise RuntimeError, "Timeout Error while calling #{url}", caller + end + result + end + +end diff --git a/tomcat6/libraries/tomcat_manager.rb b/tomcat6/libraries/tomcat_manager.rb new file mode 100644 index 0000000..a2bd7a2 --- /dev/null +++ b/tomcat6/libraries/tomcat_manager.rb @@ -0,0 +1,233 @@ + +require File.join(File.dirname(__FILE__), 'tomcat') + +class Chef + class Resource + class TomcatManager < Chef::Resource + + def initialize(name, collection=nil, node=nil) + super(name, collection, node) + @resource_name = :tomcat_manager + @host = "localhost" + @port = "8080" + @action = :nothing + @allowed_actions.push(:install) + @allowed_actions.push(:start) + @allowed_actions.push(:stop) + @allowed_actions.push(:update) + @allowed_actions.push(:undeploy) + + end + + def port(arg=nil) + set_or_return( + :port, + arg, + :kind_of => [ String ] + ) + end + + def host(arg=nil) + set_or_return( + :host, + arg, + :kind_of => [ String ] + ) + end + + def admin(arg=nil) + set_or_return( + :admin, + arg, + :kind_of => [ String ] + ) + end + + def password(arg=nil) + set_or_return( + :password, + arg, + :kind_of => [ String ] + ) + end + + def base(arg=nil) + set_or_return( + :base, + arg, + :kind_of => [ String ] + ) + end + + def war(arg=nil) + set_or_return( + :war, + arg, + :kind_of => [ String ] + ) + end + + def path(arg=nil) + set_or_return( + :path, + arg, + :kind_of => [ String ] + ) + end + + def tag(arg=nil) + set_or_return( + :tag, + arg, + :kind_of => [ String ] + ) + end + + def service(arg=nil) + set_or_return( + :service, + arg, + :kind_of => [ Object ] + ) + end + + + + end + end + + class Provider + class TomcatManager < Chef::Provider + + def load_current_resource + #super + #@current_resource + end + + def action_install + ensure_tomcat_manager_running + Chef::Log.info "Running tomcat_manager[#{@new_resource.name}] install" + tomcat = new_tomcat + begin + result = tomcat.install + (!"200".eql?(result.code) || result.body.include?("FAIL"))?(Chef::Log.error "Ran tomcat_manager[#{@new_resource.name}] install failed: HTTP #{result.code} #{result.message}"):(Chef::Log.info "Ran tomcat_manager[#{@new_resource.name}] install successfully") + rescue StandardError => e + Chef::Log.error "Got Exception in manager action" + e + end + end + + def action_update + ensure_tomcat_manager_running + Chef::Log.info "Running tomcat_manager[#{@new_resource.name}] update" + tomcat = new_tomcat + begin + result = tomcat.update + (!"200".eql?(result.code) || result.body.include?("FAIL"))?(Chef::Log.error "Ran tomcat_manager[#{@new_resource.name}] update failed: HTTP #{result.code} #{result.message}"):(Chef::Log.info "Ran tomcat_manager[#{@new_resource.name}] update successfully") + rescue StandardError => e + Chef::Log.error "Got Exception in manager action" + e + end + end + + def action_start + ensure_tomcat_manager_running + Chef::Log.info "Running tomcat_manager[#{@new_resource.name}] start" + tomcat = new_tomcat + begin + result = tomcat.start + (!"200".eql?(result.code) || result.body.include?("FAIL"))?(Chef::Log.error "Ran tomcat_manager[#{@new_resource.name}] start failed: HTTP #{result.code} #{result.message}"):(Chef::Log.info "Ran tomcat_manager[#{@new_resource.name}] start successfully") + rescue StandardError => e + Chef::Log.error "Got Exception in manager action" + e + end + end + + def action_stop + ensure_tomcat_manager_running + Chef::Log.info "Running tomcat_manager[#{@new_resource.name}] stop" + tomcat = new_tomcat + begin + result = tomcat.stop + (!"200".eql?(result.code) || result.body.include?("FAIL"))?(Chef::Log.error "Ran tomcat_manager[#{@new_resource.name}] stop failed: HTTP #{result.code} #{result.message}"):(Chef::Log.info "Ran tomcat_manager[#{@new_resource.name}] stop successfully") + rescue StandardError => e + Chef::Log.error "Got Exception in manager action" + e + end + end + + def action_undeploy + ensure_tomcat_manager_running + Chef::Log.info "Running tomcat_manager[#{@new_resource.name}] undeploy" + tomcat = new_tomcat + begin + result = tomcat.undeploy + (!"200".eql?(result.code) || result.body.include?("FAIL"))?(Chef::Log.error "Ran tomcat_manager[#{@new_resource.name}] undeploy failed: HTTP #{result.code} #{result.message}"):(Chef::Log.info "Ran tomcat_manager[#{@new_resource.name}] undeploy successfully") + rescue StandardError => e + Chef::Log.error "Got Exception in manager action" + e + end + end + + def new_tomcat(opts={}) + Tomcat.new :host => @new_resource.host, + :port => @new_resource.port, + :admin => @new_resource.admin, + :password => @new_resource.password, + :path => @new_resource.path, + :base => @new_resource.base, + :war => @new_resource.war, + :name => @new_resource.name, + :tag => @new_resource.tag + + end + + def ensure_tomcat_manager_running + require 'snmp' + + snmp = Hash.new + # "jvmMemPoolUsed.5" is PermGen used + snmp_names = ["jvmMemPoolUsed.5","jvmMemPoolMaxSize.5"] + begin + SNMP::Manager.open(:Host => "localhost", :Port => "1161", :MibModules => ['JVM-MANAGEMENT-MIB','SNMPv2-SMI']) do |m| + response = m.get(snmp_names) + i=0 + response.each_varbind do |vb| + snmp[snmp_names[i]]=vb + i+=1 + end + end + rescue + Chef::Log.info "SNMP java not responding, restarting [#{@new_resource.name}] " + #restart passed in service, which should be the tomcat service + @new_resource.service.run_action(:restart) + poll_manger_until_running + end + perm_gen_max = (snmp["jvmMemPoolMaxSize.5"])?(snmp["jvmMemPoolMaxSize.5"].value.to_f):27262976 + perm_gen_used = (snmp["jvmMemPoolUsed.5"])?(snmp["jvmMemPoolUsed.5"].value.to_f):0 + #restart passed in service, which should be the tomcat service + min_perm_gen = 25*1024*1024 + if ((perm_gen_max - perm_gen_used) < min_perm_gen) #@node[:tomcat][:permgen_min_free_in_mb]) + Chef::Log.info "SNMP reported: PermGen Max:#{perm_gen_max/1024/1024} PermGen Used:#{perm_gen_used/1024/1024} , diff: #{(perm_gen_max/1024/1024 - perm_gen_used/1024/1024)} is lower than #{min_perm_gen/1024/1024} " + @new_resource.service.run_action(:restart) + poll_manger_until_running + end + end + def poll_manger_until_running + times = 40 + tomcat = new_tomcat + while(times > 0) + Chef::Log.info "waiting for tomcat_manager[#{@new_resource.name}] restart" + begin + tomcat.status + times = 0 + rescue Timeout::Error + Chef::Log.info "Timeout, waiting for another #{2*times} seconds" + rescue + Chef::Log.info "Manager not responding, waiting for another #{2*times} seconds" + ensure + sleep 2 + times-=1 + end + end + end + end + end +end + +Chef::Platform.platforms[:default].merge! :tomcat_manager => Chef::Provider::TomcatManager diff --git a/tomcat6/metadata.json b/tomcat6/metadata.json new file mode 100644 index 0000000..176e0dc --- /dev/null +++ b/tomcat6/metadata.json @@ -0,0 +1,60 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs and configures all aspects of tomcat6 using custom local installation", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "tomcat6": "Main Tomcat 6 configuration", + "tomcat6": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "centos": [ + + ], + "debian": [ + + ], + "redhat": [ + + ] + }, + "version": "0.1.0", + "name": "tomcat6", + "conflicting": { + + }, + "attributes": { + "tomcat6\/with_native": { + "default": "false", + "type": "string", + "multiple_values": false, + "description": "works for centos, install tomcat-native libraries", + "display_name": "Tomcat native support", + "recipes": [ + + ], + "required": false + } + }, + "providing": { + "tomcat6": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "= DESCRIPTION:\n\nInstalls Tomcat6\n\n= REQUIREMENTS:\n\n== Platform and Application Environment:\n\nTested on Centos 5.2 8.10. May work on other platforms, esp Redhat.\nNeeds Java at least Java 5\n\n== Cookbooks:\n\nOpscode cookbooks, http:\/\/github.com\/opscode\/cookbooks\/tree\/master:\n\n* java\n\n= ATTRIBUTES: \n\n= USAGE:\n\n\n= LICENSE and AUTHOR:\n \nAuthor:: Edmund Haselwanter ()\nCopyright:: 2009, Edmund Haselwanter\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http:\/\/www.apache.org\/licenses\/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/tomcat6/metadata.rb b/tomcat6/metadata.rb new file mode 100644 index 0000000..bc6dc51 --- /dev/null +++ b/tomcat6/metadata.rb @@ -0,0 +1,17 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs and configures all aspects of tomcat6 using custom local installation" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.1" +recipe "tomcat6", "Main Tomcat 6 configuration" + +%w{redhat centos debian ubuntu}.each do |os| + supports os +end + +attribute "tomcat6/with_native", + :display_name => "Tomcat native support", + :description => "works for centos, install tomcat-native libraries", + :type => "string", + :default => "false" diff --git a/tomcat6/recipes/default.rb b/tomcat6/recipes/default.rb new file mode 100644 index 0000000..7f577f6 --- /dev/null +++ b/tomcat6/recipes/default.rb @@ -0,0 +1,197 @@ +# +# Cookbook Name:: tomcat6 +# Recipe:: default +# +# Copyright 2009, Edmund Haselwanter +# +# 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 "java" + +service "tomcat6" do + action :nothing +end + +group node[:tomcat6][:user] do +end + +user node[:tomcat6][:user] do + comment "Apache Tomcat" + gid node[:tomcat6][:user] + home node[:tomcat6][:home] + shell "/bin/sh" +end + +[node[:tomcat6][:temp],node[:tomcat6][:logs],node[:tomcat6][:webapps],node[:tomcat6][:home],node[:tomcat6][:conf]].each do |dir| + directory dir do + action :create + mode 0755 + owner "#{node[:tomcat6][:user]}" + group "#{node[:tomcat6][:user]}" + end +end + +[:temp,:logs,:webapps,:conf].each do |dir| + link File.join(node[:tomcat6][:home],dir.to_s) do + to node[:tomcat6][dir] # use values from attributes + end +end + +usr_share_dir = "/usr/share" + +bash "update_manager" do + user node[:tomcat6][:user] + action :nothing + cwd node[:tomcat6][:webapps] + code <<-EOH + rm -rf ./manager + cp -r #{usr_share_dir}/apache-tomcat-#{node[:tomcat6][:version]}/webapps/manager . + EOH +end + +bash "install_tomcat6" do + tomcat_version_name = "apache-tomcat-#{node[:tomcat6][:version]}" + tomcat_version_name_tgz = "#{tomcat_version_name}.tar.gz" + user "root" + cwd usr_share_dir + not_if do File.exists?(File.join(usr_share_dir,tomcat_version_name)) end + code <<-EOH + wget http://archive.apache.org/dist/tomcat/tomcat-6/v#{node[:tomcat6][:version]}/bin/#{tomcat_version_name_tgz} + tar -zxf #{tomcat_version_name_tgz} + rm #{tomcat_version_name_tgz} + chown -R #{node[:tomcat6][:user]}:#{node[:tomcat6][:user]} #{tomcat_version_name} + EOH +end + +# just to have it here, may be overriden through own configuration +bash "install_tomcat6_etc" do + user node[:tomcat6][:user] + not_if do File.exists?(File.join(node[:tomcat6][:conf],"tomcat6.conf")) end + cwd node[:tomcat6][:conf] + code <<-EOH + cp -r #{usr_share_dir}/apache-tomcat-#{node[:tomcat6][:version]}/conf/* . + EOH +end + +link File.join(node[:tomcat6][:home],"lib") do + to File.join(usr_share_dir,"apache-tomcat-#{node[:tomcat6][:version]}","lib") + notifies :run, resources(:bash => "update_manager"), :immediately + notifies :restart, resources(:service => "tomcat6"), :delayed +end + +link File.join(node[:tomcat6][:home],"bin") do + to File.join(usr_share_dir,"apache-tomcat-#{node[:tomcat6][:version]}","bin") + notifies :restart, resources(:service => "tomcat6"), :delayed +end + +case node[:platform] +when "centos" + + # remote_file "/etc/yum.repos.d/rightscale.repo" do + # source "rightscale.repo" + # mode 0755 + # owner "root" + # group "root" + # end + # + # package "tomcat6" + # + # link "/usr/share/java/tomcat6/\[ecj\].jar" do + # to "/usr/share/java/eclipse-ecj.jar" + # end + # + + # package "tomcat6-admin-webapps" + + r = remote_file "/tmp/JVM-MANAGEMENT-MIB.mib" do + source "JVM-MANAGEMENT-MIB.mib" + mode 0755 + owner "root" + group "root" + end + + r.run_action(:create) + + p = package "libsmi" do + action :install + end + + p.run_action(:install) + + g = gem_package "snmp" do + action :install + end + + g.run_action(:install) + + Gem.clear_paths + + require "snmp" + + SNMP::MIB.import_module("/tmp/JVM-MANAGEMENT-MIB.mib") + + package "tomcat-native" do + action :install + only_if do @node[:tomcat6][:with_native] end + end + + +else + +end + +remote_file "/etc/init.d/tomcat6" do + source "tomcat6" + mode 0755 + owner "root" + group "root" +end + +remote_file "/usr/bin/dtomcat6" do + source "dtomcat6" + mode 0755 + owner "root" + group "root" +end + +remote_file File.join(node[:tomcat6][:dir],"logging.properties") do + source "logging.properties" + mode 0644 + owner "root" + group "root" +end + +service "tomcat6" do + case node[:platform] + when "centos" + service_name "tomcat6" + else + name "tomcat" + end + supports :start=> true, :stop => true, :restart => true, :status => true + action :enable +end + +template "#{node[:tomcat6][:dir]}/tomcat6.conf" do + source "tomcat6.conf.erb" + group "#{node[:tomcat6][:user]}" + owner "#{node[:tomcat6][:user]}" + mode 0644 + notifies :stop, resources(:service => "god"), :immediately + notifies :restart, resources(:service => "tomcat6"), :immediately +end + +service "tomcat6" do + action :start +end diff --git a/tomcat6/templates/default/manager.xml.erb b/tomcat6/templates/default/manager.xml.erb new file mode 100644 index 0000000..34551e9 --- /dev/null +++ b/tomcat6/templates/default/manager.xml.erb @@ -0,0 +1,21 @@ + + + + \ No newline at end of file diff --git a/tomcat6/templates/default/tomcat-users.xml.erb b/tomcat6/templates/default/tomcat-users.xml.erb new file mode 100644 index 0000000..d81c583 --- /dev/null +++ b/tomcat6/templates/default/tomcat-users.xml.erb @@ -0,0 +1,5 @@ + + + + + diff --git a/tomcat6/templates/default/tomcat6.conf.erb b/tomcat6/templates/default/tomcat6.conf.erb new file mode 100644 index 0000000..e1746a2 --- /dev/null +++ b/tomcat6/templates/default/tomcat6.conf.erb @@ -0,0 +1,55 @@ +# System-wide configuration file for tomcat6 services +# This will be sourced by tomcat6 and any secondary service +# Values will be overridden by service-specific configuration +# files in /etc/sysconfig +# +# Use this one to change default values for all services +# Change the service specific ones to affect only one service +# (see, for instance, /etc/sysconfig/tomcat6) +# + +# Where your java installation lives +JAVA_HOME="<%= @node[:tomcat6][:java_home]%>" + +# Where your tomcat installation lives +CATALINA_BASE="<%= @node[:tomcat6][:home]%>" +CATALINA_HOME="<%= @node[:tomcat6][:home]%>" +JASPER_HOME="<%= @node[:tomcat6][:home]%>" +CATALINA_TMPDIR="<%= @node[:tomcat6][:temp]%>" + +# You can pass some parameters to java here if you wish to +#JAVA_OPTS="-Xminf0.1 -Xmaxf0.3" +JAVA_OPTS="-Dcom.sun.management.snmp.interface=0.0.0.0 -Dcom.sun.management.snmp.acl=false -Dcom.sun.management.snmp.port=1161 <%= @node[:tomcat6][:java_opts]%> " +# Use JAVA_OPTS to set java.library.path for libtcnative.so +#JAVA_OPTS="-Djava.library.path=/usr/lib" +#JAVA_OPTS="-agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n" +# What user should run tomcat +TOMCAT_USER="<%= @node[:tomcat6][:user]%>" + +# You can change your tomcat locale here +#LANG="en_US" + +# set the timezone + +TZ='Universal' +export TZ +# Run tomcat under the Java Security Manager +SECURITY_MANAGER="false" + +# Time to wait in seconds, before killing process +SHUTDOWN_WAIT="3" + +# Whether to annoy the user with "attempting to shut down" messages or not +SHUTDOWN_VERBOSE="false" + +# Set the TOMCAT_PID location +CATALINA_PID="/var/run/tomcat6.pid" + +# Connector port is 8080 for this tomcat6 instance +#CONNECTOR_PORT="8080" + +# If you wish to further customize your tomcat environment, +# put your own definitions here +# (i.e. LD_LIBRARY_PATH for some jdbc drivers) + +LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/share/tomcat6/jai-1_1_3/lib/ diff --git a/ubuntu/metadata.json b/ubuntu/metadata.json new file mode 100644 index 0000000..27fe29e --- /dev/null +++ b/ubuntu/metadata.json @@ -0,0 +1,42 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Sets up sources for ubuntu", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "ubuntu": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ] + }, + "version": "0.7.0", + "name": "ubuntu", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "ubuntu": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + "apt": [ + + ] + } +} \ No newline at end of file diff --git a/ubuntu/metadata.rb b/ubuntu/metadata.rb new file mode 100644 index 0000000..02694a7 --- /dev/null +++ b/ubuntu/metadata.rb @@ -0,0 +1,7 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Sets up sources for ubuntu" +version "0.8" +depends "apt" +supports "ubuntu" diff --git a/ubuntu/recipes/default.rb b/ubuntu/recipes/default.rb new file mode 100644 index 0000000..9990d51 --- /dev/null +++ b/ubuntu/recipes/default.rb @@ -0,0 +1,27 @@ +# +# Cookbook Name:: ubuntu +# Recipe:: default +# +# Copyright 2008-2009, Opscode, 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 "apt" + +template "/etc/apt/sources.list" do + mode 0644 + variables :code_name => node[:lsb][:codename] + notifies :run, resources(:execute => "apt-get update"), :immediately + source "sources.list.erb" +end diff --git a/ubuntu/templates/default/sources.list.erb b/ubuntu/templates/default/sources.list.erb new file mode 100644 index 0000000..e788d2e --- /dev/null +++ b/ubuntu/templates/default/sources.list.erb @@ -0,0 +1,15 @@ +# +# Ubuntu <%= @code_name %> - Generated by Chef +# + +deb http://us.archive.ubuntu.com/ubuntu <%= @code_name %> main restricted universe multiverse +deb-src http://us.archive.ubuntu.com/ubuntu <%= @code_name %> main restricted universe multiverse + +deb http://us.archive.ubuntu.com/ubuntu <%= @code_name %>-updates main restricted universe multiverse +deb-src http://us.archive.ubuntu.com/ubuntu <%= @code_name %>-updates main restricted universe multiverse + +# +# Security updates +# +deb http://security.ubuntu.com/ubuntu <%= @code_name %>-security main restricted universe multiverse +deb-src http://security.ubuntu.com/ubuntu <%= @code_name %>-security main restricted universe multiverse diff --git a/unicorn/README.rdoc b/unicorn/README.rdoc new file mode 100644 index 0000000..54c550b --- /dev/null +++ b/unicorn/README.rdoc @@ -0,0 +1,17 @@ += LICENSE AND AUTHOR: + +Author:: Adam Jacob + +Copyright 2009-2010, Opscode, 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/unicorn/definitions/unicorn_config.rb b/unicorn/definitions/unicorn_config.rb new file mode 100644 index 0000000..86c5fb0 --- /dev/null +++ b/unicorn/definitions/unicorn_config.rb @@ -0,0 +1,49 @@ +# +# Author:: Adam Jacob +# Cookbook Name:: unicorn +# Definition:: unicorn_config +# +# Copyright 2009, Opscode, 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. +# + +define :unicorn_config, :listen => nil, :worker_timeout => 60, :preload_app => false, :worker_processes => 4, :before_fork => nil, :after_fork => nil, :pid => nil, :stderr_path => nil, :stdout_path => nil, :notifies => nil, :owner => nil, :group => nil, :mode => nil do + config_dir = File.dirname(params[:name]) + + directory config_dir do + recursive true + action :create + end + + tvars = params.clone + params[:listen].each do |port, options| + oarray = Array.new + options.each do |k, v| + oarray << ":#{k} => #{v}" + end + tvars[:listen][port] = oarray.join(", ") + end + + template params[:name] do + source "unicorn.rb.erb" + cookbook "unicorn" + mode "0644" + owner params[:owner] if params[:owner] + group params[:group] if params[:group] + mode params[:mode] if params[:mode] + variables params + notifies *params[:notifies] if params[:notifies] + end + +end diff --git a/unicorn/metadata.rb b/unicorn/metadata.rb new file mode 100644 index 0000000..aa872d0 --- /dev/null +++ b/unicorn/metadata.rb @@ -0,0 +1,8 @@ +maintainer "Opscode, Inc" +maintainer_email "ops@opscode.com" +license "Apache 2.0" +description "Installs/Configures unicorn" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.1" +depends "ruby" +depends "rubygems" diff --git a/unicorn/recipes/default.rb b/unicorn/recipes/default.rb new file mode 100644 index 0000000..dd71946 --- /dev/null +++ b/unicorn/recipes/default.rb @@ -0,0 +1,24 @@ +# +# Author:: Adam Jacob +# Cookbook Name:: unicorn +# Recipe:: default +# +# Copyright 2009, Opscode, 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 "ruby" +include_recipe "rubygems" + +gem_package "unicorn" diff --git a/unicorn/templates/default/unicorn.rb.erb b/unicorn/templates/default/unicorn.rb.erb new file mode 100644 index 0000000..455bf1d --- /dev/null +++ b/unicorn/templates/default/unicorn.rb.erb @@ -0,0 +1,48 @@ +## +# Unicorn config at <%= @name %> +# Managed by Chef - Local Changes will be Nuked from Orbit (just to be sure) +## + +# What ports/sockets to listen on, and what options for them. +<%- @listen.each do |port, options| %> +listen <%= port %>, <%= options %> +<%- end %> + +# What the timeout for killing busy workers is, in seconds +timeout <%= @worker_timeout %> + +# Whether the app should be pre-loaded +preload_app <%= @preload_app %> + +# How many worker processes +worker_processes <%= @worker_processes %> + +<%- if @before_fork %> +# What to do before we fork a worker +before_fork do |server, worker| + <%= @before_fork %> +end + +<%- end %> +<%- if @after_fork %> +# What to do after we fork a worker +before_fork do |server, worker| + <%= @before_fork %> +end + +<%- end %> +<%- if @pid %> +# Where to drop a pidfile +pid '<%= @pid %>' + +<%- end %> +<%- if @stderr_path %> +# Where stderr gets logged +stderr_path '<%= @stderr_path %>' + +<%- end %> +<%- if @stdout_path %> +# Where stdout gets logged +stdout_path '<%= @stdout_path %>' + +<%- end %> diff --git a/users/attributes/default.rb b/users/attributes/default.rb new file mode 100755 index 0000000..3905695 --- /dev/null +++ b/users/attributes/default.rb @@ -0,0 +1,4 @@ +users Mash.new unless attribute?("users") + +# passwords must be in shadow password format with a salt. To generate: openssl passwd -1 +# users[:jose] = {:password => "shadowpass", :comment => "José Amador", :ssh_key => "..." } diff --git a/users/definitions/add_keys.rb b/users/definitions/add_keys.rb new file mode 100755 index 0000000..431aa49 --- /dev/null +++ b/users/definitions/add_keys.rb @@ -0,0 +1,38 @@ +define :add_keys, :conf => {} do + config = params[:conf] + name = params[:name] + keys = Mash.new + keys[name] = node[:ssh_keys][name] + + if config[:ssh_key_groups] + config[:ssh_key_groups].each do |group| + node[:users].find_all { |u| u.last[:groups].include?(group) }.each do |user| + keys[user.first] = node[:ssh_keys][user.first] + end + end + end + + if config[:extra_ssh_keys] + config[:extra_ssh_keys].each do |username| + keys[username] = node[:ssh_keys][username] + end + end + + directory "/home/#{name}/.ssh" do + action :create + owner name + group config[:groups] ? config[:groups].first.to_s : name + mode 0755 + not_if { File.exists? "/home/#{name}/.ssh" } + end + + template "/home/#{name}/.ssh/authorized_keys" do + source "authorized_keys.erb" + action :create + owner name + group config[:groups] ? config[:groups].first.to_s : name + variables(:keys => keys) + mode 0600 + not_if { defined?(node[:users][name][:preserve_keys]) ? node[:users][name][:preserve_keys] : false } + end +end \ No newline at end of file diff --git a/users/libraries/roles.rb b/users/libraries/roles.rb new file mode 100755 index 0000000..8b98106 --- /dev/null +++ b/users/libraries/roles.rb @@ -0,0 +1,17 @@ +def user_is_in_role?(username) + return false if !@node[:role] + Chef::Log.info role[:groups].inspect + role[:groups].include? get_user(username)[:group] +end + +def role + @node[:roles][@node[:role]] +end + +# method name 'user' conflicts with chef, so we use 'get_user' +def get_user(username) + Chef::Log.info username + user = @node[:users][username] + Chef::Log.info user.inspect + user +end diff --git a/users/metadata.json b/users/metadata.json new file mode 100755 index 0000000..1990bd8 --- /dev/null +++ b/users/metadata.json @@ -0,0 +1,38 @@ +{ + "replacing": { + + }, + "long_description": "", + "attributes": { + + }, + "maintainer": "37signals", + "recommendations": { + + }, + "license": "Apache v2.0", + "recipes": { + "users": "" + }, + "maintainer_email": "sysadmins@37signals.com", + "suggestions": { + + }, + "dependencies": { + + }, + "conflicting": { + + }, + "platforms": { + + }, + "description": "Configures users and groups", + "version": "0.1.0", + "name": "users", + "providing": { + "users": [ + + ] + } +} \ No newline at end of file diff --git a/users/metadata.rb b/users/metadata.rb new file mode 100755 index 0000000..a671e4b --- /dev/null +++ b/users/metadata.rb @@ -0,0 +1,4 @@ +maintainer "37signals" +maintainer_email "sysadmins@37signals.com" +description "Configures users and groups" +version "0.1" diff --git a/users/recipes/default.rb b/users/recipes/default.rb new file mode 100755 index 0000000..4499e16 --- /dev/null +++ b/users/recipes/default.rb @@ -0,0 +1,17 @@ +include_recipe "ruby-shadow" + +if node[:users] + node[:users].keys.each do |username| + config = node[:users][username] + user username do + comment config[:comment] + home "/home/#{username}" + shell "/bin/bash" + password config[:password] + supports :manage_home => true + action [:create, :manage] + end + + add_keys username + end +end diff --git a/users/templates/default/authorized_keys.erb b/users/templates/default/authorized_keys.erb new file mode 100755 index 0000000..71491f4 --- /dev/null +++ b/users/templates/default/authorized_keys.erb @@ -0,0 +1,4 @@ +<% @keys.each do |name, key| %> +# <%= name %> +<%= key %> +<% end %> \ No newline at end of file diff --git a/varnish/attributes/varnish.rb b/varnish/attributes/varnish.rb new file mode 100644 index 0000000..1bb9cbd --- /dev/null +++ b/varnish/attributes/varnish.rb @@ -0,0 +1,5 @@ +case platform +when "debian","ubuntu" + set[:varnish][:dir] = "/etc/varnish" + set[:varnish][:default] = "/etc/default/varnish" +end diff --git a/varnish/metadata.json b/varnish/metadata.json new file mode 100644 index 0000000..9755e23 --- /dev/null +++ b/varnish/metadata.json @@ -0,0 +1,43 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Instsalls and configures varnish", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "varnish": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "debian": [ + + ] + }, + "version": "0.7.0", + "name": "varnish", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "varnish": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/varnish/metadata.rb b/varnish/metadata.rb new file mode 100644 index 0000000..d7b106f --- /dev/null +++ b/varnish/metadata.rb @@ -0,0 +1,9 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Instsalls and configures varnish" +version "0.7" + +%w{ubuntu debian}.each do |os| + supports os +end diff --git a/varnish/recipes/default.rb b/varnish/recipes/default.rb new file mode 100644 index 0000000..8703706 --- /dev/null +++ b/varnish/recipes/default.rb @@ -0,0 +1,44 @@ +# Cookbook Name:: varnish +# Recipe:: default +# Author:: Joe Williams +# +# Copyright 2008-2009, Joe Williams +# +# 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 "varnish" + +template "#{node[:varnish][:dir]}default.vcl" do + source "default.vcl.erb" + owner "root" + group "root" + mode 0644 +end + +template "#{node[:varnish][:default]}" do + source "ubuntu-default.erb" + owner "root" + group "root" + mode 0644 +end + +service "varnish" do + supports :restart => true, :reload => true + action [ :enable, :start ] +end + +service "varnishlog" do + supports :restart => true, :reload => true + action [ :enable, :start ] +end diff --git a/varnish/templates/default/default.vcl.erb b/varnish/templates/default/default.vcl.erb new file mode 100644 index 0000000..81760e0 --- /dev/null +++ b/varnish/templates/default/default.vcl.erb @@ -0,0 +1,11 @@ +backend default { + .host = "localhost"; + .port = "8080"; +} + +sub vcl_fetch { + # force minimum ttl of 120 seconds + if (obj.ttl < 120s) { + set obj.ttl = 120s; + } +} diff --git a/varnish/templates/default/ubuntu-default.erb b/varnish/templates/default/ubuntu-default.erb new file mode 100644 index 0000000..88d35f2 --- /dev/null +++ b/varnish/templates/default/ubuntu-default.erb @@ -0,0 +1,92 @@ +# Configuration file for varnish +# +# /etc/init.d/varnish expects the variable $DAEMON_OPTS to be set from this +# shell script fragment. +# + +# Maximum number of open files (for ulimit -n) +NFILES=131072 + +# Default varnish instance name is the local nodename. Can be overridden with +# the -n switch, to have more instances on a single server. +INSTANCE=$(uname -n) + +# This file contains 4 alternatives, please use only one. + +## Alternative 1, Minimal configuration, no VCL +# +# Listen on port 6081, administration on localhost:6082, and forward to +# content server on localhost:8080. Use a fixed-size cache file. +# +DAEMON_OPTS="-a :6081 \ + -T localhost:6082 \ + -b localhost:8080 \ + -u varnish -g varnish \ + -s file,/var/lib/varnish/$INSTANCE/varnish_storage.bin,1G" + + +## Alternative 2, Configuration with VCL +# +# Listen on port 6081, administration on localhost:6082, and forward to +# one content server selected by the vcl file, based on the request. Use a +# fixed-size cache file. +# +# DAEMON_OPTS="-a :6081 \ +# -T localhost:6082 \ +# -f /etc/varnish/default.vcl \ +# -s file,/var/lib/varnish/$INSTANCE/varnish_storage.bin,1G" + + +## Alternative 3, Advanced configuration +# +# See varnishd(1) for more information. +# +# # Main configuration file. You probably want to change it :) +# VARNISH_VCL_CONF=/etc/varnish/default.vcl +# +# # Default address and port to bind to +# # Blank address means all IPv4 and IPv6 interfaces, otherwise specify +# # a host name, an IPv4 dotted quad, or an IPv6 address in brackets. +# VARNISH_LISTEN_ADDRESS= +# VARNISH_LISTEN_PORT=6081 +# +# # Telnet admin interface listen address and port +# VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1 +# VARNISH_ADMIN_LISTEN_PORT=6082 +# +# # The minimum number of worker threads to start +# VARNISH_MIN_THREADS=1 +# +# # The Maximum number of worker threads to start +# VARNISH_MAX_THREADS=1000 +# +# # Idle timeout for worker threads +# VARNISH_THREAD_TIMEOUT=120 +# +# # Cache file location +# VARNISH_STORAGE_FILE=/var/lib/varnish/$INSTANCE/varnish_storage.bin +# +# # Cache file size: in bytes, optionally using k / M / G / T suffix, +# # or in percentage of available disk space using the % suffix. +# VARNISH_STORAGE_SIZE=1G +# +# # Backend storage specification +# VARNISH_STORAGE="file,${VARNISH_STORAGE_FILE},${VARNISH_STORAGE_SIZE}" +# +# # Default TTL used when the backend does not specify one +# VARNISH_TTL=120 +# +# # DAEMON_OPTS is used by the init script. If you add or remove options, make +# # sure you update this section, too. +# DAEMON_OPTS="-a ${VARNISH_LISTEN_ADDRESS}:${VARNISH_LISTEN_PORT} \ +# -f ${VARNISH_VCL_CONF} \ +# -T ${VARNISH_ADMIN_LISTEN_ADDRESS}:${VARNISH_ADMIN_LISTEN_PORT} \ +# -t ${VARNISH_TTL} \ +# -w ${VARNISH_MIN_THREADS},${VARNISH_MAX_THREADS},${VARNISH_THREAD_TIMEOUT} \ +# -s ${VARNISH_STORAGE}" +# + + +## Alternative 4, Do It Yourself +# +# DAEMON_OPTS="" \ No newline at end of file diff --git a/xen/create_slice/example b/xen/create_slice/example new file mode 100755 index 0000000..ca0dd1e --- /dev/null +++ b/xen/create_slice/example @@ -0,0 +1,24 @@ +Copy the stock image to a new volume on a dom0. +Mount the new volume, and drop in working /etc/network/interfaces, /etc/hostname, and /root/.ssh/authorized_keys. +Generate a Xen config file in /etc/xen/auto. +xm create ... +cool. the copy process is a dd? +Actually, restore. +might as well get a recipe going for it +So, it's really: +/usr/sbin/lvcreate -L 16G -n slice_root VolGroupXen +/usr/sbin/lvcreate -L 2G -n slice_swap +^ VolGroupXen +where can i try this? +Any of the xens. +We need to copy the stock image around, it's currently in my NFS homedir. +/sbin/mkfs.ext3 /dev/mapper/VolGroupXen-slice_root +/sbin/mkswap /dev/mapper/VolGroupXen-slice_swap +mkdir /tmp/mnt.slice_root +mount -t ext3 /dev/mapper/VolGroupXen-slice_root /tmp/mnt.slice_root +cd /tmp/mnt.slice_root +restore -rf /home/mark/intrepid.dump +cd / +umount /tmp/mnt.slice_root +cool +"slice" is replaced with the name of the slice everywhere, obviously. diff --git a/xen/create_slice/libraries/default.rb b/xen/create_slice/libraries/default.rb new file mode 100755 index 0000000..d808456 --- /dev/null +++ b/xen/create_slice/libraries/default.rb @@ -0,0 +1,3 @@ +def generate_mac_address + "00:16:3E:%X%X:%X%X:%X%X" % Array.new(6) { rand(16) } +end \ No newline at end of file diff --git a/xen/create_slice/templates/default/slice_config.xen.erb b/xen/create_slice/templates/default/slice_config.xen.erb new file mode 100755 index 0000000..07165a0 --- /dev/null +++ b/xen/create_slice/templates/default/slice_config.xen.erb @@ -0,0 +1,10 @@ +kernel = "/boot/vmlinuz-2.6.18-92.1.6.el5xen" +ramdisk = "/boot/initrd-2.6.18-92.1.6.el5xen.img" +extra = "xencons=tty maxmem=<%= @maxmem %>M" +name = "<%= @name %>" +disk = [ 'phy:mapper/VolGroupXen-<%= @name %>_root,xvda,w', 'phy:mapper/VolGroupXen-<%= @name %>_swap,xvdb,w' ] +vif = [ 'mac=<%= @mac_address %>, bridge=br0' ] +bootloader="/usr/bin/pygrub" +vcpus=<%= @vcpus %> +memory="<%= @memory %>" +maxmem="<%= @maxmem %>" diff --git a/xen/metadata.json b/xen/metadata.json new file mode 100755 index 0000000..29afbfa --- /dev/null +++ b/xen/metadata.json @@ -0,0 +1,36 @@ +{ + "replacing": { + + }, + "long_description": "", + "attributes": { + + }, + "maintainer": "37signals", + "recommendations": { + + }, + "license": "Apache v2.0", + "recipes": { + + }, + "maintainer_email": "sysadmins@37signals.com", + "suggestions": { + + }, + "dependencies": { + + }, + "conflicting": { + + }, + "platforms": { + + }, + "description": "Configures xen", + "version": "0.1.0", + "name": "xen", + "providing": { + + } +} \ No newline at end of file diff --git a/xen/metadata.rb b/xen/metadata.rb new file mode 100755 index 0000000..ae509af --- /dev/null +++ b/xen/metadata.rb @@ -0,0 +1,4 @@ +maintainer "37signals" +maintainer_email "sysadmins@37signals.com" +description "Configures xen" +version "0.1" diff --git a/xfs/README.rdoc b/xfs/README.rdoc new file mode 100644 index 0000000..4246de2 --- /dev/null +++ b/xfs/README.rdoc @@ -0,0 +1,24 @@ += DESCRIPTION: + +Installs packages for working with XFS filesystems. + += REQUIREMENTS: + +Ubuntu or Debian package names are assumed. + += LICENSE and AUTHOR: + +Author:: Joshua Timberman () +Copyright:: 2009, Opscode, 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/xfs/metadata.json b/xfs/metadata.json new file mode 100644 index 0000000..c0c6fec --- /dev/null +++ b/xfs/metadata.json @@ -0,0 +1,46 @@ +{ + "replacing": { + + }, + "dependencies": { + + }, + "groupings": { + + }, + "long_description": "= DESCRIPTION:\n\nInstalls packages for working with XFS filesystems.\n\n= REQUIREMENTS:\n\nUbuntu or Debian package names are assumed.\n\n= LICENSE and AUTHOR:\n\nAuthor:: Joshua Timberman ()\nCopyright:: 2009, Opscode, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n", + "description": "Installs packages for working with XFS", + "recommendations": { + + }, + "platforms": { + "ubuntu": [ + + ], + "debian": [ + + ] + }, + "version": "0.1.0", + "maintainer": "Opscode, Inc.", + "name": "xfs", + "recipes": { + "xfs": "" + }, + "suggestions": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "xfs": [ + + ] + }, + "license": "Apache 2.0" +} \ No newline at end of file diff --git a/xfs/metadata.rb b/xfs/metadata.rb new file mode 100644 index 0000000..3d8ff75 --- /dev/null +++ b/xfs/metadata.rb @@ -0,0 +1,10 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs packages for working with XFS" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) +version "0.1" + +%w{ debian ubuntu }.each do |os| + supports os +end diff --git a/xfs/recipes/default.rb b/xfs/recipes/default.rb new file mode 100644 index 0000000..f906bbf --- /dev/null +++ b/xfs/recipes/default.rb @@ -0,0 +1,22 @@ +# +# Cookbook Name:: xfs +# Recipe:: default +# +# Copyright 2009, Opscode, 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. +# + +%w{ xfsprogs xfsdump xfslibs-dev }.each do |pkg| + package pkg +end diff --git a/zsh/metadata.json b/zsh/metadata.json new file mode 100644 index 0000000..2900f88 --- /dev/null +++ b/zsh/metadata.json @@ -0,0 +1,43 @@ +{ + "maintainer": "Opscode, Inc.", + "description": "Installs zsh", + "recommendations": { + + }, + "maintainer_email": "cookbooks@opscode.com", + "recipes": { + "zsh": "" + }, + "suggestions": { + + }, + "platforms": { + "ubuntu": [ + + ], + "debian": [ + + ] + }, + "version": "0.7.0", + "name": "zsh", + "conflicting": { + + }, + "attributes": { + + }, + "providing": { + "zsh": [ + + ] + }, + "license": "Apache 2.0", + "long_description": "", + "replacing": { + + }, + "dependencies": { + + } +} \ No newline at end of file diff --git a/zsh/metadata.rb b/zsh/metadata.rb new file mode 100644 index 0000000..6d78f6f --- /dev/null +++ b/zsh/metadata.rb @@ -0,0 +1,9 @@ +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs zsh" +version "0.7" + +%w{ubuntu debian}.each do |os| + supports os +end diff --git a/zsh/recipes/default.rb b/zsh/recipes/default.rb new file mode 100644 index 0000000..3f07689 --- /dev/null +++ b/zsh/recipes/default.rb @@ -0,0 +1,29 @@ +# +# Cookbook Name:: zsh +# Recipe:: default +# +# Copyright 2008-2009, Opscode, 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 "zsh" do + action :install +end + +case node[:platform] +when "ubuntu" + package "zsh-doc" do + action :install + end +end