From 40d26f9da0d2ec379f9da35bd4e57043abd8abdb Mon Sep 17 00:00:00 2001 From: vagrant Date: Sat, 25 May 2013 05:22:41 +0000 Subject: [PATCH] Add Vagrantfile and Chef recipes for easy setup --- .gitignore | 3 +- Vagrantfile | 38 + chef/cookbooks/apt/.gitignore | 14 + chef/cookbooks/apt/.kitchen.yml | 38 + chef/cookbooks/apt/Berksfile | 8 + chef/cookbooks/apt/CHANGELOG.md | 91 + chef/cookbooks/apt/CONTRIBUTING | 29 + chef/cookbooks/apt/LICENSE | 201 +++ chef/cookbooks/apt/README.md | 240 +++ chef/cookbooks/apt/TESTING.md | 25 + chef/cookbooks/apt/attributes/default.rb | 4 + .../apt/files/default/apt-proxy-v2.conf | 50 + chef/cookbooks/apt/metadata.rb | 30 + chef/cookbooks/apt/providers/preference.rb | 61 + chef/cookbooks/apt/providers/repository.rb | 138 ++ chef/cookbooks/apt/recipes/cacher-client.rb | 59 + chef/cookbooks/apt/recipes/cacher-ng.rb | 40 + chef/cookbooks/apt/recipes/default.rb | 68 + chef/cookbooks/apt/resources/preference.rb | 30 + chef/cookbooks/apt/resources/repository.rb | 40 + .../apt/templates/debian-6.0/acng.conf.erb | 174 ++ .../apt/templates/default/01proxy.erb | 2 + .../apt/templates/default/acng.conf.erb | 276 +++ .../apt/templates/ubuntu-10.04/acng.conf.erb | 270 +++ .../apt/test/cookbooks/apt_test/README.md | 1 + .../default/tests/minitest/cacher-ng_test.rb | 28 + .../default/tests/minitest/default_test.rb | 28 + .../default/tests/minitest/lwrps_test.rb | 48 + .../default/tests/minitest/support/helpers.rb | 29 + .../apt/test/cookbooks/apt_test/metadata.rb | 6 + .../cookbooks/apt_test/recipes/cacher-ng.rb | 20 + .../cookbooks/apt_test/recipes/default.rb | 20 + .../test/cookbooks/apt_test/recipes/lwrps.rb | 66 + chef/cookbooks/mysql/.gitignore | 7 + chef/cookbooks/mysql/.kitchen.yml | 45 + chef/cookbooks/mysql/Berksfile | 11 + chef/cookbooks/mysql/CHANGELOG.md | 154 ++ chef/cookbooks/mysql/CONTRIBUTING | 29 + chef/cookbooks/mysql/LICENSE | 201 +++ chef/cookbooks/mysql/README.md | 250 +++ chef/cookbooks/mysql/TESTING.md | 25 + chef/cookbooks/mysql/attributes/client.rb | 52 + .../mysql/attributes/percona_repo.rb | 3 + chef/cookbooks/mysql/attributes/server.rb | 255 +++ chef/cookbooks/mysql/libraries/helpers.rb | 33 + chef/cookbooks/mysql/metadata.rb | 140 ++ chef/cookbooks/mysql/recipes/client.rb | 59 + chef/cookbooks/mysql/recipes/default.rb | 20 + chef/cookbooks/mysql/recipes/percona_repo.rb | 48 + chef/cookbooks/mysql/recipes/ruby.rb | 31 + chef/cookbooks/mysql/recipes/server.rb | 221 +++ chef/cookbooks/mysql/recipes/server_ec2.rb | 51 + .../mysql/templates/default/debian.cnf.erb | 12 + .../mysql/templates/default/grants.sql.erb | 34 + .../mysql/templates/default/my.cnf.erb | 317 ++++ .../templates/default/mysql-server.seed.erb | 10 + .../mysql/templates/default/port_mysql.erb | 3 + .../mysql/templates/windows/my.cnf.erb | 61 + .../test/cookbooks/mysql_test/.gitignore | 1 + .../mysql/test/cookbooks/mysql_test/README.md | 63 + .../mysql_test/attributes/default.rb | 27 + .../default/tests/minitest/server_test.rb | 36 + .../default/tests/minitest/support/helpers.rb | 11 + .../test/cookbooks/mysql_test/metadata.rb | 9 + .../cookbooks/mysql_test/recipes/client.rb | 20 + .../cookbooks/mysql_test/recipes/server.rb | 62 + .../test/features/query_database.feature | 26 + .../features/step_definitions/mysql_steps.rb | 47 + .../mysql/test/features/support/env.rb | 3 + .../test/features/support/mysql_helpers.rb | 51 + chef/cookbooks/rvm/.gitignore | 7 + chef/cookbooks/rvm/.kitchen.yml | 71 + chef/cookbooks/rvm/.travis.yml | 4 + chef/cookbooks/rvm/Berksfile | 10 + chef/cookbooks/rvm/CHANGELOG.md | 220 +++ chef/cookbooks/rvm/Gemfile | 14 + chef/cookbooks/rvm/README.md | 1535 +++++++++++++++++ chef/cookbooks/rvm/Rakefile | 25 + chef/cookbooks/rvm/attributes/.gitkeep | 0 chef/cookbooks/rvm/attributes/default.rb | 75 + chef/cookbooks/rvm/attributes/gem_package.rb | 23 + chef/cookbooks/rvm/attributes/vagrant.rb | 23 + .../libraries/chef_rvm_environment_helpers.rb | 55 + .../rvm/libraries/chef_rvm_gemset_helpers.rb | 67 + .../rvm/libraries/chef_rvm_recipe_helpers.rb | 225 +++ .../rvm/libraries/chef_rvm_ruby_helpers.rb | 95 + .../rvm/libraries/chef_rvm_set_helpers.rb | 16 + .../rvm/libraries/chef_rvm_shell_helpers.rb | 57 + .../rvm/libraries/chef_rvm_string_cache.rb | 104 ++ .../rvm/libraries/chef_rvm_string_helpers.rb | 61 + .../rvm/libraries/chef_rvm_version_helpers.rb | 45 + .../rvm/libraries/gem_package_monkeypatch.rb | 34 + .../libraries/rvm_chef_user_environment.rb | 55 + .../rvm/libraries/rvm_rubygems_package.rb | 190 ++ .../rvm/libraries/rvm_shell_chef_wrapper.rb | 99 ++ chef/cookbooks/rvm/metadata.rb | 34 + chef/cookbooks/rvm/providers/default_ruby.rb | 63 + chef/cookbooks/rvm/providers/environment.rb | 77 + chef/cookbooks/rvm/providers/gemset.rb | 118 ++ chef/cookbooks/rvm/providers/global_gem.rb | 97 ++ chef/cookbooks/rvm/providers/ruby.rb | 176 ++ chef/cookbooks/rvm/providers/shell.rb | 120 ++ chef/cookbooks/rvm/providers/wrapper.rb | 72 + chef/cookbooks/rvm/recipes/.gitkeep | 0 chef/cookbooks/rvm/recipes/default.rb | 40 + chef/cookbooks/rvm/recipes/gem_package.rb | 33 + chef/cookbooks/rvm/recipes/system.rb | 37 + chef/cookbooks/rvm/recipes/system_install.rb | 52 + chef/cookbooks/rvm/recipes/user.rb | 43 + chef/cookbooks/rvm/recipes/user_install.rb | 49 + chef/cookbooks/rvm/recipes/vagrant.rb | 37 + chef/cookbooks/rvm/resources/default_ruby.rb | 31 + chef/cookbooks/rvm/resources/environment.rb | 31 + chef/cookbooks/rvm/resources/gem.rb | 37 + chef/cookbooks/rvm/resources/gemset.rb | 32 + chef/cookbooks/rvm/resources/global_gem.rb | 34 + chef/cookbooks/rvm/resources/ruby.rb | 32 + chef/cookbooks/rvm/resources/shell.rb | 41 + chef/cookbooks/rvm/resources/wrapper.rb | 34 + .../cookbooks/rvm/templates/default/rvmrc.erb | 16 + .../default/vagrant-chef-client-wrapper.erb | 23 + .../default/vagrant-chef-solo-wrapper.erb | 23 + .../integration/data_bags/users/virgil1.json | 4 + .../integration/data_bags/users/virgil2.json | 4 + .../data_bags/users/wigglebottom.json | 3 + .../test/integration/rubies/bats/_common.bash | 16 + .../integration/rubies/bats/verify_1.9.3.bats | 9 + .../integration/rubies/bats/verify_jruby.bats | 12 + .../rubies/bats/verify_patch_support.bats | 19 + .../integration/rubies/bats/verify_ree.bats | 9 + .../bats/verify_rubygems_version_support.bats | 15 + .../rvm_versions/bats/version_pinning.bats | 13 + .../stock_system_and_user/bats/system.bats | 45 + .../test/unit/chef/rvm/recipe_helpers_spec.rb | 73 + readme.md | 10 + 135 files changed, 9326 insertions(+), 1 deletion(-) create mode 100644 Vagrantfile create mode 100644 chef/cookbooks/apt/.gitignore create mode 100644 chef/cookbooks/apt/.kitchen.yml create mode 100644 chef/cookbooks/apt/Berksfile create mode 100644 chef/cookbooks/apt/CHANGELOG.md create mode 100644 chef/cookbooks/apt/CONTRIBUTING create mode 100644 chef/cookbooks/apt/LICENSE create mode 100644 chef/cookbooks/apt/README.md create mode 100644 chef/cookbooks/apt/TESTING.md create mode 100644 chef/cookbooks/apt/attributes/default.rb create mode 100644 chef/cookbooks/apt/files/default/apt-proxy-v2.conf create mode 100644 chef/cookbooks/apt/metadata.rb create mode 100644 chef/cookbooks/apt/providers/preference.rb create mode 100644 chef/cookbooks/apt/providers/repository.rb create mode 100644 chef/cookbooks/apt/recipes/cacher-client.rb create mode 100644 chef/cookbooks/apt/recipes/cacher-ng.rb create mode 100644 chef/cookbooks/apt/recipes/default.rb create mode 100644 chef/cookbooks/apt/resources/preference.rb create mode 100644 chef/cookbooks/apt/resources/repository.rb create mode 100644 chef/cookbooks/apt/templates/debian-6.0/acng.conf.erb create mode 100644 chef/cookbooks/apt/templates/default/01proxy.erb create mode 100644 chef/cookbooks/apt/templates/default/acng.conf.erb create mode 100644 chef/cookbooks/apt/templates/ubuntu-10.04/acng.conf.erb create mode 100644 chef/cookbooks/apt/test/cookbooks/apt_test/README.md create mode 100644 chef/cookbooks/apt/test/cookbooks/apt_test/files/default/tests/minitest/cacher-ng_test.rb create mode 100644 chef/cookbooks/apt/test/cookbooks/apt_test/files/default/tests/minitest/default_test.rb create mode 100644 chef/cookbooks/apt/test/cookbooks/apt_test/files/default/tests/minitest/lwrps_test.rb create mode 100644 chef/cookbooks/apt/test/cookbooks/apt_test/files/default/tests/minitest/support/helpers.rb create mode 100644 chef/cookbooks/apt/test/cookbooks/apt_test/metadata.rb create mode 100644 chef/cookbooks/apt/test/cookbooks/apt_test/recipes/cacher-ng.rb create mode 100644 chef/cookbooks/apt/test/cookbooks/apt_test/recipes/default.rb create mode 100644 chef/cookbooks/apt/test/cookbooks/apt_test/recipes/lwrps.rb create mode 100644 chef/cookbooks/mysql/.gitignore create mode 100644 chef/cookbooks/mysql/.kitchen.yml create mode 100644 chef/cookbooks/mysql/Berksfile create mode 100644 chef/cookbooks/mysql/CHANGELOG.md create mode 100644 chef/cookbooks/mysql/CONTRIBUTING create mode 100644 chef/cookbooks/mysql/LICENSE create mode 100644 chef/cookbooks/mysql/README.md create mode 100644 chef/cookbooks/mysql/TESTING.md create mode 100644 chef/cookbooks/mysql/attributes/client.rb create mode 100644 chef/cookbooks/mysql/attributes/percona_repo.rb create mode 100644 chef/cookbooks/mysql/attributes/server.rb create mode 100644 chef/cookbooks/mysql/libraries/helpers.rb create mode 100644 chef/cookbooks/mysql/metadata.rb create mode 100644 chef/cookbooks/mysql/recipes/client.rb create mode 100644 chef/cookbooks/mysql/recipes/default.rb create mode 100644 chef/cookbooks/mysql/recipes/percona_repo.rb create mode 100644 chef/cookbooks/mysql/recipes/ruby.rb create mode 100644 chef/cookbooks/mysql/recipes/server.rb create mode 100644 chef/cookbooks/mysql/recipes/server_ec2.rb create mode 100644 chef/cookbooks/mysql/templates/default/debian.cnf.erb create mode 100644 chef/cookbooks/mysql/templates/default/grants.sql.erb create mode 100644 chef/cookbooks/mysql/templates/default/my.cnf.erb create mode 100644 chef/cookbooks/mysql/templates/default/mysql-server.seed.erb create mode 100644 chef/cookbooks/mysql/templates/default/port_mysql.erb create mode 100644 chef/cookbooks/mysql/templates/windows/my.cnf.erb create mode 100644 chef/cookbooks/mysql/test/cookbooks/mysql_test/.gitignore create mode 100644 chef/cookbooks/mysql/test/cookbooks/mysql_test/README.md create mode 100644 chef/cookbooks/mysql/test/cookbooks/mysql_test/attributes/default.rb create mode 100644 chef/cookbooks/mysql/test/cookbooks/mysql_test/files/default/tests/minitest/server_test.rb create mode 100644 chef/cookbooks/mysql/test/cookbooks/mysql_test/files/default/tests/minitest/support/helpers.rb create mode 100644 chef/cookbooks/mysql/test/cookbooks/mysql_test/metadata.rb create mode 100644 chef/cookbooks/mysql/test/cookbooks/mysql_test/recipes/client.rb create mode 100644 chef/cookbooks/mysql/test/cookbooks/mysql_test/recipes/server.rb create mode 100644 chef/cookbooks/mysql/test/features/query_database.feature create mode 100644 chef/cookbooks/mysql/test/features/step_definitions/mysql_steps.rb create mode 100644 chef/cookbooks/mysql/test/features/support/env.rb create mode 100644 chef/cookbooks/mysql/test/features/support/mysql_helpers.rb create mode 100644 chef/cookbooks/rvm/.gitignore create mode 100644 chef/cookbooks/rvm/.kitchen.yml create mode 100644 chef/cookbooks/rvm/.travis.yml create mode 100644 chef/cookbooks/rvm/Berksfile create mode 100644 chef/cookbooks/rvm/CHANGELOG.md create mode 100644 chef/cookbooks/rvm/Gemfile create mode 100644 chef/cookbooks/rvm/README.md create mode 100644 chef/cookbooks/rvm/Rakefile create mode 100644 chef/cookbooks/rvm/attributes/.gitkeep create mode 100644 chef/cookbooks/rvm/attributes/default.rb create mode 100644 chef/cookbooks/rvm/attributes/gem_package.rb create mode 100644 chef/cookbooks/rvm/attributes/vagrant.rb create mode 100644 chef/cookbooks/rvm/libraries/chef_rvm_environment_helpers.rb create mode 100644 chef/cookbooks/rvm/libraries/chef_rvm_gemset_helpers.rb create mode 100644 chef/cookbooks/rvm/libraries/chef_rvm_recipe_helpers.rb create mode 100644 chef/cookbooks/rvm/libraries/chef_rvm_ruby_helpers.rb create mode 100644 chef/cookbooks/rvm/libraries/chef_rvm_set_helpers.rb create mode 100644 chef/cookbooks/rvm/libraries/chef_rvm_shell_helpers.rb create mode 100644 chef/cookbooks/rvm/libraries/chef_rvm_string_cache.rb create mode 100644 chef/cookbooks/rvm/libraries/chef_rvm_string_helpers.rb create mode 100644 chef/cookbooks/rvm/libraries/chef_rvm_version_helpers.rb create mode 100644 chef/cookbooks/rvm/libraries/gem_package_monkeypatch.rb create mode 100644 chef/cookbooks/rvm/libraries/rvm_chef_user_environment.rb create mode 100644 chef/cookbooks/rvm/libraries/rvm_rubygems_package.rb create mode 100644 chef/cookbooks/rvm/libraries/rvm_shell_chef_wrapper.rb create mode 100644 chef/cookbooks/rvm/metadata.rb create mode 100644 chef/cookbooks/rvm/providers/default_ruby.rb create mode 100644 chef/cookbooks/rvm/providers/environment.rb create mode 100644 chef/cookbooks/rvm/providers/gemset.rb create mode 100644 chef/cookbooks/rvm/providers/global_gem.rb create mode 100644 chef/cookbooks/rvm/providers/ruby.rb create mode 100644 chef/cookbooks/rvm/providers/shell.rb create mode 100644 chef/cookbooks/rvm/providers/wrapper.rb create mode 100644 chef/cookbooks/rvm/recipes/.gitkeep create mode 100644 chef/cookbooks/rvm/recipes/default.rb create mode 100644 chef/cookbooks/rvm/recipes/gem_package.rb create mode 100644 chef/cookbooks/rvm/recipes/system.rb create mode 100644 chef/cookbooks/rvm/recipes/system_install.rb create mode 100644 chef/cookbooks/rvm/recipes/user.rb create mode 100644 chef/cookbooks/rvm/recipes/user_install.rb create mode 100644 chef/cookbooks/rvm/recipes/vagrant.rb create mode 100644 chef/cookbooks/rvm/resources/default_ruby.rb create mode 100644 chef/cookbooks/rvm/resources/environment.rb create mode 100644 chef/cookbooks/rvm/resources/gem.rb create mode 100644 chef/cookbooks/rvm/resources/gemset.rb create mode 100644 chef/cookbooks/rvm/resources/global_gem.rb create mode 100644 chef/cookbooks/rvm/resources/ruby.rb create mode 100644 chef/cookbooks/rvm/resources/shell.rb create mode 100644 chef/cookbooks/rvm/resources/wrapper.rb create mode 100644 chef/cookbooks/rvm/templates/default/rvmrc.erb create mode 100644 chef/cookbooks/rvm/templates/default/vagrant-chef-client-wrapper.erb create mode 100644 chef/cookbooks/rvm/templates/default/vagrant-chef-solo-wrapper.erb create mode 100644 chef/cookbooks/rvm/test/integration/data_bags/users/virgil1.json create mode 100644 chef/cookbooks/rvm/test/integration/data_bags/users/virgil2.json create mode 100644 chef/cookbooks/rvm/test/integration/data_bags/users/wigglebottom.json create mode 100644 chef/cookbooks/rvm/test/integration/rubies/bats/_common.bash create mode 100644 chef/cookbooks/rvm/test/integration/rubies/bats/verify_1.9.3.bats create mode 100644 chef/cookbooks/rvm/test/integration/rubies/bats/verify_jruby.bats create mode 100644 chef/cookbooks/rvm/test/integration/rubies/bats/verify_patch_support.bats create mode 100644 chef/cookbooks/rvm/test/integration/rubies/bats/verify_ree.bats create mode 100644 chef/cookbooks/rvm/test/integration/rubies/bats/verify_rubygems_version_support.bats create mode 100644 chef/cookbooks/rvm/test/integration/rvm_versions/bats/version_pinning.bats create mode 100644 chef/cookbooks/rvm/test/integration/stock_system_and_user/bats/system.bats create mode 100644 chef/cookbooks/rvm/test/unit/chef/rvm/recipe_helpers_spec.rb diff --git a/.gitignore b/.gitignore index 6201479..345b868 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ .sass-cache /tmp/ -/.env \ No newline at end of file +/.env +/.vagrant \ No newline at end of file diff --git a/Vagrantfile b/Vagrantfile new file mode 100644 index 0000000..fcd19a5 --- /dev/null +++ b/Vagrantfile @@ -0,0 +1,38 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +Vagrant.configure("2") do |config| + config.vm.box = "precise32" + config.vm.box_url = "http://files.vagrantup.com/precise32.box" + + config.ssh.forward_agent = true + + config.vm.network :forwarded_port, guest: 5000, host: 5000 + + config.vm.provision :chef_solo do |chef| + chef.cookbooks_path = ["chef/cookbooks"] + chef.add_recipe "apt" + chef.add_recipe "mysql" + chef.add_recipe "rvm::vagrant" + chef.add_recipe "rvm::system" + chef.json = { + :rvm => { + 'user_installs' => [ + { + 'user' => 'vagrant', + 'default_ruby' => 'ruby-1.9.2-p320', + 'rubies' => ['1.9.2'] + } + ], + :rubies => [ + "1.9.2" + ], + :default_ruby => "ruby-1.9.2-p320", + :user_default_ruby => "ruby-1.9.2-p320", + 'vagrant' => { + 'system_chef_solo' => '/usr/local/ruby/bin/chef-solo' + } + } + } + end +end diff --git a/chef/cookbooks/apt/.gitignore b/chef/cookbooks/apt/.gitignore new file mode 100644 index 0000000..dd1e425 --- /dev/null +++ b/chef/cookbooks/apt/.gitignore @@ -0,0 +1,14 @@ +.vagrant +Berksfile.lock +Gemfile.lock +*~ +*# +.#* +\#*# +.*.sw[a-z] +*.un~ +.bundle +.cache +.kitchen +bin +.kitchen.local.yml diff --git a/chef/cookbooks/apt/.kitchen.yml b/chef/cookbooks/apt/.kitchen.yml new file mode 100644 index 0000000..d881698 --- /dev/null +++ b/chef/cookbooks/apt/.kitchen.yml @@ -0,0 +1,38 @@ +--- +driver_plugin: vagrant +driver_config: + require_chef_omnibus: true + +platforms: +- name: ubuntu-12.04 + driver_config: + box: canonical-ubuntu-12.04 + box_url: https://opscode-vm.s3.amazonaws.com/vagrant/opscode_ubuntu-12.04_provisionerless.box + run_list: + - recipe[apt] + +- name: ubuntu-10.04 + driver_config: + box: opscode-ubuntu-10.04 + box_url: https://opscode-vm.s3.amazonaws.com/vagrant/opscode_ubuntu-10.04_provisionerless.box + run_list: + - recipe[apt] + +suites: +- name: default + run_list: + - recipe[minitest-handler] + - recipe[apt_test] + attributes: {} + +- name: cacher-ng + run_list: + - recipe[minitest-handler] + - recipe[apt_test::cacher-ng] + attributes: {} + +- name: lwrps + run_list: + - recipe[minitest-handler] + - recipe[apt_test::lwrps] + attributes: {} diff --git a/chef/cookbooks/apt/Berksfile b/chef/cookbooks/apt/Berksfile new file mode 100644 index 0000000..91b26e6 --- /dev/null +++ b/chef/cookbooks/apt/Berksfile @@ -0,0 +1,8 @@ +site :opscode + +metadata + +group :integration do + cookbook "minitest-handler" + cookbook "apt_test", :path => "./test/cookbooks/apt_test" +end diff --git a/chef/cookbooks/apt/CHANGELOG.md b/chef/cookbooks/apt/CHANGELOG.md new file mode 100644 index 0000000..7217ef7 --- /dev/null +++ b/chef/cookbooks/apt/CHANGELOG.md @@ -0,0 +1,91 @@ +## v1.10.0: + +### Improvement + +- [COOK-2885]: Improvements for apt cache server search + +### Bug + +- [COOK-2441]: Apt recipe broken in new chef version +- [COOK-2660]: Create Debian 6.0 "squeeze" specific template for + apt-cacher-ng + +## v1.9.2: + +* [COOK-2631] - Create Ubuntu 10.04 specific template for apt-cacher-ng + +## v1.9.0: + +* [COOK-2185] - Proxy for apt-key +* [COOK-2338] - Support pinning by glob() or regexp + +## v1.8.4: + +* [COOK-2171] - Update README to clarify required Chef version: 10.18.0 + or higher. + +## v1.8.2: + +* [COOK-2112] - need [] around "arch" in sources.list entries +* [COOK-2171] - fixes a regression in the notification + +## v1.8.0: + +* [COOK-2143] - Allow for a custom cacher-ng port +* [COOK-2171] - On `apt_repository.run_action(:add)` the source file + is not created. +* [COOK-2184] - apt::cacher-ng, use `cacher_port` attribute in + acng.conf + +## v1.7.0: + +* [COOK-2082] - add "arch" parameter to apt_repository LWRP + +## v1.6.0: + +* [COOK-1893] - `apt_preference` use "`package_name`" resource instead of "name" +* [COOK-1894] - change filename for sources.list.d files +* [COOK-1914] - Wrong dir permissions for /etc/apt/preferences.d/ +* [COOK-1942] - README.md has wrong name for the keyserver attribute +* [COOK-2019] - create 01proxy before any other apt-get updates get executed + +## v1.5.2: + +* [COOK-1682] - use template instead of file resource in apt::cacher-client +* [COOK-1875] - cacher-client should be Environment-aware + +## V1.5.0: + +* [COOK-1500] - Avoid triggering apt-get update +* [COOK-1548] - Add execute commands for autoclean and autoremove +* [COOK-1591] - Setting up the apt proxy should leave https + connections direct +* [COOK-1596] - execute[apt-get-update-periodic] never runs +* [COOK-1762] - create /etc/apt/preferences.d directory +* [COOK-1776] - apt key check isn't idempotent + +## v1.4.8: + +* Adds test-kitchen support +* [COOK-1435] - repository lwrp is not idempotent with http key + +## v1.4.6: + +* [COOK-1530] - apt_repository isn't aware of update-success-stamp + file (also reverts COOK-1382 patch). + +## v1.4.4: + +* [COOK-1229] - Allow cacher IP to be set manually in non-Chef Solo + environments +* [COOK-1530] - Immediately update apt-cache when sources.list file is dropped off + +## v1.4.2: + +* [COOK-1155] - LWRP for apt pinning + +## v1.4.0: + +* [COOK-889] - overwrite existing repo source files +* [COOK-921] - optionally use cookbook\_file or remote\_file for key +* [COOK-1032] - fixes problem with apt repository key installation diff --git a/chef/cookbooks/apt/CONTRIBUTING b/chef/cookbooks/apt/CONTRIBUTING new file mode 100644 index 0000000..89ac873 --- /dev/null +++ b/chef/cookbooks/apt/CONTRIBUTING @@ -0,0 +1,29 @@ +If you would like to contribute, please open a ticket in JIRA: + +* http://tickets.opscode.com + +Create the ticket in the COOK project and use the cookbook name as the +component. + +For all code contributions, we ask that contributors sign a +contributor license agreement (CLA). Instructions may be found here: + +* http://wiki.opscode.com/display/chef/How+to+Contribute + +When contributing changes to individual cookbooks, please do not +modify the version number in the metadata.rb. Also please do not +update the CHANGELOG.md for a new version. Not all changes to a +cookbook may be merged and released in the same versions. Opscode will +handle the version updates during the release process. You are welcome +to correct typos or otherwise make updates to documentation in the +README. + +If a contribution adds new platforms or platform versions, indicate +such in the body of the commit message(s), and update the relevant +COOK ticket. When writing commit messages, it is helpful for others if +you indicate the COOK ticket. For example: + + git commit -m '[COOK-1041] Updated pool resource to correctly delete.' + +In the ticket itself, it is also helpful if you include log output of +a successful Chef run, but this is not absolutely required. diff --git a/chef/cookbooks/apt/LICENSE b/chef/cookbooks/apt/LICENSE new file mode 100644 index 0000000..11069ed --- /dev/null +++ b/chef/cookbooks/apt/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/chef/cookbooks/apt/README.md b/chef/cookbooks/apt/README.md new file mode 100644 index 0000000..747a15f --- /dev/null +++ b/chef/cookbooks/apt/README.md @@ -0,0 +1,240 @@ +Description +=========== + +This cookbook includes recipes to execute apt-get update to ensure the +local APT package cache is up to date. There are recipes for managing +the apt-cacher-ng caching proxy and proxy clients. It also includes a +LWRP for managing APT repositories in /etc/apt/sources.list.d as well as +an LWRP for pinning packages via /etc/apt/preferences.d. + +Requirements +============ + +Version 1.8.2+ of this cookbook requires **Chef 10.16.4** or later. + +If your Chef version is earlier than 10.16.4, use version 1.7.0 of +this cookbook. + +See [CHEF-3493](http://tickets.opscode.com/browse/CHEF-3493) and +[this code comment](http://bit.ly/VgvCgf) for more information on this +requirement. + +Platform +-------- + +* Debian +* Ubuntu + +May work with or without modification on other Debian derivatives. + +Recipes +======= + +default +------- + +This recipe installs the `update-notifier-common` package to provide +the timestamp file used to only run `apt-get update` if the cache is +more than one day old. + +This recipe should appear first in the run list of Debian or Ubuntu +nodes to ensure that the package cache is up to date before managing +any `package` resources with Chef. + +This recipe also sets up a local cache directory for preseeding packages. + +cacher-ng +--------- + +Installs the `apt-cacher-ng` package and service so the system can +provide APT caching. You can check the usage report at +http://{hostname}:3142/acng-report.html. The `cacher-ng` recipe +includes the `cacher-client` recipe, so it helps seed itself. + +cacher-client +------------- + +Configures the node to use the `apt-cacher-ng` server as a client. If you +want to restrict your node to using the `apt-cacher-ng` server in your +Environment, set `['apt']['cacher-client']['restrict_environment']` to `true`. + +To use a cacher server (or standard proxy server) not available via search +set the atttribute `['apt']['cacher-ipaddress']` and for a custom port +set `['apt']['cacher_port']`. + +Resources/Providers +=================== + +Managing repositories +--------------------- + +This LWRP provides an easy way to manage additional APT repositories. +Adding a new repository will notify running the `execute[apt-get-update]` +resource immediately. + +# Actions + +- :add: creates a repository file and builds the repository listing +- :remove: removes the repository file + +# Attribute Parameters + +- repo_name: name attribute. The name of the channel to discover +- uri: the base of the Debian distribution +- distribution: this is usually your release's codename...ie something + like `karmic`, `lucid` or `maverick` +- components: package groupings..when it doubt use `main` +- arch: constrain package to a particular arch like `i386`, `amd64` or + even `armhf` or `powerpc`. Defaults to nil. +- deb_src: whether or not to add the repository as a source repo as + well - value can be `true` or `false`, default `false`. +- keyserver: the GPG keyserver where the key for the repo should be retrieved +- key: if a `keyserver` is provided, this is assumed to be the + fingerprint, otherwise it can be either the URI to the GPG key for + the repo, or a cookbook_file. +- key_proxy: if set, pass the specified proxy via `http-proxy=` to GPG. +- cookbook: if key should be a cookbook_file, specify a cookbook where + the key is located for files/default. Defaults to nil, so it will + use the cookbook where the resource is used. + +# Examples + + # add the Zenoss repo + apt_repository "zenoss" do + uri "http://dev.zenoss.org/deb" + components ["main","stable"] + end + + # add the Nginx PPA; grab key from keyserver + apt_repository "nginx-php" do + uri "http://ppa.launchpad.net/nginx/php5/ubuntu" + distribution node['lsb']['codename'] + components ["main"] + keyserver "keyserver.ubuntu.com" + key "C300EE8C" + end + + # add the Nginx PPA; grab key from keyserver, also add source repo + apt_repository "nginx-php" do + uri "http://ppa.launchpad.net/nginx/php5/ubuntu" + distribution node['lsb']['codename'] + components ["main"] + keyserver "keyserver.ubuntu.com" + key "C300EE8C" + deb_src true + end + + # add the Cloudkick Repo + apt_repository "cloudkick" do + uri "http://packages.cloudkick.com/ubuntu" + distribution node['lsb']['codename'] + components ["main"] + key "http://packages.cloudkick.com/cloudkick.packages.key" + end + + # add the Cloudkick Repo with the key downloaded in the cookbook + apt_repository "cloudkick" do + uri "http://packages.cloudkick.com/ubuntu" + distribution node['lsb']['codename'] + components ["main"] + key "cloudkick.packages.key" + end + + # add the Cloudera Repo of CDH4 packages for Ubuntu 12.04 on AMD64 + apt_repository "cloudera" do + uri "http://archive.cloudera.com/cdh4/ubuntu/precise/amd64/cdh" + arch "amd64" + distribution "precise-cdh4" + components ["contrib"] + key "http://archive.cloudera.com/debian/archive.key" + end + + # remove Zenoss repo + apt_repository "zenoss" do + action :remove + end + +Pinning packages +---------------- + +This LWRP provides an easy way to pin packages in /etc/apt/preferences.d. +Although apt-pinning is quite helpful from time to time please note that Debian +does not encourage its use without thorough consideration. + +Further information regarding apt-pinning is available via +http://wiki.debian.org/AptPreferences. + +# Actions + +- :add: creates a preferences file under /etc/apt/preferences.d +- :remove: Removes the file, therefore unpin the package + +# Attribute Parameters + +- package_name: name attribute. The name of the package +- glob: Pin by glob() expression or regexp surrounded by /. +- pin: The package version/repository to pin +- pin_priority: The pinning priority aka "the highest package version wins" + +# Examples + + # Pin libmysqlclient16 to version 5.1.49-3 + apt_preference "libmysqlclient16" do + pin "version 5.1.49-3" + pin_priority "700" + end + + # Unpin libmysqlclient16 + apt_preference "libmysqlclient16" do + action :remove + end + + # Pin all packages from dotdeb.org + apt_preference "dotdeb" do + glob "*" + pin "origin packages.dotdeb.org " + pin_priority "700" + end + +Usage +===== + +Put `recipe[apt]` first in the run list. If you have other recipes +that you want to use to configure how apt behaves, like new sources, +notify the execute resource to run, e.g.: + + template "/etc/apt/sources.list.d/my_apt_sources.list" do + notifies :run, resources(:execute => "apt-get update"), :immediately + end + +The above will run during execution phase since it is a normal +template resource, and should appear before other package resources +that need the sources in the template. + +Put `recipe[apt::cacher-ng]` in the run_list for a server to provide +APT caching and add `recipe[apt::cacher-client]` on the rest of the +Debian-based nodes to take advantage of the caching server. + +If you want to cleanup unused packages, there is also the `apt-get autoclean` +and `apt-get autoremove` resources provided for automated cleanup. + +License and Author +================== + +Author:: Joshua Timberman () +Author:: Matt Ray () +Author:: Seth Chisamore () + +Copyright 2009-2012 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/chef/cookbooks/apt/TESTING.md b/chef/cookbooks/apt/TESTING.md new file mode 100644 index 0000000..e29ff7c --- /dev/null +++ b/chef/cookbooks/apt/TESTING.md @@ -0,0 +1,25 @@ +This cookbook includes support for running tests via Test Kitchen (1.0). This has some requirements. + +1. You must be using the Git repository, rather than the downloaded cookbook from the Chef Community Site. +2. You must have Vagrant 1.1 installed. +3. You must have a "sane" Ruby 1.9.3 environment. + +Once the above requirements are met, install the additional requirements: + +Install the berkshelf plugin for vagrant, and berkshelf to your local Ruby environment. + + vagrant plugin install vagrant-berkshelf + gem install berkshelf + +Install Test Kitchen 1.0 (unreleased yet, use the alpha / prerelease version). + + gem install test-kitchen --pre + +Install the Vagrant driver for Test Kitchen. + + gem install kitchen-vagrant + +Once the above are installed, you should be able to run Test Kitchen: + + kitchen list + kitchen test diff --git a/chef/cookbooks/apt/attributes/default.rb b/chef/cookbooks/apt/attributes/default.rb new file mode 100644 index 0000000..de054f6 --- /dev/null +++ b/chef/cookbooks/apt/attributes/default.rb @@ -0,0 +1,4 @@ +default['apt']['cacher-client']['restrict_environment'] = false +default['apt']['cacher_port'] = 3142 +default['apt']['key_proxy'] = '' +default['apt']['caching_server'] = false diff --git a/chef/cookbooks/apt/files/default/apt-proxy-v2.conf b/chef/cookbooks/apt/files/default/apt-proxy-v2.conf new file mode 100644 index 0000000..6541f25 --- /dev/null +++ b/chef/cookbooks/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/chef/cookbooks/apt/metadata.rb b/chef/cookbooks/apt/metadata.rb new file mode 100644 index 0000000..203d21d --- /dev/null +++ b/chef/cookbooks/apt/metadata.rb @@ -0,0 +1,30 @@ +name "apt" +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Configures apt and apt services and LWRPs for managing apt repositories and preferences" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) +version "1.10.1" +recipe "apt", "Runs apt-get update during compile phase and sets up preseed directories" +recipe "apt::cacher-ng", "Set up an apt-cacher-ng caching proxy" +recipe "apt::cacher-client", "Client for the apt::cacher-ng caching proxy" + +%w{ ubuntu debian }.each do |os| + supports os +end + +attribute "apt/cacher-client/restrict_environment", + :description => "Whether to restrict the search for the caching server to the same environment as this node", + :default => "false" + +attribute "apt/cacher_port", + :description => "Default listen port for the caching server", + :default => "3142" + +attribute "apt/key_proxy", + :description => "Passed as the proxy passed to GPG for the apt_repository resource", + :default => "" + +attribute "apt/caching_server", + :description => "Set this to true if the node is a caching server", + :default => "false" diff --git a/chef/cookbooks/apt/providers/preference.rb b/chef/cookbooks/apt/providers/preference.rb new file mode 100644 index 0000000..8f34e74 --- /dev/null +++ b/chef/cookbooks/apt/providers/preference.rb @@ -0,0 +1,61 @@ +# +# Cookbook Name:: apt +# Provider:: preference +# +# Copyright 2010-2011, 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. +# + +# Build preferences.d file contents +def build_pref(package_name, pin, pin_priority) + preference_content = "Package: #{package_name}\nPin: #{pin}\nPin-Priority: #{pin_priority}\n" +end + +action :add do + new_resource.updated_by_last_action(false) + + preference = build_pref(new_resource.glob || new_resource.package_name, + new_resource.pin, + new_resource.pin_priority) + + preference_dir = directory "/etc/apt/preferences.d" do + owner "root" + group "root" + mode 00755 + recursive true + action :nothing + end + + preference_file = file "/etc/apt/preferences.d/#{new_resource.name}" do + owner "root" + group "root" + mode 00644 + content preference + action :nothing + end + + preference_dir.run_action(:create) + # write out the preference file, replace it if it already exists + preference_file.run_action(:create) +end + +action :remove do + if ::File.exists?("/etc/apt/preferences.d/#{new_resource.name}") + Chef::Log.info "Un-pinning #{new_resource.name} from /etc/apt/preferences.d/" + file "/etc/apt/preferences.d/#{new_resource.name}" do + action :delete + end + new_resource.updated_by_last_action(true) + end +end diff --git a/chef/cookbooks/apt/providers/repository.rb b/chef/cookbooks/apt/providers/repository.rb new file mode 100644 index 0000000..a894ccf --- /dev/null +++ b/chef/cookbooks/apt/providers/repository.rb @@ -0,0 +1,138 @@ +# +# Cookbook Name:: apt +# Provider:: repository +# +# Copyright 2010-2011, 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. +# + +def whyrun_supported? + true +end + +# install apt key from keyserver +def install_key_from_keyserver(key, keyserver) + execute "install-key #{key}" do + if !node['apt']['key_proxy'].empty? + command "apt-key adv --keyserver-options http-proxy=#{node['apt']['key_proxy']} --keyserver #{keyserver} --recv #{key}" + else + command "apt-key adv --keyserver #{keyserver} --recv #{key}" + end + action :run + not_if "apt-key list | grep #{key}" + end +end + +# run command and extract gpg ids +def extract_gpg_ids_from_cmd(cmd) + so = Mixlib::ShellOut.new(cmd) + so.run_command + so.stdout.split(/\n/).collect do |t| + if z = t.match(/^pub\s+\d+\w\/([0-9A-F]{8})/) + z[1] + end + end.compact +end + +# install apt key from URI +def install_key_from_uri(uri) + key_name = uri.split(/\//).last + cached_keyfile = "#{Chef::Config[:file_cache_path]}/#{key_name}" + if new_resource.key =~ /http/ + remote_file cached_keyfile do + source new_resource.key + mode 00644 + action :create + end + else + cookbook_file cached_keyfile do + source new_resource.key + cookbook new_resource.cookbook + mode 00644 + action :create + end + end + + execute "install-key #{key_name}" do + command "apt-key add #{cached_keyfile}" + action :run + not_if do + installed_ids = extract_gpg_ids_from_cmd("apt-key finger") + key_ids = extract_gpg_ids_from_cmd("gpg --with-fingerprint #{cached_keyfile}") + (installed_ids & key_ids).sort == key_ids.sort + end + end +end + +# build repo file contents +def build_repo(uri, distribution, components, arch, add_deb_src) + components = components.join(' ') if components.respond_to?(:join) + repo_info = "#{uri} #{distribution} #{components}\n" + repo_info = "[arch=#{arch}] #{repo_info}" if arch + repo = "deb #{repo_info}" + repo << "deb-src #{repo_info}" if add_deb_src + repo +end + +action :add do + new_resource.updated_by_last_action(false) + @repo_file = nil + + recipe_eval do + # add key + if new_resource.keyserver && new_resource.key + install_key_from_keyserver(new_resource.key, new_resource.keyserver) + elsif new_resource.key + install_key_from_uri(new_resource.key) + end + + file "/var/lib/apt/periodic/update-success-stamp" do + action :nothing + end + + execute "apt-get update" do + ignore_failure true + action :nothing + end + + # build repo file + repository = build_repo(new_resource.uri, + new_resource.distribution, + new_resource.components, + new_resource.arch, + new_resource.deb_src) + + @repo_file = file "/etc/apt/sources.list.d/#{new_resource.name}.list" do + owner "root" + group "root" + mode 00644 + content repository + action :create + notifies :delete, "file[/var/lib/apt/periodic/update-success-stamp]", :immediately + notifies :run, "execute[apt-get update]", :immediately if new_resource.cache_rebuild + end + end + + raise RuntimeError, "The repository file to create is nil, cannot continue." if @repo_file.nil? + new_resource.updated_by_last_action(@repo_file.updated?) +end + +action :remove do + if ::File.exists?("/etc/apt/sources.list.d/#{new_resource.name}.list") + Chef::Log.info "Removing #{new_resource.name} repository from /etc/apt/sources.list.d/" + file "/etc/apt/sources.list.d/#{new_resource.name}.list" do + action :delete + end + end +end diff --git a/chef/cookbooks/apt/recipes/cacher-client.rb b/chef/cookbooks/apt/recipes/cacher-client.rb new file mode 100644 index 0000000..7f2ab2f --- /dev/null +++ b/chef/cookbooks/apt/recipes/cacher-client.rb @@ -0,0 +1,59 @@ +# +# Cookbook Name:: apt +# Recipe:: cacher-client +# +# Copyright 2011, 2012 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. +# + +#remove Acquire::http::Proxy lines from /etc/apt/apt.conf since we use 01proxy +#these are leftover from preseed installs +execute 'Remove proxy from /etc/apt/apt.conf' do + command "sed --in-place '/^Acquire::http::Proxy/d' /etc/apt/apt.conf" + only_if "grep Acquire::http::Proxy /etc/apt/apt.conf" +end + +servers = [] +if node['apt'] && node['apt']['cacher_ipaddress'] + cacher = Chef::Node.new + cacher.name(node['apt']['cacher_ipaddress']) + cacher.set['ipaddress'] = node['apt']['cacher_ipaddress'] + servers << cacher +end + +unless Chef::Config[:solo] + query = "apt_caching_server:true NOT name:#{node.name}" + query += " AND chef_environment:#{node.chef_environment}" if node['apt']['cacher-client']['restrict_environment'] + Chef::Log.debug("apt::cacher-client searching for '#{query}'") + servers += search(:node, query) +end + +if servers.length > 0 + Chef::Log.info("apt-cacher-ng server found on #{servers[0]}.") + template '/etc/apt/apt.conf.d/01proxy' do + source '01proxy.erb' + owner 'root' + group 'root' + mode 00644 + variables( + :proxy => servers[0]['ipaddress'], + :port => node['apt']['cacher_port'] + ) + end.run_action(:create) +else + Chef::Log.info('No apt-cacher-ng server found.') + file '/etc/apt/apt.conf.d/01proxy' do + action :delete + end +end diff --git a/chef/cookbooks/apt/recipes/cacher-ng.rb b/chef/cookbooks/apt/recipes/cacher-ng.rb new file mode 100644 index 0000000..284e2e4 --- /dev/null +++ b/chef/cookbooks/apt/recipes/cacher-ng.rb @@ -0,0 +1,40 @@ +# +# Cookbook Name:: apt +# Recipe:: cacher-ng +# +# Copyright 2008-2012, 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. +# + +node.set['apt']['caching_server'] = true + +package "apt-cacher-ng" do + action :install +end + +template "/etc/apt-cacher-ng/acng.conf" do + source "acng.conf.erb" + owner "root" + group "root" + mode 00644 + notifies :restart, "service[apt-cacher-ng]" +end + +service "apt-cacher-ng" do + supports :restart => true, :status => false + action [:enable, :start] +end + +#this will help seed the proxy +include_recipe "apt::cacher-client" diff --git a/chef/cookbooks/apt/recipes/default.rb b/chef/cookbooks/apt/recipes/default.rb new file mode 100644 index 0000000..a6bd8c4 --- /dev/null +++ b/chef/cookbooks/apt/recipes/default.rb @@ -0,0 +1,68 @@ +# +# Cookbook Name:: apt +# Recipe:: default +# +# Copyright 2008-2011, Opscode, Inc. +# Copyright 2009, Bryan McLellan +# +# 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. +# + +# Run apt-get update to create the stamp file +execute "apt-get-update" do + command "apt-get update" + ignore_failure true + not_if do ::File.exists?('/var/lib/apt/periodic/update-success-stamp') end +end + +# For other recipes to call to force an update +execute "apt-get update" do + command "apt-get update" + ignore_failure true + action :nothing +end + +# Automatically remove packages that are no longer needed for dependencies +execute "apt-get autoremove" do + command "apt-get -y autoremove" + action :nothing +end + +# Automatically remove .deb files for packages no longer on your system +execute "apt-get autoclean" do + command "apt-get -y autoclean" + action :nothing +end + +# provides /var/lib/apt/periodic/update-success-stamp on apt-get update +package "update-notifier-common" do + notifies :run, 'execute[apt-get-update]', :immediately +end + +execute "apt-get-update-periodic" do + command "apt-get update" + ignore_failure true + only_if do + ::File.exists?('/var/lib/apt/periodic/update-success-stamp') && + ::File.mtime('/var/lib/apt/periodic/update-success-stamp') < Time.now - 86400 + end +end + +%w{/var/cache/local /var/cache/local/preseeding}.each do |dirname| + directory dirname do + owner "root" + group "root" + mode 00755 + action :create + end +end diff --git a/chef/cookbooks/apt/resources/preference.rb b/chef/cookbooks/apt/resources/preference.rb new file mode 100644 index 0000000..3ad7207 --- /dev/null +++ b/chef/cookbooks/apt/resources/preference.rb @@ -0,0 +1,30 @@ +# +# Cookbook Name:: apt +# Resource:: preference +# +# Copyright 2010-2011, 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. +# + +actions :add, :remove + +def initialize(*args) + super + @action = :add +end + +attribute :package_name, :kind_of => String, :name_attribute => true +attribute :glob, :kind_of => String +attribute :pin, :kind_of => String +attribute :pin_priority, :kind_of => String diff --git a/chef/cookbooks/apt/resources/repository.rb b/chef/cookbooks/apt/resources/repository.rb new file mode 100644 index 0000000..7515da4 --- /dev/null +++ b/chef/cookbooks/apt/resources/repository.rb @@ -0,0 +1,40 @@ +# +# Cookbook Name:: apt +# Resource:: repository +# +# Copyright 2010-2011, 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. +# + +actions :add, :remove + +def initialize(*args) + super + @action = :add +end + +#name of the repo, used for source.list filename +attribute :repo_name, :kind_of => String, :name_attribute => true +attribute :uri, :kind_of => String +attribute :distribution, :kind_of => String +attribute :components, :kind_of => Array, :default => [] +attribute :arch, :kind_of => String, :default => nil +#whether or not to add the repository as a source repo as well +attribute :deb_src, :default => false +attribute :keyserver, :kind_of => String, :default => nil +attribute :key, :kind_of => String, :default => nil +attribute :cookbook, :kind_of => String, :default => nil +#trigger cache rebuild +#If not you can trigger in the recipe itself after checking the status of resource.updated{_by_last_action}? +attribute :cache_rebuild, :kind_of => [TrueClass, FalseClass], :default => true diff --git a/chef/cookbooks/apt/templates/debian-6.0/acng.conf.erb b/chef/cookbooks/apt/templates/debian-6.0/acng.conf.erb new file mode 100644 index 0000000..38d7a91 --- /dev/null +++ b/chef/cookbooks/apt/templates/debian-6.0/acng.conf.erb @@ -0,0 +1,174 @@ + +# Letter case in directive names does not matter. Must be separated with colons. +# Valid boolean values are a zero number for false, non-zero numbers for true. + +CacheDir: /var/cache/apt-cacher-ng + +# set empty to disable logging +LogDir: /var/log/apt-cacher-ng + +# TCP (http) port +# Set to 9999 to emulate apt-proxy +Port:<%= node['apt']['cacher_port'] %> + +# Addresses or hostnames to listen on. Multiple addresses must be separated by +# spaces. Each entry must be associated with a local interface. DNS resolution +# is performed using getaddrinfo(3) for all available protocols (i.e. IPv4 and +# IPv6 if available). +# +# Default: not set, will listen on all interfaces. +# +# BindAddress: localhost 192.168.7.254 publicNameOnMainInterface + +#Proxy: http://www-proxy.example.net:80 +#proxy: http://username:proxypassword@proxy.example.net:3128 + +# Repository remapping. See manual for details. +# In this example, backends file is generated during package installation. +Remap-debrep: file:deb_mirror*.gz /debian ; file:backends_debian +Remap-uburep: file:ubuntu_mirrors /ubuntu ; file:backends_ubuntu +Remap-debvol: file:debvol_mirror*.gz /debian-volatile ; file:backends_debvol +Remap-cygwin: file:cygwin_mirrors /cygwin # ; file:backends_cygwin # incomplete, please create this file + +# Virtual page accessible in a web browser to see statistics and status +# information, i.e. under http://localhost:3142/acng-report.html +ReportPage: acng-report.html + +# Socket file for accessing through local UNIX socket instead of TCP/IP. Can be +# used with inetd bridge or cron client. +# SocketPath:/var/run/apt-cacher-ng/socket + +# Forces log file to be written to disk after every line when set to 1. Default +# is 0, buffer flush happens after client disconnects. +# +# (technically, this is an alias to the Debug option provided for convenience) +# +# UnbufferLogs: 0 + +# Set to 0 to store only type, time and transfer sizes. +# 1 -> client IP and relative local path are logged too +# VerboseLog: 1 + +# Don't detach from the console +# ForeGround: 0 + +# Store the pid of the daemon process therein +# PidFile: /var/run/apt-cacher-ng/pid + +# Forbid outgoing connections, work around them or respond with 503 error +# offlinemode:0 + +# Forbid all downloads that don't run through preconfigured backends (.where) +#ForceManaged: 0 + +# Days before considering an unreferenced file expired (to be deleted). +# Warning: if the value is set too low and particular index files are not +# available for some days (mirror downtime) there is a risk of deletion of +# still usefull package files. +ExTreshold: 4 + +# Stop expiration when a critical problem appeared. Currently only failed +# refresh of an index file is considered as critical. +# +# WARNING: don't touch this option or set to a non-zero number. +# Anything else is DANGEROUS and may cause data loss. +# +# ExAbortOnProblems: 1 + +# Replace some Windows/DOS-FS incompatible chars when storing +# StupidFs: 0 + +# Experimental feature for apt-listbugs: pass-through SOAP requests and +# responses to/from bugs.debian.org. If not set, default is true if +# ForceManaged is enabled and false otherwise. +# ForwardBtsSoap: 1 + +# The daemon has a small cache for DNS data, to speed up resolution. The +# expiration time of the DNS entries can be configured in seconds. +# DnsCacheSeconds: 3600 + +# Don't touch the following values without good consideration! +# +# Max. count of connection threads kept ready (for faster response in the +# future). Should be a sane value between 0 and average number of connections, +# and depend on the amount of spare RAM. +# MaxStandbyConThreads: 8 +# +# Hard limit of active thread count for incomming connections, i.e. operation +# is refused when this value is reached (below zero = unlimited). +# MaxConThreads: -1 +# +#VfilePattern = (^|.*?/)(Index|Packages\.bz2|Packages\.gz|Packages|Release|Release\.gpg|Sources\.bz2|Sources\.gz|Sources|release|index\.db-.*\.gz|Contents-[^/]*\.gz|pkglist[^/]*\.bz2|rclist[^/]*\.bz2|/meta-release[^/]*|Translation[^/]*\.bz2)$ +#PfilePattern = .*(\.deb|\.rpm|\.dsc|\.tar\.gz\.gpg|\.tar\.gz|\.diff\.gz|\.diff\.bz2|\.jigdo|\.template|changelog|copyright|\.udeb|\.diff/.*\.gz|vmlinuz|initrd\.gz|(Devel)?ReleaseAnnouncement(\\?.*)?)$ +# Whitelist for expiration, file types not to be removed even when being +# unreferenced. Default: same as VfilePattern which is a safe bed. When and +# only when the only used mirrors are official repositories (with working +# Release files) then it might be set to something more restrictive, like +# (^|.*?/)(Release|Release\.gpg|release|meta-release|Translation[^/]*\.bz2)$ +#WfilePattern = (^|.*?/)(Index|Packages\.bz2|Packages\.gz|Packages|Release|Release\.gpg|Sources\.bz2|Sources\.gz|Sources|release|index\.db-.*\.gz|Contents-[^/]*\.gz|pkglist[^/]*\.bz2|rclist[^/]*\.bz2|/meta-release[^/]*|Translation[^/]*\.bz2)$ + +# Higher modes only working with the debug version +# Warning, writes a lot into apt-cacher.err logfile +# Value overwrites UnbufferLogs setting (aliased) +# Debug:3 + +# Usually, general purpose proxies like Squid expose the IP adress of the +# client user to the remote server using the X-Forwarded-For HTTP header. This +# behaviour can be optionally turned on with the Expose-Origin option. +# ExposeOrigin: 0 + +# When logging the originating IP address, trust the information supplied by +# the client in the X-Forwarded-For header. +# LogSubmittedOrigin: 0 + +# The version string reported to the peer, to be displayed as HTTP client (and +# version) in the logs of the mirror. +# WARNING: some archives use this header to detect/guess capabilities of the +# client (i.e. redirection support) and change the behaviour accordingly, while +# ACNG might not support the expected features. Expect side effects. +# +# UserAgent: Yet Another HTTP Client/1.2.3p4 + +# In some cases the Import and Expiration tasks might create fresh volatile +# data for internal use by reconstructing them using patch files. This +# by-product might be recompressed with bzip2 and with some luck the resulting +# file becomes identical to the *.bz2 file on the server, usable for APT +# clients trying to fetch the full .bz2 compressed version. Injection of the +# generated files into the cache has however a disadvantage on underpowered +# servers: bzip2 compession can create high load on the server system and the +# visible download of the busy .bz2 files also becomes slower. +# +# RecompBz2: 0 + +# Network timeout for outgoing connections. +# NetworkTimeout: 60 + +# Sometimes it makes sense to not store the data in cache and just return the +# package data to client as it comes in. DontCache parameters can enable this +# behaviour for certain URL types. The tokens are extended regular expressions +# that URLs are matched against. +# +# DontCacheRequested is applied to the URL as it comes in from the client. +# Example: exclude packages built with kernel-package for x86 +# DontCacheRequested: linux-.*_10\...\.Custo._i386 +# Example usecase: exclude popular private IP ranges from caching +# DontCacheRequested: 192.168.0 ^10\..* 172.30 +# +# DontCacheResolved is applied to URLs after mapping to the target server. If +# multiple backend servers are specified then it's only matched against the +# download link for the FIRST possible source (due to implementation limits). +# Example usecase: all Ubuntu stuff comes from a local mirror (specified as +# backend), don't cache it again: +# DontCacheResolved: ubuntumirror.local.net +# +# DontCache directive sets (overrides) both, DontCacheResolved and +# DontCacheRequested. Provided for convenience, see those directives for +# details. +# +# Default permission set of freshly created files and directories, as octal +# numbers (see chmod(1) for details). +# Can by limited by the umask value (see umask(2) for details) if it's set in +# the environment of the starting shell, e.g. in apt-cacher-ng init script or +# in its configuration file. +# DirPerms: 00755 +# FilePerms: 00664 diff --git a/chef/cookbooks/apt/templates/default/01proxy.erb b/chef/cookbooks/apt/templates/default/01proxy.erb new file mode 100644 index 0000000..eea71c2 --- /dev/null +++ b/chef/cookbooks/apt/templates/default/01proxy.erb @@ -0,0 +1,2 @@ +Acquire::http::Proxy "http://<%= @proxy %>:<%= @port %>"; +Acquire::https::Proxy "DIRECT"; diff --git a/chef/cookbooks/apt/templates/default/acng.conf.erb b/chef/cookbooks/apt/templates/default/acng.conf.erb new file mode 100644 index 0000000..869fdfd --- /dev/null +++ b/chef/cookbooks/apt/templates/default/acng.conf.erb @@ -0,0 +1,276 @@ + +# Letter case in directive names does not matter. Must be separated with colons. +# Valid boolean values are a zero number for false, non-zero numbers for true. + +CacheDir: /var/cache/apt-cacher-ng + +# set empty to disable logging +LogDir: /var/log/apt-cacher-ng + +# place to look for additional configuration and resource files if they are not +# found in the configuration directory +# SupportDir: /usr/lib/apt-cacher-ng + +# TCP (http) port +# Set to 9999 to emulate apt-proxy +Port:<%= node['apt']['cacher_port'] %> + +# Addresses or hostnames to listen on. Multiple addresses must be separated by +# spaces. Each entry must be an exact local address which is associated with a +# local interface. DNS resolution is performed using getaddrinfo(3) for all +# available protocols (IPv4, IPv6, ...). Using a protocol specific format will +# create binding(s) only on protocol specific socket(s) (e.g. 0.0.0.0 will listen +# only to IPv4). +# +# Default: not set, will listen on all interfaces and protocols +# +# BindAddress: localhost 192.168.7.254 publicNameOnMainInterface + +# The specification of another proxy which shall be used for downloads. +# Username and password are, and see manual for limitations. +# +#Proxy: http://www-proxy.example.net:80 +#proxy: username:proxypassword@proxy.example.net:3128 + +# Repository remapping. See manual for details. +# In this example, some backends files might be generated during package +# installation using information collected on the system. +Remap-debrep: file:deb_mirror*.gz /debian ; file:backends_debian # Debian Archives +Remap-uburep: file:ubuntu_mirrors /ubuntu ; file:backends_ubuntu # Ubuntu Archives +Remap-debvol: file:debvol_mirror*.gz /debian-volatile ; file:backends_debvol # Debian Volatile Archives +Remap-cygwin: file:cygwin_mirrors /cygwin # ; file:backends_cygwin # incomplete, please create this file or specify preferred mirrors here +Remap-sfnet: file:sfnet_mirrors # ; file:backends_sfnet # incomplete, please create this file or specify preferred mirrors here +Remap-alxrep: file:archlx_mirrors /archlinux # ; file:backend_archlx # Arch Linux +Remap-fedora: file:fedora_mirrors # Fedora Linux +Remap-epel: file:epel_mirrors # Fedora EPEL +Remap-slrep: file:sl_mirrors # Scientific Linux + +# This is usually not needed for security.debian.org because it's always the +# same DNS hostname. However, it might be enabled in order to use hooks, +# ForceManaged mode or special flags in this context. +# Remap-secdeb: security.debian.org + +# Virtual page accessible in a web browser to see statistics and status +# information, i.e. under http://localhost:3142/acng-report.html +ReportPage: acng-report.html + +# Socket file for accessing through local UNIX socket instead of TCP/IP. Can be +# used with inetd bridge or cron client. +# SocketPath:/var/run/apt-cacher-ng/socket + +# Forces log file to be written to disk after every line when set to 1. Default +# is 0, buffers are flushed when the client disconnects. +# +# (technically, alias to the Debug option, see its documentation for details) +# +# UnbufferLogs: 0 + +# Set to 0 to store only type, time and transfer sizes. +# 1 -> client IP and relative local path are logged too +# VerboseLog: 1 + +# Don't detach from the console +# ForeGround: 0 + +# Store the pid of the daemon process therein +# PidFile: /var/run/apt-cacher-ng/pid + +# Forbid outgoing connections, work around them or respond with 503 error +# offlinemode:0 + +# Forbid all downloads that don't run through preconfigured backends (.where) +#ForceManaged: 0 + +# Days before considering an unreferenced file expired (to be deleted). +# Warning: if the value is set too low and particular index files are not +# available for some days (mirror downtime) there is a risk of deletion of +# still useful package files. +ExTreshold: 4 + +# Stop expiration when a critical problem appeared. Currently only failed +# refresh of an index file is considered as critical. +# +# WARNING: don't touch this option or set to zero. +# Anything else is DANGEROUS and may cause data loss. +# +# ExAbortOnProblems: 1 + +# Replace some Windows/DOS-FS incompatible chars when storing +# StupidFs: 0 + +# Experimental feature for apt-listbugs: pass-through SOAP requests and +# responses to/from bugs.debian.org. If not set, default is true if +# ForceManaged is enabled and false otherwise. +# ForwardBtsSoap: 1 + +# The daemon has a small cache for DNS data, to speed up resolution. The +# expiration time of the DNS entries can be configured in seconds. +# DnsCacheSeconds: 3600 + +# Don't touch the following values without good consideration! +# +# Max. count of connection threads kept ready (for faster response in the +# future). Should be a sane value between 0 and average number of connections, +# and depend on the amount of spare RAM. +# MaxStandbyConThreads: 8 +# +# Hard limit of active thread count for incoming connections, i.e. operation +# is refused when this value is reached (below zero = unlimited). +# MaxConThreads: -1 +# +# Pigeonholing files with regular expressions (static/volatile). Can be +# overriden here but not should not be done permanently because future update +# of default settings would not be applied later. +# VfilePattern = (^|.*?/)(Index|Packages(\.gz|\.bz2|\.lzma|\.xz)?|InRelease|Release|Release\.gpg|Sources(\.gz|\.bz2|\.lzma|\.xz)?|release|index\.db-.*\.gz|Contents-[^/]*(\.gz|\.bz2|\.lzma|\.xz)?|pkglist[^/]*\.bz2|rclist[^/]*\.bz2|/meta-release[^/]*|Translation[^/]*(\.gz|\.bz2|\.lzma|\.xz)?|MD5SUMS|SHA1SUMS|((setup|setup-legacy)(\.ini|\.bz2|\.hint)(\.sig)?)|mirrors\.lst|repo(index|md)\.xml(\.asc|\.key)?|directory\.yast|products|content(\.asc|\.key)?|media|filelists\.xml\.gz|filelists\.sqlite\.bz2|repomd\.xml|packages\.[a-zA-Z][a-zA-Z]\.gz|info\.txt|license\.tar\.gz|license\.zip|.*\.db(\.tar\.gz)?|.*\.files\.tar\.gz|.*\.abs\.tar\.gz|metalink\?repo|.*prestodelta\.xml\.gz)$|/dists/.*/installer-[^/]+/[^0-9][^/]+/images/.* +# PfilePattern = .*(\.d?deb|\.rpm|\.dsc|\.tar(\.gz|\.bz2|\.lzma|\.xz)(\.gpg)?|\.diff(\.gz|\.bz2|\.lzma|\.xz)|\.jigdo|\.template|changelog|copyright|\.udeb|\.debdelta|\.diff/.*\.gz|(Devel)?ReleaseAnnouncement(\?.*)?|[a-f0-9]+-(susedata|updateinfo|primary|deltainfo).xml.gz|fonts/(final/)?[a-z]+32.exe(\?download.*)?|/dists/.*/installer-[^/]+/[0-9][^/]+/images/.*)$ +# Whitelist for expiration, file types not to be removed even when being +# unreferenced. Default: many parts from VfilePattern where no parent index +# exists or might be unknown. +# WfilePattern = (^|.*?/)(Release|InRelease|Release\.gpg|(Packages|Sources)(\.gz|\.bz2|\.lzma|\.xz)?|Translation[^/]*(\.gz|\.bz2|\.lzma|\.xz)?|MD5SUMS|SHA1SUMS|.*\.xml|.*\.db\.tar\.gz|.*\.files\.tar\.gz|.*\.abs\.tar\.gz|[a-z]+32.exe)$|/dists/.*/installer-.*/images/.* + +# Higher modes only working with the debug version +# Warning, writes a lot into apt-cacher.err logfile +# Value overwrites UnbufferLogs setting (aliased) +# Debug:3 + +# Usually, general purpose proxies like Squid expose the IP address of the +# client user to the remote server using the X-Forwarded-For HTTP header. This +# behaviour can be optionally turned on with the Expose-Origin option. +# ExposeOrigin: 0 + +# When logging the originating IP address, trust the information supplied by +# the client in the X-Forwarded-For header. +# LogSubmittedOrigin: 0 + +# The version string reported to the peer, to be displayed as HTTP client (and +# version) in the logs of the mirror. +# WARNING: some archives use this header to detect/guess capabilities of the +# client (i.e. redirection support) and change the behaviour accordingly, while +# ACNG might not support the expected features. Expect side effects. +# +# UserAgent: Yet Another HTTP Client/1.2.3p4 + +# In some cases the Import and Expiration tasks might create fresh volatile +# data for internal use by reconstructing them using patch files. This +# by-product might be recompressed with bzip2 and with some luck the resulting +# file becomes identical to the *.bz2 file on the server, usable for APT +# clients trying to fetch the full .bz2 compressed version. Injection of the +# generated files into the cache has however a disadvantage on underpowered +# servers: bzip2 compression can create high load on the server system and the +# visible download of the busy .bz2 files also becomes slower. +# +# RecompBz2: 0 + +# Network timeout for outgoing connections. +# NetworkTimeout: 60 + +# Sometimes it makes sense to not store the data in cache and just return the +# package data to client as it comes in. DontCache parameters can enable this +# behaviour for certain URL types. The tokens are extended regular expressions +# that URLs are matched against. +# +# DontCacheRequested is applied to the URL as it comes in from the client. +# Example: exclude packages built with kernel-package for x86 +# DontCacheRequested: linux-.*_10\...\.Custo._i386 +# Example usecase: exclude popular private IP ranges from caching +# DontCacheRequested: 192.168.0 ^10\..* 172.30 +# +# DontCacheResolved is applied to URLs after mapping to the target server. If +# multiple backend servers are specified then it's only matched against the +# download link for the FIRST possible source (due to implementation limits). +# Example usecase: all Ubuntu stuff comes from a local mirror (specified as +# backend), don't cache it again: +# DontCacheResolved: ubuntumirror.local.net +# +# DontCache directive sets (overrides) both, DontCacheResolved and +# DontCacheRequested. Provided for convenience, see those directives for +# details. +# +# Default permission set of freshly created files and directories, as octal +# numbers (see chmod(1) for details). +# Can by limited by the umask value (see umask(2) for details) if it's set in +# the environment of the starting shell, e.g. in apt-cacher-ng init script or +# in its configuration file. +# DirPerms: 00755 +# FilePerms: 00664 +# +# +# It's possible to use use apt-cacher-ng as a regular web server with limited +# feature set, i.e. +# including directory browsing and download of any file; +# excluding sorting, mime types/encodings, CGI execution, index page +# redirection and other funny things. +# To get this behavior, mappings between virtual directories and real +# directories on the server must be defined with the LocalDirs directive. +# Virtual and real dirs are separated by spaces, multiple pairs are separated +# by semi-colons. Real directories must be absolute paths. +# NOTE: Since the names of that key directories share the same namespace as +# repository names (see Remap-...) it's administrators job to avoid such +# collisions on them (unless created deliberately). +# +# LocalDirs: woo /data/debarchive/woody ; hamm /data/debarchive/hamm + +# Precache a set of files referenced by specified index files. This can be used +# to create a partial mirror usable for offline work. There are certain limits +# and restrictions on the path specification, see manual for details. A list of +# (maybe) relevant index files could be retrieved via +# "apt-get --print-uris update" on a client machine. +# +# PrecacheFor: debrep/dists/unstable/*/source/Sources* debrep/dists/unstable/*/binary-amd64/Packages* + +# Arbitrary set of data to append to request headers sent over the wire. Should +# be a well formated HTTP headers part including newlines (DOS style) which +# can be entered as escape sequences (\r\n). +# RequestAppendix: X-Tracking-Choice: do-not-track\r\n + +# Specifies the IP protocol families to use for remote connections. Order does +# matter, first specified are considered first. Possible combinations: +# v6 v4 +# v4 v6 +# v6 +# v4 +# (empty or not set: use system default) +# +# ConnectProto: v6 v4 + +# Regular expiration algorithm finds package files which are no longer listed +# in any index file and removes them of them after a safety period. +# This option allows to keep more versions of a package in the cache after +# safety period is over. +# KeepExtraVersions: 1 + +# Optionally uses TCP access control provided by libwrap, see hosts_access(5) +# for details. Daemon name is apt-cacher-ng. Default if not set: decided on +# startup by looking for explicit mentioning of apt-cacher-ng in +# /etc/hosts.allow or /etc/hosts.deny files. +# UseWrap: 0 + +# If many machines from the same local network attempt to update index files +# (apt-get update) at nearly the same time, the known state of these index file +# is temporarily frozen and multiple requests receive the cached response +# without contacting the server. This parameter (in seconds) specifies the +# length of this period before the files are considered outdated. +# Setting it too low transfers more data and increases remote server load, +# setting it too high (more than a couple of minutes) increases the risk of +# delivering inconsistent responses to the clients. +# FreshIndexMaxAge: 27 + +# Usually the users are not allowed to specify custom TCP ports of remote +# mirrors in the requests, only the default HTTP port can be used (instead, +# proxy administrator can create Remap- rules with custom ports). This +# restriction can be disabled by specifying a list of allowed ports or 0 for +# any port. +# +# AllowUserPorts: 80 + +# Normally the HTTP redirection responses are forwarded to the original caller +# (i.e. APT) which starts a new download attempt from the new URL. This +# solution is ok for client configurations with proxy mode but doesn't work +# well with configurations using URL prefixes. To work around this the server +# can restart its own download with another URL. However, this might be used to +# circumvent download source policies by malicious users. +# The RedirMax option specifies how many such redirects the server should +# follow per request, 0 disables the internal redirection. If not set, +# default value is 0 if ForceManaged is used and 5 otherwise. +# +# RedirMax: 5 \ No newline at end of file diff --git a/chef/cookbooks/apt/templates/ubuntu-10.04/acng.conf.erb b/chef/cookbooks/apt/templates/ubuntu-10.04/acng.conf.erb new file mode 100644 index 0000000..fabbba4 --- /dev/null +++ b/chef/cookbooks/apt/templates/ubuntu-10.04/acng.conf.erb @@ -0,0 +1,270 @@ + +# Letter case in directive names does not matter. Must be separated with colons. +# Valid boolean values are a zero number for false, non-zero numbers for true. + +CacheDir: /var/cache/apt-cacher-ng + +# set empty to disable logging +LogDir: /var/log/apt-cacher-ng + +# place to look for additional configuration and resource files if they are not +# found in the configuration directory +# SupportDir: /usr/lib/apt-cacher-ng + +# TCP (http) port +# Set to 9999 to emulate apt-proxy +Port:<%= node['apt']['cacher_port'] %> + +# Addresses or hostnames to listen on. Multiple addresses must be separated by +# spaces. Each entry must be an exact local address which is associated with a +# local interface. DNS resolution is performed using getaddrinfo(3) for all +# available protocols (IPv4, IPv6, ...). Using a protocol specific format will +# create binding(s) only on protocol specific socket(s) (e.g. 0.0.0.0 will listen +# only to IPv4). +# +# Default: not set, will listen on all interfaces and protocols +# +# BindAddress: localhost 192.168.7.254 publicNameOnMainInterface + +# The specification of another proxy which shall be used for downloads. +# Username and password are, and see manual for limitations. +# +#Proxy: http://www-proxy.example.net:80 +#proxy: username:proxypassword@proxy.example.net:3128 + +# Repository remapping. See manual for details. +# In this example, some backends files might be generated during package +# installation using information collected on the system. +Remap-debrep: file:deb_mirror*.gz /debian ; file:backends_debian # Debian Archives +Remap-uburep: file:ubuntu_mirrors /ubuntu ; file:backends_ubuntu # Ubuntu Archives +Remap-debvol: file:debvol_mirror*.gz /debian-volatile ; file:backends_debvol # Debian Volatile Archives + +# This is usually not needed for security.debian.org because it's always the +# same DNS hostname. However, it might be enabled in order to use hooks, +# ForceManaged mode or special flags in this context. +# Remap-secdeb: security.debian.org + +# Virtual page accessible in a web browser to see statistics and status +# information, i.e. under http://localhost:3142/acng-report.html +ReportPage: acng-report.html + +# Socket file for accessing through local UNIX socket instead of TCP/IP. Can be +# used with inetd bridge or cron client. +# SocketPath:/var/run/apt-cacher-ng/socket + +# Forces log file to be written to disk after every line when set to 1. Default +# is 0, buffers are flushed when the client disconnects. +# +# (technically, alias to the Debug option, see its documentation for details) +# +# UnbufferLogs: 0 + +# Set to 0 to store only type, time and transfer sizes. +# 1 -> client IP and relative local path are logged too +# VerboseLog: 1 + +# Don't detach from the console +# ForeGround: 0 + +# Store the pid of the daemon process therein +# PidFile: /var/run/apt-cacher-ng/pid + +# Forbid outgoing connections, work around them or respond with 503 error +# offlinemode:0 + +# Forbid all downloads that don't run through preconfigured backends (.where) +#ForceManaged: 0 + +# Days before considering an unreferenced file expired (to be deleted). +# Warning: if the value is set too low and particular index files are not +# available for some days (mirror downtime) there is a risk of deletion of +# still useful package files. +ExTreshold: 4 + +# Stop expiration when a critical problem appeared. Currently only failed +# refresh of an index file is considered as critical. +# +# WARNING: don't touch this option or set to zero. +# Anything else is DANGEROUS and may cause data loss. +# +# ExAbortOnProblems: 1 + +# Replace some Windows/DOS-FS incompatible chars when storing +# StupidFs: 0 + +# Experimental feature for apt-listbugs: pass-through SOAP requests and +# responses to/from bugs.debian.org. If not set, default is true if +# ForceManaged is enabled and false otherwise. +# ForwardBtsSoap: 1 + +# The daemon has a small cache for DNS data, to speed up resolution. The +# expiration time of the DNS entries can be configured in seconds. +# DnsCacheSeconds: 3600 + +# Don't touch the following values without good consideration! +# +# Max. count of connection threads kept ready (for faster response in the +# future). Should be a sane value between 0 and average number of connections, +# and depend on the amount of spare RAM. +# MaxStandbyConThreads: 8 +# +# Hard limit of active thread count for incoming connections, i.e. operation +# is refused when this value is reached (below zero = unlimited). +# MaxConThreads: -1 +# +# Pigeonholing files with regular expressions (static/volatile). Can be +# overriden here but not should not be done permanently because future update +# of default settings would not be applied later. +# VfilePattern = (^|.*?/)(Index|Packages(\.gz|\.bz2|\.lzma|\.xz)?|InRelease|Release|Release\.gpg|Sources(\.gz|\.bz2|\.lzma|\.xz)?|release|index\.db-.*\.gz|Contents-[^/]*(\.gz|\.bz2|\.lzma|\.xz)?|pkglist[^/]*\.bz2|rclist[^/]*\.bz2|/meta-release[^/]*|Translation[^/]*(\.gz|\.bz2|\.lzma|\.xz)?|MD5SUMS|SHA1SUMS|((setup|setup-legacy)(\.ini|\.bz2|\.hint)(\.sig)?)|mirrors\.lst|repo(index|md)\.xml(\.asc|\.key)?|directory\.yast|products|content(\.asc|\.key)?|media|filelists\.xml\.gz|filelists\.sqlite\.bz2|repomd\.xml|packages\.[a-zA-Z][a-zA-Z]\.gz|info\.txt|license\.tar\.gz|license\.zip|.*\.db(\.tar\.gz)?|.*\.files\.tar\.gz|.*\.abs\.tar\.gz|metalink\?repo|.*prestodelta\.xml\.gz)$|/dists/.*/installer-[^/]+/[^0-9][^/]+/images/.* +# PfilePattern = .*(\.d?deb|\.rpm|\.dsc|\.tar(\.gz|\.bz2|\.lzma|\.xz)(\.gpg)?|\.diff(\.gz|\.bz2|\.lzma|\.xz)|\.jigdo|\.template|changelog|copyright|\.udeb|\.debdelta|\.diff/.*\.gz|(Devel)?ReleaseAnnouncement(\?.*)?|[a-f0-9]+-(susedata|updateinfo|primary|deltainfo).xml.gz|fonts/(final/)?[a-z]+32.exe(\?download.*)?|/dists/.*/installer-[^/]+/[0-9][^/]+/images/.*)$ +# Whitelist for expiration, file types not to be removed even when being +# unreferenced. Default: many parts from VfilePattern where no parent index +# exists or might be unknown. +# WfilePattern = (^|.*?/)(Release|InRelease|Release\.gpg|(Packages|Sources)(\.gz|\.bz2|\.lzma|\.xz)?|Translation[^/]*(\.gz|\.bz2|\.lzma|\.xz)?|MD5SUMS|SHA1SUMS|.*\.xml|.*\.db\.tar\.gz|.*\.files\.tar\.gz|.*\.abs\.tar\.gz|[a-z]+32.exe)$|/dists/.*/installer-.*/images/.* + +# Higher modes only working with the debug version +# Warning, writes a lot into apt-cacher.err logfile +# Value overwrites UnbufferLogs setting (aliased) +# Debug:3 + +# Usually, general purpose proxies like Squid expose the IP address of the +# client user to the remote server using the X-Forwarded-For HTTP header. This +# behaviour can be optionally turned on with the Expose-Origin option. +# ExposeOrigin: 0 + +# When logging the originating IP address, trust the information supplied by +# the client in the X-Forwarded-For header. +# LogSubmittedOrigin: 0 + +# The version string reported to the peer, to be displayed as HTTP client (and +# version) in the logs of the mirror. +# WARNING: some archives use this header to detect/guess capabilities of the +# client (i.e. redirection support) and change the behaviour accordingly, while +# ACNG might not support the expected features. Expect side effects. +# +# UserAgent: Yet Another HTTP Client/1.2.3p4 + +# In some cases the Import and Expiration tasks might create fresh volatile +# data for internal use by reconstructing them using patch files. This +# by-product might be recompressed with bzip2 and with some luck the resulting +# file becomes identical to the *.bz2 file on the server, usable for APT +# clients trying to fetch the full .bz2 compressed version. Injection of the +# generated files into the cache has however a disadvantage on underpowered +# servers: bzip2 compression can create high load on the server system and the +# visible download of the busy .bz2 files also becomes slower. +# +# RecompBz2: 0 + +# Network timeout for outgoing connections. +# NetworkTimeout: 60 + +# Sometimes it makes sense to not store the data in cache and just return the +# package data to client as it comes in. DontCache parameters can enable this +# behaviour for certain URL types. The tokens are extended regular expressions +# that URLs are matched against. +# +# DontCacheRequested is applied to the URL as it comes in from the client. +# Example: exclude packages built with kernel-package for x86 +# DontCacheRequested: linux-.*_10\...\.Custo._i386 +# Example usecase: exclude popular private IP ranges from caching +# DontCacheRequested: 192.168.0 ^10\..* 172.30 +# +# DontCacheResolved is applied to URLs after mapping to the target server. If +# multiple backend servers are specified then it's only matched against the +# download link for the FIRST possible source (due to implementation limits). +# Example usecase: all Ubuntu stuff comes from a local mirror (specified as +# backend), don't cache it again: +# DontCacheResolved: ubuntumirror.local.net +# +# DontCache directive sets (overrides) both, DontCacheResolved and +# DontCacheRequested. Provided for convenience, see those directives for +# details. +# +# Default permission set of freshly created files and directories, as octal +# numbers (see chmod(1) for details). +# Can by limited by the umask value (see umask(2) for details) if it's set in +# the environment of the starting shell, e.g. in apt-cacher-ng init script or +# in its configuration file. +# DirPerms: 00755 +# FilePerms: 00664 +# +# +# It's possible to use use apt-cacher-ng as a regular web server with limited +# feature set, i.e. +# including directory browsing and download of any file; +# excluding sorting, mime types/encodings, CGI execution, index page +# redirection and other funny things. +# To get this behavior, mappings between virtual directories and real +# directories on the server must be defined with the LocalDirs directive. +# Virtual and real dirs are separated by spaces, multiple pairs are separated +# by semi-colons. Real directories must be absolute paths. +# NOTE: Since the names of that key directories share the same namespace as +# repository names (see Remap-...) it's administrators job to avoid such +# collisions on them (unless created deliberately). +# +# LocalDirs: woo /data/debarchive/woody ; hamm /data/debarchive/hamm + +# Precache a set of files referenced by specified index files. This can be used +# to create a partial mirror usable for offline work. There are certain limits +# and restrictions on the path specification, see manual for details. A list of +# (maybe) relevant index files could be retrieved via +# "apt-get --print-uris update" on a client machine. +# +# PrecacheFor: debrep/dists/unstable/*/source/Sources* debrep/dists/unstable/*/binary-amd64/Packages* + +# Arbitrary set of data to append to request headers sent over the wire. Should +# be a well formated HTTP headers part including newlines (DOS style) which +# can be entered as escape sequences (\r\n). +# RequestAppendix: X-Tracking-Choice: do-not-track\r\n + +# Specifies the IP protocol families to use for remote connections. Order does +# matter, first specified are considered first. Possible combinations: +# v6 v4 +# v4 v6 +# v6 +# v4 +# (empty or not set: use system default) +# +# ConnectProto: v6 v4 + +# Regular expiration algorithm finds package files which are no longer listed +# in any index file and removes them of them after a safety period. +# This option allows to keep more versions of a package in the cache after +# safety period is over. +# KeepExtraVersions: 1 + +# Optionally uses TCP access control provided by libwrap, see hosts_access(5) +# for details. Daemon name is apt-cacher-ng. Default if not set: decided on +# startup by looking for explicit mentioning of apt-cacher-ng in +# /etc/hosts.allow or /etc/hosts.deny files. +# UseWrap: 0 + +# If many machines from the same local network attempt to update index files +# (apt-get update) at nearly the same time, the known state of these index file +# is temporarily frozen and multiple requests receive the cached response +# without contacting the server. This parameter (in seconds) specifies the +# length of this period before the files are considered outdated. +# Setting it too low transfers more data and increases remote server load, +# setting it too high (more than a couple of minutes) increases the risk of +# delivering inconsistent responses to the clients. +# FreshIndexMaxAge: 27 + +# Usually the users are not allowed to specify custom TCP ports of remote +# mirrors in the requests, only the default HTTP port can be used (instead, +# proxy administrator can create Remap- rules with custom ports). This +# restriction can be disabled by specifying a list of allowed ports or 0 for +# any port. +# +# AllowUserPorts: 80 + +# Normally the HTTP redirection responses are forwarded to the original caller +# (i.e. APT) which starts a new download attempt from the new URL. This +# solution is ok for client configurations with proxy mode but doesn't work +# well with configurations using URL prefixes. To work around this the server +# can restart its own download with another URL. However, this might be used to +# circumvent download source policies by malicious users. +# The RedirMax option specifies how many such redirects the server should +# follow per request, 0 disables the internal redirection. If not set, +# default value is 0 if ForceManaged is used and 5 otherwise. +# +# RedirMax: 5 \ No newline at end of file diff --git a/chef/cookbooks/apt/test/cookbooks/apt_test/README.md b/chef/cookbooks/apt/test/cookbooks/apt_test/README.md new file mode 100644 index 0000000..6e1f578 --- /dev/null +++ b/chef/cookbooks/apt/test/cookbooks/apt_test/README.md @@ -0,0 +1 @@ +This cookbook is used with test-kitchen to test the parent, apt cookbok diff --git a/chef/cookbooks/apt/test/cookbooks/apt_test/files/default/tests/minitest/cacher-ng_test.rb b/chef/cookbooks/apt/test/cookbooks/apt_test/files/default/tests/minitest/cacher-ng_test.rb new file mode 100644 index 0000000..f3cdce5 --- /dev/null +++ b/chef/cookbooks/apt/test/cookbooks/apt_test/files/default/tests/minitest/cacher-ng_test.rb @@ -0,0 +1,28 @@ +# +# Cookbook Name:: apt_test +# Recipe:: default +# +# Copyright 2012, 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 File.expand_path('../support/helpers', __FILE__) + +describe "apt_test::default" do + include Helpers::AptTest + + it 'runs the cacher service' do + service("apt-cacher-ng").must_be_running + end +end diff --git a/chef/cookbooks/apt/test/cookbooks/apt_test/files/default/tests/minitest/default_test.rb b/chef/cookbooks/apt/test/cookbooks/apt_test/files/default/tests/minitest/default_test.rb new file mode 100644 index 0000000..ab97676 --- /dev/null +++ b/chef/cookbooks/apt/test/cookbooks/apt_test/files/default/tests/minitest/default_test.rb @@ -0,0 +1,28 @@ +# +# Cookbook Name:: apt_test +# Recipe:: default +# +# Copyright 2012, 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 File.expand_path('../support/helpers', __FILE__) + +describe "apt_test::default" do + include Helpers::AptTest + + it 'creates the preseeding directory' do + directory('/var/cache/local/preseeding').must_exist + end +end diff --git a/chef/cookbooks/apt/test/cookbooks/apt_test/files/default/tests/minitest/lwrps_test.rb b/chef/cookbooks/apt/test/cookbooks/apt_test/files/default/tests/minitest/lwrps_test.rb new file mode 100644 index 0000000..b9c5cb3 --- /dev/null +++ b/chef/cookbooks/apt/test/cookbooks/apt_test/files/default/tests/minitest/lwrps_test.rb @@ -0,0 +1,48 @@ +# +# Cookbook Name:: apt_test +# Recipe:: lwrps +# +# Copyright 2012, 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 File.expand_path('../support/helpers', __FILE__) + +describe "apt_test::lwrps" do + include Helpers::AptTest + + it 'creates the Opscode sources.list' do + file("/etc/apt/sources.list.d/opscode.list").must_exist + end + + it 'adds the Opscode package signing key' do + opscode_key = shell_out("apt-key list") + assert opscode_key.stdout.include?("Opscode Packages ") + end + + it 'creates the correct pinning preferences for chef' do + pinning_prefs = "Package: chef\nPin: version 10.16.2-1" + file("/etc/apt/preferences.d/chef").must_match(/#{pinning_prefs}/) + end + + it 'creates a repo with an architecture' do + cloudera = "deb\s+\\[arch=amd64\\] http://archive.cloudera.com/cdh4/ubuntu/precise/amd64/cdh precise-cdh4 contrib" + file("/etc/apt/sources.list.d/cloudera.list").must_match(/#{cloudera}/) + end + + it 'creates the correct pinning preferences with a glob' do + pinning_prefs = "Package: \\*\nPin: origin packages.dotdeb.org" + file("/etc/apt/preferences.d/dotdeb").must_match(/#{pinning_prefs}/) + end +end diff --git a/chef/cookbooks/apt/test/cookbooks/apt_test/files/default/tests/minitest/support/helpers.rb b/chef/cookbooks/apt/test/cookbooks/apt_test/files/default/tests/minitest/support/helpers.rb new file mode 100644 index 0000000..33a4ac8 --- /dev/null +++ b/chef/cookbooks/apt/test/cookbooks/apt_test/files/default/tests/minitest/support/helpers.rb @@ -0,0 +1,29 @@ +# +# Cookbook Name:: apt_test +# Recipe:: default +# +# Copyright 2012, 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. +# + +module Helpers + module AptTest + require 'chef/mixin/shell_out' + include Chef::Mixin::ShellOut + include MiniTest::Chef::Assertions + include MiniTest::Chef::Context + include MiniTest::Chef::Resources + + end +end diff --git a/chef/cookbooks/apt/test/cookbooks/apt_test/metadata.rb b/chef/cookbooks/apt/test/cookbooks/apt_test/metadata.rb new file mode 100644 index 0000000..f909851 --- /dev/null +++ b/chef/cookbooks/apt/test/cookbooks/apt_test/metadata.rb @@ -0,0 +1,6 @@ +name "apt_test" +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "This cookbook is used with test-kitchen to test the parent, apt cookbok" +version "1.0.0" diff --git a/chef/cookbooks/apt/test/cookbooks/apt_test/recipes/cacher-ng.rb b/chef/cookbooks/apt/test/cookbooks/apt_test/recipes/cacher-ng.rb new file mode 100644 index 0000000..20ae214 --- /dev/null +++ b/chef/cookbooks/apt/test/cookbooks/apt_test/recipes/cacher-ng.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: apt_test +# Recipe:: cacher-ng +# +# Copyright 2012, 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::cacher-ng" diff --git a/chef/cookbooks/apt/test/cookbooks/apt_test/recipes/default.rb b/chef/cookbooks/apt/test/cookbooks/apt_test/recipes/default.rb new file mode 100644 index 0000000..ce4d3f9 --- /dev/null +++ b/chef/cookbooks/apt/test/cookbooks/apt_test/recipes/default.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: apt_test +# Recipe:: default +# +# Copyright 2012, 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::default" diff --git a/chef/cookbooks/apt/test/cookbooks/apt_test/recipes/lwrps.rb b/chef/cookbooks/apt/test/cookbooks/apt_test/recipes/lwrps.rb new file mode 100644 index 0000000..f8bb2ae --- /dev/null +++ b/chef/cookbooks/apt/test/cookbooks/apt_test/recipes/lwrps.rb @@ -0,0 +1,66 @@ +# +# Cookbook Name:: apt_test +# Recipe:: lwrps +# +# Copyright 2012, 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" + +# Apt Repository +apt_repository "opscode" do + uri "http://apt.opscode.com" + components ["main"] + distribution "#{node['lsb']['codename']}-0.10" + key "2940ABA983EF826A" + keyserver "pgpkeys.mit.edu" + action :add +end + +# Apt Repository with arch +apt_repository "cloudera" do + uri "http://archive.cloudera.com/cdh4/ubuntu/precise/amd64/cdh" + arch "amd64" + distribution "precise-cdh4" + components ["contrib"] + key "http://archive.cloudera.com/debian/archive.key" + action :add +end + +# Apt repository and install a package it contains +apt_repository "nginx" do + uri "http://nginx.org/packages/ubuntu" + distribution node['lsb']['codename'] + components ["nginx"] + key "http://nginx.org/keys/nginx_signing.key" + deb_src true +end + +package "nginx-debug" do + action :upgrade +end + +# Apt Preferences +apt_preference "chef" do + pin "version 10.16.2-1" + pin_priority "700" +end + +# COOK-2338 +apt_preference "dotdeb" do + glob "*" + pin "origin packages.dotdeb.org " + pin_priority "700" +end diff --git a/chef/cookbooks/mysql/.gitignore b/chef/cookbooks/mysql/.gitignore new file mode 100644 index 0000000..852d35c --- /dev/null +++ b/chef/cookbooks/mysql/.gitignore @@ -0,0 +1,7 @@ +.bundle +.cache +.kitchen +bin +*.sw[op] + +Gemfile.lock diff --git a/chef/cookbooks/mysql/.kitchen.yml b/chef/cookbooks/mysql/.kitchen.yml new file mode 100644 index 0000000..a7d5cb3 --- /dev/null +++ b/chef/cookbooks/mysql/.kitchen.yml @@ -0,0 +1,45 @@ +--- +driver_plugin: vagrant +platforms: +- name: ubuntu-12.04 + driver_config: + box: canonical-ubuntu-12.04 + box_url: http://cloud-images.ubuntu.com/vagrant/precise/current/precise-server-cloudimg-amd64-vagrant-disk1.box + require_chef_omnibus: 11.4.0 + run_list: + - recipe[apt] +- name: ubuntu-10.04 + driver_config: + box: opscode-ubuntu-10.04 + box_url: http://opscode-vm.s3.amazonaws.com/vagrant/opscode_ubuntu-10.04_chef-11.2.0.box + require_chef_omnibus: 11.4.0 + run_list: + - recipe[apt] +- name: centos-6.3 + driver_config: + box: opscode-centos-6.3 + box_url: http://opscode-vm.s3.amazonaws.com/vagrant/opscode_centos-6.3_chef-11.2.0.box + require_chef_omnibus: 11.4.0 + run_list: + - recipe[yum::epel] +- name: centos-5.8 + driver_config: + box: opscode-centos-5.8 + box_url: http://opscode-vm.s3.amazonaws.com/vagrant/opscode_centos-5.8_chef-11.2.0.box + require_chef_omnibus: 11.4.0 + run_list: + - recipe[yum::epel] +suites: +- name: client + run_list: + - recipe[mysql::client] + attributes: {} +- name: ruby + run_list: + - recipe[mysql::ruby] + attributes: {} +- name: server + run_list: + - recipe[minitest-handler] + - recipe[mysql_test::server] + attributes: {} diff --git a/chef/cookbooks/mysql/Berksfile b/chef/cookbooks/mysql/Berksfile new file mode 100644 index 0000000..4b0944b --- /dev/null +++ b/chef/cookbooks/mysql/Berksfile @@ -0,0 +1,11 @@ +site :opscode + +metadata + +group :integration do + cookbook "apt" + cookbook "yum" + + cookbook "mysql_test", :path => "../../../test/cookbooks/mysql_test" + cookbook "minitest-handler" +end diff --git a/chef/cookbooks/mysql/CHANGELOG.md b/chef/cookbooks/mysql/CHANGELOG.md new file mode 100644 index 0000000..ecbe671 --- /dev/null +++ b/chef/cookbooks/mysql/CHANGELOG.md @@ -0,0 +1,154 @@ +## v3.0.0: + +**Note** This is a backwards incompatible version with previous + versions of the cookbook. Tickets that introduce incompatibility are + COOK-2615 and COOK-2617. + +* [COOK-2478] - Duplicate 'read_only' server attribute in base and tunable +* [COOK-2471] - Add tunable to set slave_compressed_protocol for reduced network traffic +* [COOK-1059] - Update attributes in mysql cookbook to support missing options for my.cnf usable by Percona +* [COOK-2590] - Typo in server recipe to do with conf_dir and confd_dir +* [COOK-2602] - Add `lower_case_table_names` tunable +* [COOK-2430] - Add a tunable to create a network ACL when allowing `remote_root_access` +* [COOK-2619] - mysql: isamchk deprecated +* [COOK-2515] - Better support for SUSE distribution for mysql cookbook +* [COOK-2557] - mysql::percona_repo attributes missing and key server typo +* [COOK-2614] - Duplicate `innodb_file_per_table` +* [COOK-2145] - MySQL cookbook should remove anonymous and password less accounts +* [COOK-2553] - Enable include directory in my.cnf template for any platform +* [COOK-2615] - Rename `key_buffer` to `key_buffer_size` +* [COOK-2626] - Percona repo URL is being constructed incorrectly +* [COOK-2616] - Unneeded attribute thread_cache +* [COOK-2618] - myisam-recover not using attribute value +* [COOK-2617] - open-files is a duplicate of open-files-limit + +## v2.1.2: + +* [COOK-2172] - Mysql cookbook duplicates `binlog_format` + configuration + +## v2.1.0: + +* [COOK-1669] - Using platform("ubuntu") in default attributes always + returns true +* [COOK-1694] - Added additional my.cnf fields and reorganized + cookbook to avoid race conditions with mysql startup and sql script + execution +* [COOK-1851] - Support server-id and binlog_format settings +* [COOK-1929] - Update msyql server attributes file because setting + attributes without specifying a precedence is deprecated +* [COOK-1999] - Add read_only tunable useful for replication slave + servers + +## v2.0.2: + +* [COOK-1967] - mysql: trailing comma in server.rb platform family + +## v2.0.0: + +**Important note for this release** + +Under Chef Solo, you must set the node attributes for the root, debian +and repl passwords or the run will completely fail. See COOK-1737 for +background on this. + +* [COOK-1390] - MySQL service cannot start after reboot +* [COOK-1610] - Set root password outside preseed (blocker for drop-in mysql + replacements) +* [COOK-1624] - Mysql cookbook fails to even compile on windows +* [COOK-1669] - Using platform("ubuntu") in default attributes always returns true +* [COOK-1686] - Add mysql service start +* [COOK-1687] - duplicate `innodb_buffer_pool_size` attribute +* [COOK-1704] - mysql cookbook fails spec tests when minitest-handler cookbook enabled +* [COOK-1737] - Fail a chef-solo run when `server_root_password`, + `server_debian_password`, and/or `server_repl_password` is not set +* [COOK-1769] - link to database recipe in mysql README goes to old opscode/cookbooks + repo instead of opscode-cookbook organization +* [COOK-1963] - use `platform_family` + +## v1.3.0: + +**Important note for this release** + +This version no longer installs Ruby bindings in the client recipe by +default. Use the ruby recipe if you'd like the RubyGem. If you'd like +packages from your distribution, use them in your application's +specific cookbook/recipe, or modify the client packages attribute. +This resolves the following tickets: + +* COOK-932 +* COOK-1009 +* COOK-1384 + +Additionally, this cookbook now has tests (COOK-1439) for use under +test-kitchen. + +The following issues are also addressed in this release. + +* [COOK-1443] - MySQL (>= 5.1.24) does not support `innodb_flush_method` + = fdatasync +* [COOK-1175] - Add Mac OS X support +* [COOK-1289] - handle additional tunable attributes +* [COOK-1305] - add auto-increment-increment and auto-increment-offset + attributes +* [COOK-1397] - make the port an attribute +* [COOK-1439] - Add MySQL cookbook tests for test-kitchen support +* [COOK-1236] - Move package names into attributes to allow percona to + free-ride +* [COOK-934] - remove deprecated mysql/libraries/database.rb, use the + database cookbook instead. +* [COOK-1475] - fix restart on config change + +## v1.2.6: + +* [COOK-1113] - Use an attribute to determine if upstart is used +* [COOK-1121] - Add support for Windows +* [COOK-1140] - Fix conf.d on Debian +* [COOK-1151] - Fix server_ec2 handling /var/lib/mysql bind mount +* [COOK-1321] - Document setting password attributes for solo + +## v1.2.4 + +* [COOK-992] - fix FATAL nameerror +* [COOK-827] - `mysql:server_ec2` recipe can't mount `data_dir` +* [COOK-945] - FreeBSD support + +## v1.2.2 + +* [COOK-826] mysql::server recipe doesn't quote password string +* [COOK-834] Add 'scientific' and 'amazon' platforms to mysql cookbook + +## v1.2.1 + +* [COOK-644] Mysql client cookbook 'package missing' error message is confusing +* [COOK-645] RHEL6/CentOS6 - mysql cookbook contains 'skip-federated' directive which is unsupported on MySQL 5.1 + +## v1.2.0 + +* [COOK-684] remove mysql_database LWRP + +## v1.0.8: + +* [COOK-633] ensure "cloud" attribute is available + +## v1.0.7: + +* [COOK-614] expose all mysql tunable settings in config +* [COOK-617] bind to private IP if available + +## v1.0.6: + +* [COOK-605] install mysql-client package on ubuntu/debian + +## v1.0.5: + +* [COOK-465] allow optional remote root connections to mysql +* [COOK-455] improve platform version handling +* externalize conf_dir attribute for easier cross platform support +* change datadir attribute to data_dir for consistency + +## v1.0.4: + +* fix regressions on debian platform +* [COOK-578] wrap root password in quotes +* [COOK-562] expose all tunables in my.cnf diff --git a/chef/cookbooks/mysql/CONTRIBUTING b/chef/cookbooks/mysql/CONTRIBUTING new file mode 100644 index 0000000..89ac873 --- /dev/null +++ b/chef/cookbooks/mysql/CONTRIBUTING @@ -0,0 +1,29 @@ +If you would like to contribute, please open a ticket in JIRA: + +* http://tickets.opscode.com + +Create the ticket in the COOK project and use the cookbook name as the +component. + +For all code contributions, we ask that contributors sign a +contributor license agreement (CLA). Instructions may be found here: + +* http://wiki.opscode.com/display/chef/How+to+Contribute + +When contributing changes to individual cookbooks, please do not +modify the version number in the metadata.rb. Also please do not +update the CHANGELOG.md for a new version. Not all changes to a +cookbook may be merged and released in the same versions. Opscode will +handle the version updates during the release process. You are welcome +to correct typos or otherwise make updates to documentation in the +README. + +If a contribution adds new platforms or platform versions, indicate +such in the body of the commit message(s), and update the relevant +COOK ticket. When writing commit messages, it is helpful for others if +you indicate the COOK ticket. For example: + + git commit -m '[COOK-1041] Updated pool resource to correctly delete.' + +In the ticket itself, it is also helpful if you include log output of +a successful Chef run, but this is not absolutely required. diff --git a/chef/cookbooks/mysql/LICENSE b/chef/cookbooks/mysql/LICENSE new file mode 100644 index 0000000..11069ed --- /dev/null +++ b/chef/cookbooks/mysql/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/chef/cookbooks/mysql/README.md b/chef/cookbooks/mysql/README.md new file mode 100644 index 0000000..1a0856a --- /dev/null +++ b/chef/cookbooks/mysql/README.md @@ -0,0 +1,250 @@ +Description +=========== + +Installs and configures MySQL client or server. + +Requirements +============ + +Chef 0.10.10+. + +Platform +-------- + +* Debian, Ubuntu +* CentOS, Red Hat, Fedora +* Mac OS X (Using homebrew) + +Tested on: + +* Debian 5.0, 6.0 +* Ubuntu 10.04-12.04 +* CentOS 5.5-5.8, 6.2-6.3 +* Mac OS X 10.7.2 + +See TESTING.md for information about running tests in Opscode's Test +Kitchen. + +Cookbooks +--------- + +Requires Opscode's openssl cookbook for secure password generation. +See _Attributes_ and _Usage_ for more information. + +The RubyGem installation in the `mysql::ruby` recipe requires a C +compiler and Ruby development headers to be installed in order to +build the mysql gem. + +Requires `homebrew` +[cookbook](http://community.opscode.com/cookbooks/homebrew) on Mac OS +X. + +Resources and Providers +======================= + +The LWRP that used to ship as part of this cookbook has been +refactored into the +[database](http://community.opscode.com/cookbooks/database) +cookbook. Please see the README for details on updated usage. + +Attributes +========== + +See the `attributes/server.rb` or `attributes/client.rb` for default +values. Several attributes have values that vary based on the node's +platform and version. + +* `node['mysql']['client']['packages']` - An array of package names + that should be installed on "client" systems. This can be modified, + e.g., to specify packages for Percona. +* `node['mysql']['server']['packages']` - An array of package names + that should be installed on "server" systems. This can be modified, + e.g., to specify packages for Percona. + +* `node['mysql']['auto-increment-increment']` - + auto-increment-increment value in my.cnf +* `node['mysql']['auto-increment-offset]` - auto-increment-offset + value in my.cnf +* `node['mysql']['basedir']` - Base directory where MySQL is installed +* `node['mysql']['bind_address']` - Listen address for MySQLd +* `node['mysql']['conf_dir']` - Location for mysql conf directory +* `node['mysql']['confd_dir']` - Location for mysql conf.d style + include directory +* `node['mysql']['data_dir']` - Location for mysql data directory +* `node['mysql']['ec2_path']` - location of mysql data_dir on EC2 + nodes +* `node['mysql']['grants_path']` - Path where the grants.sql should be + written +* `node['mysql']['mysqladmin_bin']` - Path to the mysqladmin binary +* `node['mysql']['old_passwords']` - Sets the `old_passwords` value in + my.cnf. +* `node['mysql']['pid_file']` - Path to the mysqld.pid file +* `node['mysql']['port']` - Liten port for MySQLd +* `node['mysql']['reload_action']` - Action to take when mysql conf + files are modified. Also allows "reload" and "none". +* `node['mysql']['root_group']` - The default group of the "root" user +* `node['mysql']['service_name']` - The name of the mysqld service +* `node['mysql']['socket']` - Path to the mysqld.sock file +* `node['mysql']['use_upstart']` - Whether to use upstart for the + service provider +* `mysql['root_network_acl']` - Set define the network the root user will be able to login from, default is nil + +Performance and other "tunable" attributes are under the +`node['mysql']['tunable']` attribute, corresponding to the same-named +parameter in my.cnf, and the default values are used. See +`attributes/server.rb`. + +By default, a MySQL installation has an anonymous user, allowing anyone +to log into MySQL without having to have a user account created for +them. This is intended only for testing, and to make the installation +go a bit smoother. You should remove them before moving into a +production environment. + +* `node['mysql']['remove_anonymous_users']` - Remove anonymous users + +Normally, root should only be allowed to connect from 'localhost'. This +ensures that someone cannot guess at the root password from the network. + +* `node['mysql']['allow_remote_root']` - If true Sets root access from '%'. If false deletes any non-localhost root users. + +By default, MySQL comes with a database named 'test' that anyone can +access. This is also intended only for testing, and should be removed +before moving into a production environment. This will also drop any user privileges to the test databae and any DB named test_% . + +* `node['mysql']['remove_test_database']` - Delete the test database and access to it. + +The following attributes are randomly generated passwords handled in +the `mysql::server` recipe, using the OpenSSL cookbook's +`secure_password` helper method. These are set using the `set_unless` +node attribute method, which allows them to be easily overridden e.g. +in a role. + +* `node['mysql']['server_root_password']` - Set the server's root + password +* `node['mysql']['server_repl_password']` - Set the replication user + 'repl' password +* `node['mysql']['server_debian_password']` - Set the debian-sys-maint + user password + +## Windows Specific + +The following attributes are specific to Windows platforms. + +* `node['mysql']['client']['version']` - The version of MySQL + connector to install. +* `node['mysql']['client']['arch']` - Force 32 bit to work with the + mysql gem +* `node['mysql']['client']['package_file']` - The MSI file for the + mysql connector. +* `node['mysql']['client']['url']` - URL to download the mysql + connector. +* `node['mysql']['client']['packages']` - Similar to other platforms, + this is the name of the client package. +* `node['mysql']['client']['basedir']` - Base installation location +* `node['mysql']['client']['lib_dir']` - Libraries under the base location +* `node['mysql']['client']['bin_dir']` - binary directory under base location +* `node['mysql']['client']['ruby_dir']` - location where the Ruby + binaries will be + +Usage +===== + +On client nodes, use the client (or default) recipe: + + { "run_list": ["recipe[mysql::client]"] } + +This will install the MySQL client libraries and development headers +on the system. + +On nodes which may use the `database` cookbook's mysql resources, also +use the ruby recipe. This installs the mysql RubyGem in the Ruby +environment Chef is using via `chef_gem`. + + { "run_list": ["recipe[mysql::client]", "recipe[mysql::ruby]"] } + +If you need to install the mysql Ruby library as a package for your +system, override the client packages attribute in your node or role. +For example, on an Ubuntu system: + + { + "mysql": { + "client": { + "packages": ["mysql-client", "libmysqlclient-dev","ruby-mysql"] + } + } + } + +This creates a resource object for the package and does the +installation before other recipes are parsed. You'll need to have the +C compiler and such (ie, build-essential on Ubuntu) before running the +recipes, but we already do that when installing Chef :-). + +On server nodes, use the server recipe: + + { "run_list": ["recipe[mysql::server]"] } + +On Debian and Ubuntu, this will preseed the mysql-server package with +the randomly generated root password in the recipe file. On other +platforms, it simply installs the required packages. It will also +create an SQL file, `/etc/mysql/grants.sql`, that will be used to set up +grants for the root, repl and debian-sys-maint users. + +The recipe will perform a `node.save` unless it is run under +`chef-solo` after the password attributes are used to ensure that in +the event of a failed run, the saved attributes would be used. + +On EC2 nodes, use the `server_ec2` recipe and the mysql data dir will +be set up in the ephmeral storage. + + { "run_list": ["recipe[mysql::server_ec2]"] } + +When the `ec2_path` doesn't exist we look for a mounted filesystem +(eg, EBS) and move the data_dir there. + +The client recipe is already included by server and 'default' recipes. + +For more infromation on the compile vs execution phase of a Chef run: + +* http://wiki.opscode.com/display/chef/Anatomy+of+a+Chef+Run + +Chef Solo Note +============== + +These node attributes are stored on the Chef +server when using `chef-client`. Because `chef-solo` does not +connect to a server or save the node object at all, to have the same +passwords persist across `chef-solo` runs, you must specify them in +the `json_attribs` file used. For example: + + { + "mysql": { + "server_root_password": "iloverandompasswordsbutthiswilldo", + "server_repl_password": "iloverandompasswordsbutthiswilldo", + "server_debian_password": "iloverandompasswordsbutthiswilldo" + }, + "run_list":["recipe[mysql::server]"] + } + +License and Author +================== + +- Author:: Joshua Timberman () +- Author:: AJ Christensen () +- Author:: Seth Chisamore () +- Author:: Brian Bianco () +- Author:: Jesse Howarth () +- Author:: Andrew Crump () + +Copyright:: 2009-2013 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/chef/cookbooks/mysql/TESTING.md b/chef/cookbooks/mysql/TESTING.md new file mode 100644 index 0000000..e29ff7c --- /dev/null +++ b/chef/cookbooks/mysql/TESTING.md @@ -0,0 +1,25 @@ +This cookbook includes support for running tests via Test Kitchen (1.0). This has some requirements. + +1. You must be using the Git repository, rather than the downloaded cookbook from the Chef Community Site. +2. You must have Vagrant 1.1 installed. +3. You must have a "sane" Ruby 1.9.3 environment. + +Once the above requirements are met, install the additional requirements: + +Install the berkshelf plugin for vagrant, and berkshelf to your local Ruby environment. + + vagrant plugin install vagrant-berkshelf + gem install berkshelf + +Install Test Kitchen 1.0 (unreleased yet, use the alpha / prerelease version). + + gem install test-kitchen --pre + +Install the Vagrant driver for Test Kitchen. + + gem install kitchen-vagrant + +Once the above are installed, you should be able to run Test Kitchen: + + kitchen list + kitchen test diff --git a/chef/cookbooks/mysql/attributes/client.rb b/chef/cookbooks/mysql/attributes/client.rb new file mode 100644 index 0000000..fcaa1da --- /dev/null +++ b/chef/cookbooks/mysql/attributes/client.rb @@ -0,0 +1,52 @@ +# +# Cookbook Name:: mysql +# Attributes:: client +# +# 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 Opscode helper in Node class to get access +# to debian_before_squeeze? and ubuntu_before_lucid? +::Chef::Node.send(:include, Opscode::Mysql::Helpers) + +case node['platform_family'] +when "rhel", "fedora" + default['mysql']['client']['packages'] = %w{mysql mysql-devel} +when "suse" + default['mysql']['client']['packages'] = %w{mysql-community-server-client libmysqlclient-devel} +when "debian" + if debian_before_squeeze? || ubuntu_before_lucid? + default['mysql']['client']['packages'] = %w{mysql-client libmysqlclient15-dev} + else + default['mysql']['client']['packages'] = %w{mysql-client libmysqlclient-dev} + end +when "freebsd" + default['mysql']['client']['packages'] = %w{mysql55-client} +when "windows" + default['mysql']['client']['version'] = "6.0.2" + default['mysql']['client']['arch'] = "win32" # force 32 bit to work with mysql gem + default['mysql']['client']['package_file'] = "mysql-connector-c-#{mysql['client']['version']}-#{mysql['client']['arch']}.msi" + default['mysql']['client']['url'] = "http://www.mysql.com/get/Downloads/Connector-C/#{mysql['client']['package_file']}/from/http://mysql.mirrors.pair.com/" + default['mysql']['client']['packages'] = ["MySQL Connector C #{mysql['client']['version']}"] + + default['mysql']['client']['basedir'] = "#{ENV['SYSTEMDRIVE']}\\Program Files (x86)\\MySQL\\#{mysql['client']['packages'].first}" + default['mysql']['client']['lib_dir'] = "#{mysql['client']['basedir']}\\lib/opt" + default['mysql']['client']['bin_dir'] = "#{mysql['client']['basedir']}\\bin" + default['mysql']['client']['ruby_dir'] = RbConfig::CONFIG['bindir'] +when "mac_os_x" + default['mysql']['client']['packages'] = %w{mysql-connector-c} +else + default['mysql']['client']['packages'] = %w{mysql-client libmysqlclient-dev} +end + diff --git a/chef/cookbooks/mysql/attributes/percona_repo.rb b/chef/cookbooks/mysql/attributes/percona_repo.rb new file mode 100644 index 0000000..80650a6 --- /dev/null +++ b/chef/cookbooks/mysql/attributes/percona_repo.rb @@ -0,0 +1,3 @@ +default['mysql']['percona']['apt_key_id'] = 'CD2EFD2A' +default['mysql']['percona']['apt_uri'] = "http://repo.percona.com/apt" +default['mysql']['percona']['apt_keyserver'] = "keys.gnupg.net" diff --git a/chef/cookbooks/mysql/attributes/server.rb b/chef/cookbooks/mysql/attributes/server.rb new file mode 100644 index 0000000..630460a --- /dev/null +++ b/chef/cookbooks/mysql/attributes/server.rb @@ -0,0 +1,255 @@ +# +# Cookbook Name:: mysql +# Attributes:: server +# +# 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. +# + +default['mysql']['bind_address'] = attribute?('cloud') ? cloud['local_ipv4'] : ipaddress +default['mysql']['port'] = 3306 +default['mysql']['nice'] = 0 + +case node["platform_family"] +when "debian" + default['mysql']['server']['packages'] = %w{mysql-server} + default['mysql']['service_name'] = "mysql" + default['mysql']['basedir'] = "/usr" + default['mysql']['data_dir'] = "/var/lib/mysql" + default['mysql']['root_group'] = "root" + default['mysql']['mysqladmin_bin'] = "/usr/bin/mysqladmin" + default['mysql']['mysql_bin'] = "/usr/bin/mysql" + + default['mysql']['conf_dir'] = '/etc/mysql' + default['mysql']['confd_dir'] = '/etc/mysql/conf.d' + default['mysql']['socket'] = "/var/run/mysqld/mysqld.sock" + default['mysql']['pid_file'] = "/var/run/mysqld/mysqld.pid" + default['mysql']['old_passwords'] = 0 + default['mysql']['grants_path'] = "/etc/mysql/grants.sql" +when "rhel", "fedora" + if node["mysql"]["version"].to_f >= 5.5 + default['mysql']['service_name'] = "mysql" + default['mysql']['pid_file'] = "/var/run/mysql/mysql.pid" + else + default['mysql']['service_name'] = "mysqld" + default['mysql']['pid_file'] = "/var/run/mysqld/mysqld.pid" + end + default['mysql']['server']['packages'] = %w{mysql-server} + default['mysql']['basedir'] = "/usr" + default['mysql']['data_dir'] = "/var/lib/mysql" + default['mysql']['root_group'] = "root" + default['mysql']['mysqladmin_bin'] = "/usr/bin/mysqladmin" + default['mysql']['mysql_bin'] = "/usr/bin/mysql" + + default['mysql']['conf_dir'] = '/etc' + default['mysql']['confd_dir'] = '/etc/mysql/conf.d' + default['mysql']['socket'] = "/var/lib/mysql/mysql.sock" + default['mysql']['old_passwords'] = 1 + default['mysql']['grants_path'] = "/etc/mysql_grants.sql" + # RHEL/CentOS mysql package does not support this option. + default['mysql']['tunable']['innodb_adaptive_flushing'] = false +when "suse" + default['mysql']['service_name'] = "mysql" + default['mysql']['server']['packages'] = %w{mysql-community-server} + default['mysql']['basedir'] = "/usr" + default['mysql']['data_dir'] = "/var/lib/mysql" + default['mysql']['root_group'] = "root" + default['mysql']['mysqladmin_bin'] = "/usr/bin/mysqladmin" + default['mysql']['mysql_bin'] = "/usr/bin/mysql" + default['mysql']['conf_dir'] = '/etc' + default['mysql']['confd_dir'] = '/etc/mysql/conf.d' + default['mysql']['socket'] = "/var/run/mysql/mysql.sock" + default['mysql']['pid_file'] = "/var/run/mysql/mysqld.pid" + default['mysql']['old_passwords'] = 1 + default['mysql']['grants_path'] = "/etc/mysql_grants.sql" +when "freebsd" + default['mysql']['server']['packages'] = %w{mysql55-server} + default['mysql']['service_name'] = "mysql-server" + default['mysql']['basedir'] = "/usr/local" + default['mysql']['data_dir'] = "/var/db/mysql" + default['mysql']['root_group'] = "wheel" + default['mysql']['mysqladmin_bin'] = "/usr/local/bin/mysqladmin" + default['mysql']['mysql_bin'] = "/usr/local/bin/mysql" + + default['mysql']['conf_dir'] = '/usr/local/etc' + default['mysql']['confd_dir'] = '/usr/local/etc/mysql/conf.d' + default['mysql']['socket'] = "/tmp/mysqld.sock" + default['mysql']['pid_file'] = "/var/run/mysqld/mysqld.pid" + default['mysql']['old_passwords'] = 0 + default['mysql']['grants_path'] = "/var/db/mysql/grants.sql" +when "windows" + default['mysql']['server']['packages'] = ["MySQL Server 5.5"] + default['mysql']['version'] = '5.5.21' + default['mysql']['arch'] = 'win32' + default['mysql']['package_file'] = "mysql-#{mysql['version']}-#{mysql['arch']}.msi" + default['mysql']['url'] = "http://www.mysql.com/get/Downloads/MySQL-5.5/#{mysql['package_file']}/from/http://mysql.mirrors.pair.com/" + + default['mysql']['service_name'] = "mysql" + default['mysql']['basedir'] = "#{ENV['SYSTEMDRIVE']}\\Program Files (x86)\\MySQL\\#{mysql['server']['packages'].first}" + default['mysql']['data_dir'] = "#{node['mysql']['basedir']}\\Data" + default['mysql']['bin_dir'] = "#{node['mysql']['basedir']}\\bin" + default['mysql']['mysqladmin_bin'] = "#{node['mysql']['bin_dir']}\\mysqladmin" + default['mysql']['mysql_bin'] = "#{node['mysql']['bin_dir']}\\mysql" + + default['mysql']['conf_dir'] = node['mysql']['basedir'] + default['mysql']['old_passwords'] = 0 + default['mysql']['grants_path'] = "#{node['mysql']['conf_dir']}\\grants.sql" +when "mac_os_x" + default['mysql']['server']['packages'] = %w{mysql} + default['mysql']['basedir'] = "/usr/local/Cellar" + default['mysql']['data_dir'] = "/usr/local/var/mysql" + default['mysql']['root_group'] = "admin" + default['mysql']['mysqladmin_bin'] = "/usr/local/bin/mysqladmin" + default['mysql']['mysql_bin'] = "/usr/local/bin/mysql" +else + default['mysql']['server']['packages'] = %w{mysql-server} + default['mysql']['service_name'] = "mysql" + default['mysql']['basedir'] = "/usr" + default['mysql']['data_dir'] = "/var/lib/mysql" + default['mysql']['root_group'] = "root" + default['mysql']['mysqladmin_bin'] = "/usr/bin/mysqladmin" + default['mysql']['mysql_bin'] = "/usr/bin/mysql" + + default['mysql']['conf_dir'] = '/etc/mysql' + default['mysql']['confd_dir'] = '/etc/mysql/conf.d' + default['mysql']['socket'] = "/var/run/mysqld/mysqld.sock" + default['mysql']['pid_file'] = "/var/run/mysqld/mysqld.pid" + default['mysql']['old_passwords'] = 0 + default['mysql']['grants_path'] = "/etc/mysql/grants.sql" +end + +if attribute?('ec2') + default['mysql']['ec2_path'] = "/mnt/mysql" + default['mysql']['ebs_vol_dev'] = "/dev/sdi" + default['mysql']['ebs_vol_size'] = 50 +end + +default['mysql']['reload_action'] = "restart" # or "reload" or "none" + +default['mysql']['use_upstart'] = node['platform'] == "ubuntu" && node['platform_version'].to_f >= 10.04 + +default['mysql']['auto-increment-increment'] = 1 +default['mysql']['auto-increment-offset'] = 1 + +default['mysql']['allow_remote_root'] = false +default['mysql']['remove_anonymous_users'] = false +default['mysql']['remove_test_database'] = false +default['mysql']['root_network_acl'] = nil +default['mysql']['tunable']['character-set-server'] = "utf8" +default['mysql']['tunable']['collation-server'] = "utf8_general_ci" +default['mysql']['tunable']['lower_case_table_names'] = nil +default['mysql']['tunable']['back_log'] = "128" +default['mysql']['tunable']['key_buffer_size'] = "256M" +default['mysql']['tunable']['myisam_sort_buffer_size'] = "8M" +default['mysql']['tunable']['myisam_max_sort_file_size'] = "2147483648" +default['mysql']['tunable']['myisam_repair_threads'] = "1" +default['mysql']['tunable']['myisam-recover'] = "BACKUP" +default['mysql']['tunable']['max_allowed_packet'] = "16M" +default['mysql']['tunable']['max_connections'] = "800" +default['mysql']['tunable']['max_connect_errors'] = "10" +default['mysql']['tunable']['concurrent_insert'] = "2" +default['mysql']['tunable']['connect_timeout'] = "10" +default['mysql']['tunable']['tmp_table_size'] = "32M" +default['mysql']['tunable']['max_heap_table_size'] = node['mysql']['tunable']['tmp_table_size'] +default['mysql']['tunable']['bulk_insert_buffer_size'] = node['mysql']['tunable']['tmp_table_size'] +default['mysql']['tunable']['net_read_timeout'] = "30" +default['mysql']['tunable']['net_write_timeout'] = "30" +default['mysql']['tunable']['table_cache'] = "128" + +default['mysql']['tunable']['thread_cache_size'] = 8 +default['mysql']['tunable']['thread_concurrency'] = 10 +default['mysql']['tunable']['thread_stack'] = "256K" +default['mysql']['tunable']['sort_buffer_size'] = "2M" +default['mysql']['tunable']['read_buffer_size'] = "128k" +default['mysql']['tunable']['read_rnd_buffer_size'] = "256k" +default['mysql']['tunable']['join_buffer_size'] = "128k" +default['mysql']['tunable']['wait_timeout'] = "180" +default['mysql']['tunable']['open-files-limit'] = "1024" + +default['mysql']['tunable']['sql_mode'] = nil + +default['mysql']['tunable']['skip-character-set-client-handshake'] = false +default['mysql']['tunable']['skip-name-resolve'] = false + +default['mysql']['tunable']['slave_compressed_protocol'] = 0 + +default['mysql']['tunable']['server_id'] = nil +default['mysql']['tunable']['log_bin'] = nil +default['mysql']['tunable']['log_bin_trust_function_creators'] = false + +default['mysql']['tunable']['relay_log'] = nil +default['mysql']['tunable']['relay_log_index'] = nil +default['mysql']['tunable']['log_slave_updates'] = false + +default['mysql']['tunable']['sync_binlog'] = 0 +default['mysql']['tunable']['skip_slave_start'] = false +default['mysql']['tunable']['read_only'] = false + +default['mysql']['tunable']['log_error'] = nil +default['mysql']['tunable']['log_warnings'] = false +default['mysql']['tunable']['log_queries_not_using_index'] = true +default['mysql']['tunable']['log_bin_trust_function_creators'] = false + +default['mysql']['tunable']['innodb_log_file_size'] = "5M" +default['mysql']['tunable']['innodb_buffer_pool_size'] = "128M" +default['mysql']['tunable']['innodb_buffer_pool_instances'] = "4" +default['mysql']['tunable']['innodb_additional_mem_pool_size'] = "8M" +default['mysql']['tunable']['innodb_data_file_path'] = "ibdata1:10M:autoextend" +default['mysql']['tunable']['innodb_flush_method'] = false +default['mysql']['tunable']['innodb_log_buffer_size'] = "8M" +default['mysql']['tunable']['innodb_write_io_threads'] = "4" +default['mysql']['tunable']['innodb_io_capacity'] = "200" +default['mysql']['tunable']['innodb_file_per_table'] = true +default['mysql']['tunable']['innodb_lock_wait_timeout'] = "60" +if node['cpu'].nil? or node['cpu']['total'].nil? + default['mysql']['tunable']['innodb_thread_concurrency'] = "8" + default['mysql']['tunable']['innodb_commit_concurrency'] = "8" + default['mysql']['tunable']['innodb_read_io_threads'] = "8" + default['mysql']['tunable']['innodb_flush_log_at_trx_commit'] = "8" +else + default['mysql']['tunable']['innodb_thread_concurrency'] = "#{(Integer(node['cpu']['total'])) * 2}" + default['mysql']['tunable']['innodb_commit_concurrency'] = "#{(Integer(node['cpu']['total'])) * 2}" + default['mysql']['tunable']['innodb_read_io_threads'] = "#{(Integer(node['cpu']['total'])) * 2}" + default['mysql']['tunable']['innodb_flush_log_at_trx_commit'] = "#{(Integer(node['cpu']['total'])) * 2}" +end +default['mysql']['tunable']['innodb_support_xa'] = true +default['mysql']['tunable']['innodb_table_locks'] = true +default['mysql']['tunable']['skip-innodb-doublewrite'] = false + +default['mysql']['tunable']['transaction-isolation'] = nil + +default['mysql']['tunable']['query_cache_limit'] = "1M" +default['mysql']['tunable']['query_cache_size'] = "16M" + +default['mysql']['tunable']['log_slow_queries'] = "/var/log/mysql/slow.log" +default['mysql']['tunable']['slow_query_log'] = node['mysql']['tunable']['log_slow_queries'] # log_slow_queries is deprecated + # in favor of slow_query_log +default['mysql']['tunable']['long_query_time'] = 2 + +default['mysql']['tunable']['expire_logs_days'] = 10 +default['mysql']['tunable']['max_binlog_size'] = "100M" +default['mysql']['tunable']['binlog_cache_size'] = "32K" + +default['mysql']['tmpdir'] = ["/tmp"] + +default['mysql']['log_dir'] = node['mysql']['data_dir'] +default['mysql']['log_files_in_group'] = false +default['mysql']['innodb_status_file'] = false + +unless node['platform_family'] == "rhel" && node['platform_version'].to_i < 6 + # older RHEL platforms don't support these options + default['mysql']['tunable']['event_scheduler'] = 0 + default['mysql']['tunable']['table_open_cache'] = "128" + default['mysql']['tunable']['binlog_format'] = "statement" if node['mysql']['tunable']['log_bin'] +end diff --git a/chef/cookbooks/mysql/libraries/helpers.rb b/chef/cookbooks/mysql/libraries/helpers.rb new file mode 100644 index 0000000..40adcfc --- /dev/null +++ b/chef/cookbooks/mysql/libraries/helpers.rb @@ -0,0 +1,33 @@ +# +# Author:: Seth Chisamore () +# Copyright:: Copyright (c) 2011 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# 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. +# + +module Opscode + module Mysql + module Helpers + + def debian_before_squeeze? + (node['platform'] == "debian") && (node['platform_version'].to_f < 6.0) + end + + def ubuntu_before_lucid? + (node['platform'] == "ubuntu") && (node['platform_version'].to_f < 10.0) + end + + end + end +end diff --git a/chef/cookbooks/mysql/metadata.rb b/chef/cookbooks/mysql/metadata.rb new file mode 100644 index 0000000..28bb17e --- /dev/null +++ b/chef/cookbooks/mysql/metadata.rb @@ -0,0 +1,140 @@ +name "mysql" +maintainer "Opscode, Inc." +maintainer_email "cookbooks@opscode.com" +license "Apache 2.0" +description "Installs and configures mysql for client or server" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) +version "3.0.1" +recipe "mysql", "Includes the client recipe to configure a client" +recipe "mysql::client", "Installs packages required for mysql clients using run_action magic" +recipe "mysql::server", "Installs packages required for mysql servers w/o manual intervention" +recipe "mysql::server_ec2", "Performs EC2-specific mountpoint manipulation" + +%w{ debian ubuntu centos suse fedora redhat scientific amazon freebsd windows mac_os_x }.each do |os| + supports os +end + +depends "openssl" +depends "build-essential", "> 1.1.0" +suggests "homebrew" +suggests "windows" + +attribute "mysql/server_root_password", + :display_name => "MySQL Server Root Password", + :description => "Randomly generated password for the mysqld root user", + :default => "randomly generated" + +attribute "mysql/bind_address", + :display_name => "MySQL Bind Address", + :description => "Address that mysqld should listen on", + :default => "ipaddress" + +attribute "mysql/data_dir", + :display_name => "MySQL Data Directory", + :description => "Location of mysql databases", + :default => "/var/lib/mysql" + +attribute "mysql/conf_dir", + :display_name => "MySQL Conf Directory", + :description => "Location of mysql conf files", + :default => "/etc/mysql" + +attribute "mysql/ec2_path", + :display_name => "MySQL EC2 Path", + :description => "Location of mysql directory on EC2 instance EBS volumes", + :default => "/mnt/mysql" + +attribute "mysql/reload_action", + :display_name => "MySQL conf file reload action", + :description => "Action to take when mysql conf files are modified", + :default => "reload" + +attribute "mysql/tunable", + :display_name => "MySQL Tunables", + :description => "Hash of MySQL tunable attributes", + :type => "hash" + +attribute "mysql/tunable/key_buffer", + :display_name => "MySQL Tuntable Key Buffer", + :default => "250M" + +attribute "mysql/tunable/max_connections", + :display_name => "MySQL Tunable Max Connections", + :default => "800" + +attribute "mysql/tunable/wait_timeout", + :display_name => "MySQL Tunable Wait Timeout", + :default => "180" + +attribute "mysql/tunable/net_read_timeout", + :display_name => "MySQL Tunable Net Read Timeout", + :default => "30" + +attribute "mysql/tunable/net_write_timeout", + :display_name => "MySQL Tunable Net Write Timeout", + :default => "30" + +attribute "mysql/tunable/back_log", + :display_name => "MySQL Tunable Back Log", + :default => "128" + +attribute "mysql/tunable/table_cache", + :display_name => "MySQL Tunable Table Cache for MySQL < 5.1.3", + :default => "128" + +attribute "mysql/tunable/table_open_cache", + :display_name => "MySQL Tunable Table Cache for MySQL >= 5.1.3", + :default => "128" + +attribute "mysql/tunable/max_heap_table_size", + :display_name => "MySQL Tunable Max Heap Table Size", + :default => "32M" + +attribute "mysql/tunable/expire_logs_days", + :display_name => "MySQL Exipre Log Days", + :default => "10" + +attribute "mysql/tunable/max_binlog_size", + :display_name => "MySQL Max Binlog Size", + :default => "100M" + +attribute "mysql/client", + :display_name => "MySQL Connector/C Client", + :description => "Hash of MySQL client attributes", + :type => "hash" + +attribute "mysql/client/version", + :display_name => "MySQL Connector/C Version", + :default => "6.0.2" + +attribute "mysql/client/arch", + :display_name => "MySQL Connector/C Architecture", + :default => "win32" + +attribute "mysql/client/package_file", + :display_name => "MySQL Connector/C Package File Name", + :default => "mysql-connector-c-6.0.2-win32.msi" + +attribute "mysql/client/url", + :display_name => "MySQL Connector/C Download URL", + :default => "http://www.mysql.com/get/Downloads/Connector-C/mysql-connector-c-6.0.2-win32.msi/from/http://mysql.mirrors.pair.com/" + +attribute "mysql/client/package_name", + :display_name => "MySQL Connector/C Registry DisplayName", + :default => "MySQL Connector C 6.0.2" + +attribute "mysql/client/basedir", + :display_name => "MySQL Connector/C Base Install Directory", + :default => "C:\\Program Files (x86)\\MySQL\\Connector C 6.0.2" + +attribute "mysql/client/lib_dir", + :display_name => "MySQL Connector/C Library Directory (containing libmysql.dll)", + :default => "C:\\Program Files (x86)\\MySQL\\Connector C 6.0.2\\lib\\opt" + +attribute "mysql/client/bin_dir", + :display_name => "MySQL Connector/C Executable Directory", + :default => "C:\\Program Files (x86)\\MySQL\\Connector C 6.0.2\\bin" + +attribute "mysql/client/ruby_dir", + :display_name => "Ruby Executable Directory which should gain MySQL support", + :default => "system ruby" diff --git a/chef/cookbooks/mysql/recipes/client.rb b/chef/cookbooks/mysql/recipes/client.rb new file mode 100644 index 0000000..91787e7 --- /dev/null +++ b/chef/cookbooks/mysql/recipes/client.rb @@ -0,0 +1,59 @@ +# +# Cookbook Name:: mysql +# Recipe:: client +# +# Copyright 2008-2011, 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 Opscode helper in Recipe class to get access +# to debian_before_squeeze? and ubuntu_before_lucid? +::Chef::Recipe.send(:include, Opscode::Mysql::Helpers) + +case node['platform'] +when "windows" + package_file = node['mysql']['client']['package_file'] + remote_file "#{Chef::Config[:file_cache_path]}/#{package_file}" do + source node['mysql']['client']['url'] + not_if { File.exists? "#{Chef::Config[:file_cache_path]}/#{package_file}" } + end + + windows_package node['mysql']['client']['packages'].first do + source "#{Chef::Config[:file_cache_path]}/#{package_file}" + end + windows_path node['mysql']['client']['bin_dir'] do + action :add + end + def package(*args, &blk) + windows_package(*args, &blk) + end +when "mac_os_x" + include_recipe 'homebrew' +end + +node['mysql']['client']['packages'].each do |mysql_pack| + package mysql_pack do + action :install + end +end + +if platform? 'windows' + ruby_block "copy libmysql.dll into ruby path" do + block do + require 'fileutils' + FileUtils.cp "#{node['mysql']['client']['lib_dir']}\\libmysql.dll", node['mysql']['client']['ruby_dir'] + end + not_if { File.exist?("#{node['mysql']['client']['ruby_dir']}\\libmysql.dll") } + end +end diff --git a/chef/cookbooks/mysql/recipes/default.rb b/chef/cookbooks/mysql/recipes/default.rb new file mode 100644 index 0000000..9ff90d6 --- /dev/null +++ b/chef/cookbooks/mysql/recipes/default.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: mysql +# 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 "mysql::client" diff --git a/chef/cookbooks/mysql/recipes/percona_repo.rb b/chef/cookbooks/mysql/recipes/percona_repo.rb new file mode 100644 index 0000000..f629e79 --- /dev/null +++ b/chef/cookbooks/mysql/recipes/percona_repo.rb @@ -0,0 +1,48 @@ +# +# Cookbook Name:: mysql +# Recipe:: percona_repo +# +# 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" + include_recipe "apt" + apt_repository "percona" do + uri node['mysql']['percona']['apt_uri'] + distribution node['lsb']['codename'] + components [ "main" ] + keyserver node['mysql']['percona']['apt_keyserver'] + key node['mysql']['percona']['apt_key_id'] + action :add + end +when "centos", "amazon", "redhat" + include_recipe "yum" + yum_key "RPM-GPG-KEY-percona" do + url "http://www.percona.com/downloads/RPM-GPG-KEY-percona" + action :add + end + arch = node['kernel']['machine'] + arch = "i386" unless arch == "x86_64" + pversion = node['platform_version'].split('.').first + yum_repository "percona" do + repo_name "Percona" + description "Percona Repo" + url "http://repo.percona.com/centos/#{pversion}/os/#{arch}/" + key "RPM-GPG-KEY-percona" + action :add + end +end diff --git a/chef/cookbooks/mysql/recipes/ruby.rb b/chef/cookbooks/mysql/recipes/ruby.rb new file mode 100644 index 0000000..8c8470d --- /dev/null +++ b/chef/cookbooks/mysql/recipes/ruby.rb @@ -0,0 +1,31 @@ +# +# Cookbook Name:: mysql +# Recipe:: ruby +# +# Author:: Jesse Howarth () +# Author:: Jamie Winsor () +# +# Copyright 2008-2012, 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. +# + +node.set['build_essential']['compiletime'] = true +include_recipe "build-essential" +include_recipe "mysql::client" + +node['mysql']['client']['packages'].each do |mysql_pack| + resources("package[#{mysql_pack}]").run_action(:install) +end + +chef_gem "mysql" diff --git a/chef/cookbooks/mysql/recipes/server.rb b/chef/cookbooks/mysql/recipes/server.rb new file mode 100644 index 0000000..5a4b3fc --- /dev/null +++ b/chef/cookbooks/mysql/recipes/server.rb @@ -0,0 +1,221 @@ +# +# Cookbook Name:: mysql +# Recipe:: default +# +# Copyright 2008-2011, 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. +# + +::Chef::Recipe.send(:include, Opscode::OpenSSL::Password) + +include_recipe "mysql::client" + +if Chef::Config[:solo] + missing_attrs = %w{ + server_debian_password server_root_password server_repl_password + }.select do |attr| + node["mysql"][attr].nil? + end.map { |attr| "node['mysql']['#{attr}']" } + + if !missing_attrs.empty? + Chef::Application.fatal!([ + "You must set #{missing_attrs.join(', ')} in chef-solo mode.", + "For more information, see https://github.com/opscode-cookbooks/mysql#chef-solo-note" + ].join(' ')) + end +else + # generate all passwords + node.set_unless['mysql']['server_debian_password'] = secure_password + node.set_unless['mysql']['server_root_password'] = secure_password + node.set_unless['mysql']['server_repl_password'] = secure_password + node.save +end + +if platform_family?(%w{debian}) + + directory "/var/cache/local/preseeding" do + owner "root" + group node['mysql']['root_group'] + mode 0755 + recursive true + end + + execute "preseed mysql-server" do + command "debconf-set-selections /var/cache/local/preseeding/mysql-server.seed" + action :nothing + end + + template "/var/cache/local/preseeding/mysql-server.seed" do + source "mysql-server.seed.erb" + owner "root" + group node['mysql']['root_group'] + mode "0600" + notifies :run, "execute[preseed mysql-server]", :immediately + end + + template "#{node['mysql']['conf_dir']}/debian.cnf" do + source "debian.cnf.erb" + owner "root" + group node['mysql']['root_group'] + mode "0600" + end + +end + +if platform_family?('windows') + package_file = node['mysql']['package_file'] + + remote_file "#{Chef::Config[:file_cache_path]}/#{package_file}" do + source node['mysql']['url'] + not_if { File.exists? "#{Chef::Config[:file_cache_path]}/#{package_file}" } + end + + windows_package node['mysql']['server']['packages'].first do + source "#{Chef::Config[:file_cache_path]}/#{package_file}" + end + + def package(*args, &blk) + windows_package(*args, &blk) + end +end + +node['mysql']['server']['packages'].each do |package_name| + package package_name do + action :install + notifies :start, "service[mysql]", :immediately + end +end + +unless platform_family?(%w{mac_os_x}) + + [File.dirname(node['mysql']['pid_file']), + File.dirname(node['mysql']['tunable']['slow_query_log']), + node['mysql']['conf_dir'], + node['mysql']['confd_dir'], + node['mysql']['log_dir'], + node['mysql']['data_dir']].each do |directory_path| + directory directory_path do + owner "mysql" unless platform? 'windows' + group "mysql" unless platform? 'windows' + action :create + recursive true + end + end + + if platform_family? 'windows' + require 'win32/service' + + windows_path node['mysql']['bin_dir'] do + action :add + end + + windows_batch "install mysql service" do + command "\"#{node['mysql']['bin_dir']}\\mysqld.exe\" --install #{node['mysql']['service_name']}" + not_if { Win32::Service.exists?(node['mysql']['service_name']) } + end + end + + skip_federated = case node['platform'] + when 'fedora', 'ubuntu', 'amazon' + true + when 'centos', 'redhat', 'scientific' + node['platform_version'].to_f < 6.0 + else + false + end +end + +# Homebrew has its own way to do databases +if platform_family?(%w{mac_os_x}) + execute "mysql-install-db" do + command "mysql_install_db --verbose --user=`whoami` --basedir=\"$(brew --prefix mysql)\" --datadir=#{node['mysql']['data_dir']} --tmpdir=/tmp" + environment('TMPDIR' => nil) + action :run + creates "#{node['mysql']['data_dir']}/mysql" + end +else + execute 'mysql-install-db' do + command "mysql_install_db" + action :run + not_if { File.exists?(node['mysql']['data_dir'] + '/mysql/user.frm') } + end + + service "mysql" do + service_name node['mysql']['service_name'] + if node['mysql']['use_upstart'] + provider Chef::Provider::Service::Upstart + end + supports :status => true, :restart => true, :reload => true + action :enable + end +end + +# set the root password for situations that don't support pre-seeding. +# (eg. platforms other than debian/ubuntu & drop-in mysql replacements) +execute "assign-root-password" do + command "\"#{node['mysql']['mysqladmin_bin']}\" -u root password \"#{node['mysql']['server_root_password']}\"" + action :run + only_if "\"#{node['mysql']['mysql_bin']}\" -u root -e 'show databases;'" +end + +unless platform_family?(%w{mac_os_x}) + grants_path = node['mysql']['grants_path'] + + begin + t = resources("template[#{grants_path}]") + rescue + Chef::Log.info("Could not find previously defined grants.sql resource") + t = template grants_path do + source "grants.sql.erb" + owner "root" unless platform_family? 'windows' + group node['mysql']['root_group'] unless platform_family? 'windows' + mode "0600" + action :create + end + end + + if platform_family? 'windows' + windows_batch "mysql-install-privileges" do + command "\"#{node['mysql']['mysql_bin']}\" -u root #{node['mysql']['server_root_password'].empty? ? '' : '-p' }\"#{node['mysql']['server_root_password']}\" < \"#{grants_path}\"" + action :nothing + subscribes :run, resources("template[#{grants_path}]"), :immediately + end + else + execute "mysql-install-privileges" do + command %Q["#{node['mysql']['mysql_bin']}" -u root #{node['mysql']['server_root_password'].empty? ? '' : '-p' }"#{node['mysql']['server_root_password']}" < "#{grants_path}"] + action :nothing + subscribes :run, resources("template[#{grants_path}]"), :immediately + end + end + + template "#{node['mysql']['conf_dir']}/my.cnf" do + source "my.cnf.erb" + owner "root" unless platform? 'windows' + group node['mysql']['root_group'] unless platform? 'windows' + mode "0644" + case node['mysql']['reload_action'] + when 'restart' + notifies :restart, "service[mysql]", :immediately + when 'reload' + notifies :reload, "service[mysql]", :immediately + else + Chef::Log.info "my.cnf updated but mysql.reload_action is #{node['mysql']['reload_action']}. No action taken." + end + variables :skip_federated => skip_federated + end + + service "mysql" do + action :start + end +end diff --git a/chef/cookbooks/mysql/recipes/server_ec2.rb b/chef/cookbooks/mysql/recipes/server_ec2.rb new file mode 100644 index 0000000..6033ef4 --- /dev/null +++ b/chef/cookbooks/mysql/recipes/server_ec2.rb @@ -0,0 +1,51 @@ +# +# Cookbook Name:: mysql +# 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. +# + + +if (node.attribute?('ec2') && ! FileTest.directory?(node['mysql']['ec2_path'])) + + service "mysql" do + action :stop + end + + execute "install-mysql" do + command "mv #{node['mysql']['data_dir']} #{node['mysql']['ec2_path']}" + not_if do FileTest.directory?(node['mysql']['ec2_path']) end + end + + [node['mysql']['ec2_path'], node['mysql']['data_dir']].each do |dir| + directory dir do + owner "mysql" + group "mysql" + end + end + + mount node['mysql']['data_dir'] do + device node['mysql']['ec2_path'] + fstype "none" + options "bind,rw" + action [:mount, :enable] + end + + service "mysql" do + action :start + end + +end + diff --git a/chef/cookbooks/mysql/templates/default/debian.cnf.erb b/chef/cookbooks/mysql/templates/default/debian.cnf.erb new file mode 100644 index 0000000..989b125 --- /dev/null +++ b/chef/cookbooks/mysql/templates/default/debian.cnf.erb @@ -0,0 +1,12 @@ +[client] +host = localhost +user = debian-sys-maint +password = <%= node['mysql']['server_debian_password'] %> +socket = <%= node['mysql']['socket'] %> + +[mysql_upgrade] +host = localhost +user = debian-sys-maint +password = <%= node['mysql']['server_debian_password'] %> +socket = <%= node['mysql']['socket'] %> +basedir = /usr diff --git a/chef/cookbooks/mysql/templates/default/grants.sql.erb b/chef/cookbooks/mysql/templates/default/grants.sql.erb new file mode 100644 index 0000000..f697fe2 --- /dev/null +++ b/chef/cookbooks/mysql/templates/default/grants.sql.erb @@ -0,0 +1,34 @@ +# Generated by Chef for <%= node['hostname'] %>. +# Local modifications will be overwritten. + +<% case node['platform_family'] -%> +<% when "debian" -%> +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'debian-sys-maint'@'localhost' IDENTIFIED BY '<%= node['mysql']['server_debian_password'] %>' WITH GRANT OPTION; +<% end -%> +# Grant replication for a slave user. +GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%' identified by '<%= node['mysql']['server_repl_password'] %>'; + +# Set the server root password. This should be preseeded by the package installation. +<% if node['mysql']['allow_remote_root'] -%> +GRANT ALL ON *.* TO 'root'@'%' IDENTIFIED BY '<%= node['mysql']['server_root_password'] %>' WITH GRANT OPTION; +<% else %> +DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1'); +<% end -%> +UPDATE mysql.user SET Password=PASSWORD('<%= node['mysql']['server_root_password'] %>') WHERE User='root'; + +# Remove anonymous users +<% if node['mysql']['remove_anonymous_users'] -%> +DELETE FROM mysql.user WHERE User=''; +<% end -%> + +# Remove test database and access to it +<% if node['mysql']['remove_test_database'] -%> +DROP DATABASE test; +DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%'; +<% end -%> +SET PASSWORD FOR 'root'@'localhost' = PASSWORD('<%= node['mysql']['server_root_password'] %>'); + +# allow root to connect from a remote network if root_network_acl is not nil +<% if node['mysql']['root_network_acl'] -%> +SET PASSWORD FOR 'root'@'<%= node['mysql']['root_network_acl'] %>' = PASSWORD('<%= node['mysql']['server_root_password'] %>'); +<% end -%> diff --git a/chef/cookbooks/mysql/templates/default/my.cnf.erb b/chef/cookbooks/mysql/templates/default/my.cnf.erb new file mode 100644 index 0000000..1022976 --- /dev/null +++ b/chef/cookbooks/mysql/templates/default/my.cnf.erb @@ -0,0 +1,317 @@ +# +# Generated by Chef for <%= node['hostname'] %> +# +# Local modifications will be overwritten. +# +# The MySQL database server configuration file. +# +# You can copy this to one of: +# - "/etc/mysql/my.cnf" to set global options, +# - "~/.my.cnf" to set user-specific options. +# +# One can use all long options that the program supports. +# Run program with --help to get a list of available options and with +# --print-defaults to see which it would actually understand and use. +# +# For explanations see +# http://dev.mysql.com/doc/mysql/en/server-system-variables.html + +# This will be passed to all mysql clients +# It has been reported that passwords should be enclosed with ticks/quotes +# escpecially if they contain "#" chars... +# Remember to edit /etc/mysql/debian.cnf when changing the socket location. +[client] +port = <%= node['mysql']['port'] %> +socket = <%= node['mysql']['socket'] %> + +# Here is entries for some specific programs +# The following values assume you have at least 32M ram + +# This was formally known as [safe_mysqld]. Both versions are currently parsed. +[mysqld_safe] +socket = <%= node['mysql']['socket'] %> +nice = <%= node['mysql']['nice'] %> + +[mysqld] +# +# * Basic Settings +# + +# +# * IMPORTANT +# If you make changes to these settings and your system uses apparmor, you may +# also need to also adjust /etc/apparmor.d/usr.sbin.mysqld. +# + +user = mysql +pid-file = <%= node['mysql']['pid_file'] %> +socket = <%= node['mysql']['socket'] %> +port = <%= node['mysql']['port'] %> +basedir = <%= node['mysql']['basedir'] %> +datadir = <%= node['mysql']['data_dir'] %> +tmpdir = <%= node['mysql']['tmpdir'].join(':') %> +skip-external-locking +<%- if node['mysql']['tunable']['skip-name-resolve'] %> +skip-name-resolve +<%- end %> + +# Charset and Collation +character-set-server = <%= node['mysql']['tunable']['character-set-server'] %> +collation-server = <%= node['mysql']['tunable']['collation-server'] %> +<%- if node['mysql']['tunable']['lower_case_table_names'] %> +lower_case_table_names = <%= node['mysql']['tunable']['lower_case_table_names'] %> +<%- end %> +<%- if node['mysql']['tunable']['event_scheduler'] %> +event_scheduler = <%= node['mysql']['tunable']['event_scheduler'] %> +<%- end %> +<%- if node['mysql']['tunable']['skip-character-set-client-handshake'] %> +skip-character-set-client-handshake +<%- end %> +<%- if (node['mysql']['tunable']['lc_messages_dir'] && node['mysql']['tunable']['lc_messages']) %> +lc_messages_dir = <%= node['mysql']['lc_messages_dir'] %> +lc_messages = <%= node['mysql']['lc_messages'] %> +<%- elsif (node['mysql']['tunable']['languages']) %> +languages = <%= node['mysql']['tunable']['languages'] %> +<%- end %> + +# +# Instead of skip-networking the default is now to listen only on +# localhost which is more compatible and is not less secure. +bind-address = <%= node['mysql']['bind_address'] %> +# +# * Fine Tuning +# +key_buffer_size = <%= node['mysql']['tunable']['key_buffer_size'] %> +max_allowed_packet = <%= node['mysql']['tunable']['max_allowed_packet'] %> +thread_stack = <%= node['mysql']['tunable']['thread_stack'] %> +thread_cache_size = <%= node['mysql']['tunable']['thread_cache_size'] %> +sort_buffer_size = <%= node['mysql']['tunable']['sort_buffer_size'] %> +read_buffer_size = <%= node['mysql']['tunable']['read_buffer_size'] %> +read_rnd_buffer_size = <%= node['mysql']['tunable']['read_rnd_buffer_size'] %> +join_buffer_size = <%= node['mysql']['tunable']['join_buffer_size'] %> + +auto-increment-increment = <%= node['mysql']['auto-increment-increment'] %> +auto-increment-offset = <%= node['mysql']['auto-increment-offset'] %> + +# This replaces the startup script and checks MyISAM tables if needed +# the first time they are touched +myisam-recover = <%= node['mysql']['tunable']['myisam-recover'] %> +max_connections = <%= node['mysql']['tunable']['max_connections'] %> +max_connect_errors = <%= node['mysql']['tunable']['max_connect_errors'] %> +concurrent_insert = <%= node['mysql']['tunable']['concurrent_insert'] %> +connect_timeout = <%= node['mysql']['tunable']['connect_timeout'] %> +wait_timeout = <%= node['mysql']['tunable']['wait_timeout'] %> +net_read_timeout = <%= node['mysql']['tunable']['net_read_timeout'] %> +net_write_timeout = <%= node['mysql']['tunable']['net_write_timeout'] %> +back_log = <%= node['mysql']['tunable']['back_log'] %> +table_cache = <%= node['mysql']['tunable']['table_cache'] %> +<%- if node['mysql']['tunable']['table_open_cache'] %> +table_open_cache = <%= node['mysql']['tunable']['table_open_cache'] %> +<%- end %> +tmp_table_size = <%= node['mysql']['tunable']['tmp_table_size'] %> +max_heap_table_size = <%= node['mysql']['tunable']['max_heap_table_size'] %> +bulk_insert_buffer_size = <%= node['mysql']['tunable']['bulk_insert_buffer_size'] %> +open-files-limit = <%= node['mysql']['tunable']['open-files-limit'] %> + +# Default Table Settings +<%- if node['mysql']['tunable']['sql_mode'] %> +sql_mode = "<%= node['mysql']['tunable']['sql_mode'] %>" +<%- end %> + +# +# * Query Cache Configuration +# +query_cache_limit = <%= node['mysql']['tunable']['query_cache_limit'] %> +query_cache_size = <%= node['mysql']['tunable']['query_cache_size'] %> +# +# * Logging +# +# Both location gets rotated by the cronjob. +# Be aware that this log type is a performance killer. +#log = /var/log/mysql/mysql.log +# +# Error logging goes to syslog. This is a Debian improvement :) +<%- if node['mysql']['tunable']['log_error'] %> +log_error = <%= node['mysql']['tunable']['log_error'] %> +<%- end %> +<%- if node['mysql']['tunable']['log_warnings'] %> +log_warnings +<%- end %> +# +# * Replication +# + + +# +# Here you can see queries with especially long duration +<%- if node['mysql']['version'].to_f >= 5.5 %> +slow_query_log = <%= node['mysql']['tunable']['slow_query_log'] %> +<% else %> +log_slow_queries = <%= node['mysql']['tunable']['slow_query_log'] %> +<% end %> + +long_query_time = <%= node['mysql']['tunable']['long_query_time'] %> +<%- if node['mysql']['tunable']['log_queries_not_using_index'] and node['mysql']['slow_query_log'] %> +log-queries-not-using-indexes +<%- end %> +# +# The following can be used as easy to replay backup logs or for replication. +# note: if you are setting up a replication slave, see README.Debian about +# other settings you may need to change. +<%- if node['mysql']['tunable']['server_id'] %> +server-id = <%= node['mysql']['tunable']['server_id'] %> +<% end %> +<%- if node['mysql']['tunable']['log_bin'] %> +log_bin = <%= node['mysql']['tunable']['log_bin'] %> +<%- if node['mysql']['tunable']['log_bin'] %> +binlog_format = <%= node['mysql']['tunable']['binlog_format'] %> +<%- end %> +log_slave_updates = <%= node['mysql']['tunable']['log_slave_updates'] %> +<%- end %> +<%- if node['mysql']['tunable']['log_bin_trust_function_creators'] %> +log_bin_trust_function_creators +<%- end %> +expire_logs_days = <%= node['mysql']['tunable']['expire_logs_days'] %> +max_binlog_size = <%= node['mysql']['tunable']['max_binlog_size'] %> +binlog_cache_size = <%= node['mysql']['tunable']['binlog_cache_size'] %> +#binlog_do_db = include_database_name +#binlog_ignore_db = include_database_name +<%- if node['mysql']['tunable']['relay_log'] %> +relay_log = <%= node['mysql']['tunable']['relay_log'] %> +<%- end %> +<%- if node['mysql']['tunable']['relay_log_index'] %> +relay_log_index = <%= node['mysql']['tunable']['relay_log_index'] %> +<%- end %> + +sync_binlog = <%= node['mysql']['tunable']['sync_binlog'] %> +<%- if node['mysql']['tunable']['skip_slave_start'] %> +skip_slave_start +<%- end %> +<%- if node['mysql']['tunable']['read_only'] %> +read_only = 1 +<%- end %> + +<%- if node['mysql']['tunable']['transaction-isolation'] %> +transaction-isolation = <%= node['mysql']['tunable']['transaction-isolation'] %> +<%- end %> + +<%- if node['mysql']['tunable']['slave_compressed_protocol'] %> +slave_compressed_protocol = <%= node['mysql']['tunable']['slave_compressed_protocol'] %> +<%- end %> +# +# * InnoDB +# +# InnoDB is enabled by default with a 10MB datafile in /var/lib/mysql/. +# Read the manual for more InnoDB related options. There are many! +# You might want to disable InnoDB to shrink the mysqld process by circa 100MB. +#skip-innodb + +<%- if node["mysql"]["version"].to_f >= 5.5 %> +innodb_write_io_threads = <%= node['mysql']['tunable']['innodb_write_io_threads'] %> +innodb_io_capacity = <%= node['mysql']['tunable']['innodb_io_capacity'] %> +innodb_read_io_threads = <%= node['mysql']['tunable']['innodb_read_io_threads'] %> +innodb_buffer_pool_instances = <%= node['mysql']['tunable']['innodb_buffer_pool_instances'] %> +<%- end %> + +## InnoDB Plugin Independent Settings +innodb_data_home_dir = <%= node['mysql']['data_dir'] %> +innodb_log_group_home_dir = <%= node['mysql']['log_dir'] %> +<%- if node['mysql']['log_files_in_group'] %> +innodb_log_files_in_group = <%= node['mysql']['log_files_in_group'] %> +<%- end %> + +<%- if node['mysql']['innodb_status_file'] %> +innodb_status_file +<%- end %> +<%- if node['mysql']['tunable']['innodb_file_per_table'] %> +innodb_file_per_table +<%- end %> +innodb_table_locks = <%= node['mysql']['tunable']['innodb_table_locks'] %> +innodb_lock_wait_timeout = <%= node['mysql']['tunable']['innodb_lock_wait_timeout'] %> +innodb_thread_concurrency = <%= node['mysql']['tunable']['innodb_thread_concurrency'] %> +innodb_commit_concurrency = <%= node['mysql']['tunable']['innodb_commit_concurrency'] %> +innodb_support_xa = <%= node['mysql']['tunable']['innodb_support_xa'] %> +<%- if node['mysql']['tunable']['skip-innodb-doublewrite'] %> +skip-innodb-doublewrite +<%- end %> + +innodb_buffer_pool_size = <%= node['mysql']['tunable']['innodb_buffer_pool_size'] %> +innodb_log_file_size = <%= node['mysql']['tunable']['innodb_log_file_size'] %> +innodb_additional_mem_pool_size = <%= node['mysql']['tunable']['innodb_additional_mem_pool_size'] %> +innodb_data_file_path = <%= node['mysql']['tunable']['innodb_data_file_path'] %> +innodb_flush_log_at_trx_commit = <%= node['mysql']['tunable']['innodb_flush_log_at_trx_commit'] %> +<%- if node['mysql']['tunable']['innodb_flush_method'] %> +innodb_flush_method = <%= node['mysql']['tunable']['innodb_flush_method'] %> +<%- end %> +innodb_log_buffer_size = <%= node['mysql']['tunable']['innodb_log_buffer_size'] %> +<%- if node['mysql']['tunable']['innodb_adaptive_flushing'] %> +innodb_adaptive_flushing = <%= node['mysql']['tunable']['innodb_adaptive_flushing'] %> +<%- end %> + +<% if @skip_federated %> +# +# * Federated +# +# The FEDERATED storage engine is disabled since 5.0.67 by default in the .cnf files +# shipped with MySQL distributions (my-huge.cnf, my-medium.cnf, and so forth). +# +skip-federated +<% end %> +# +# * Security Features +# +# Read the manual, too, if you want chroot! +# chroot = /var/lib/mysql/ +# +# For generating SSL certificates I recommend the OpenSSL GUI "tinyca". +# +# ssl-ca=/etc/mysql/cacert.pem +# ssl-cert=/etc/mysql/server-cert.pem +# ssl-key=/etc/mysql/server-key.pem + +[mysqldump] +quick +quote-names +max_allowed_packet = <%= node['mysql']['tunable']['max_allowed_packet'] %> + +[mysql] +#no-auto-rehash # faster start of mysql but no tab completition + +[myisamchk] +key_buffer = <%= node['mysql']['tunable']['max_allowed_packet'] %> + +myisam_sort_buffer_size = <%= node['mysql']['tunable']['myisam_sort_buffer_size'] %> +myisam_max_sort_file_size = <%= node['mysql']['tunable']['myisam_max_sort_file_size'] %> +myisam_repair_threads = <%= node['mysql']['tunable']['myisam_repair_threads'] %> +myisam-recover = <%= node['mysql']['tunable']['myisam-recover'] %> + +# +# * NDB Cluster +# +# See /usr/share/doc/mysql-server-*/README.Debian for more information. +# +# The following configuration is read by the NDB Data Nodes (ndbd processes) +# not from the NDB Management Nodes (ndb_mgmd processes). +# +# [MYSQL_CLUSTER] +# ndb-connectstring=127.0.0.1 + +<% case node['platform_family'] -%> +<% when "rhel", "fedora", "suse" -%> +# +# * BerkeleyDB +# +# Using BerkeleyDB is now discouraged as its support will cease in 5.1.12. +skip-bdb +# Default to using old password format for compatibility with mysql 3.x +# clients (those using the mysqlclient10 compatibility package). +old_passwords = <%= node['mysql']['old_passwords'] %> +<% end -%> + +<% if node['mysql']['confd_dir'] -%> +# +# * IMPORTANT: Additional settings that can override those from this file! +# The files must end with '.cnf', otherwise they'll be ignored. +# +!includedir <%= node['mysql']['confd_dir'] %>/ +<% end -%> diff --git a/chef/cookbooks/mysql/templates/default/mysql-server.seed.erb b/chef/cookbooks/mysql/templates/default/mysql-server.seed.erb new file mode 100644 index 0000000..a5a74f0 --- /dev/null +++ b/chef/cookbooks/mysql/templates/default/mysql-server.seed.erb @@ -0,0 +1,10 @@ +mysql-server-5.0 mysql-server/root_password_again select <%= node['mysql']['server_root_password'] %> +mysql-server-5.0 mysql-server/root_password select <%= node['mysql']['server_root_password'] %> +mysql-server-5.0 mysql-server-5.0/really_downgrade boolean false +mysql-server-5.0 mysql-server-5.0/need_sarge_compat boolean false +mysql-server-5.0 mysql-server-5.0/start_on_boot boolean true +mysql-server-5.0 mysql-server/error_setting_password boolean false +mysql-server-5.0 mysql-server-5.0/nis_warning note +mysql-server-5.0 mysql-server-5.0/postrm_remove_databases boolean false +mysql-server-5.0 mysql-server/password_mismatch boolean false +mysql-server-5.0 mysql-server-5.0/need_sarge_compat_done boolean true diff --git a/chef/cookbooks/mysql/templates/default/port_mysql.erb b/chef/cookbooks/mysql/templates/default/port_mysql.erb new file mode 100644 index 0000000..55a2ffc --- /dev/null +++ b/chef/cookbooks/mysql/templates/default/port_mysql.erb @@ -0,0 +1,3 @@ +# MySQL +-A FWR -p tcp -m tcp --dport 3306 -j ACCEPT +-A FWR -p udp -m udp --dport 3306 -j ACCEPT \ No newline at end of file diff --git a/chef/cookbooks/mysql/templates/windows/my.cnf.erb b/chef/cookbooks/mysql/templates/windows/my.cnf.erb new file mode 100644 index 0000000..f0550c1 --- /dev/null +++ b/chef/cookbooks/mysql/templates/windows/my.cnf.erb @@ -0,0 +1,61 @@ +# +# Generated by Chef for <%= node['hostname'] %> +# +# Local modifications will be overwritten. +# +# The MySQL database server configuration file. +# +# One can use all long options that the program supports. +# Run program with --help to get a list of available options and with +# --print-defaults to see which it would actually understand and use. +# +# For explanations see +# http://dev.mysql.com/doc/mysql/en/server-system-variables.html + +# This will be passed to all mysql clients +# It has been reported that passwords should be enclosed with ticks/quotes +# escpecially if they contain "#" chars... +[client] +port = 3306 + +[mysql] +default-character-set = latin1 + +[mysqld] +# +# * Basic Settings +# +port = 3306 +basedir = <%= node['mysql']['basedir'] %> +datadir = <%= node['mysql']['data_dir'] %> +character-set-server = latin1 +default-storage-engine = INNODB +sql-mode = "STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION" + +# +# * Fine Tuning +# +thread_cache_size = <%= node['mysql']['tunable']['thread_cache_size'] %> +max_connections = <%= node['mysql']['tunable']['max_connections'] %> +table_cache = <%= node['mysql']['tunable']['table_cache'] %> +query_cache_size = <%= node['mysql']['tunable']['query_cache_size'] %> +tmp_table_size = 5M +myisam_max_sort_file_size = 100G +myisam_sort_buffer_size = 8M +key_buffer_size = 8M +read_buffer_size = 64K +read_rnd_buffer_size = 256K +sort_buffer_size = 212K + +# +# * InnoDB +# +# Read the manual for more InnoDB related options. There are many! +# You might want to disable InnoDB to shrink the mysqld process by circa 100MB. +# +innodb_additional_mem_pool_size = 2M +innodb_flush_log_at_trx_commit = 1 +innodb_log_buffer_size = 1M +innodb_buffer_pool_size = <%= node['mysql']['tunable']['innodb_buffer_pool_size'] %> +innodb_log_file_size = 10M +innodb_thread_concurrency = 8 diff --git a/chef/cookbooks/mysql/test/cookbooks/mysql_test/.gitignore b/chef/cookbooks/mysql/test/cookbooks/mysql_test/.gitignore new file mode 100644 index 0000000..2d19fc7 --- /dev/null +++ b/chef/cookbooks/mysql/test/cookbooks/mysql_test/.gitignore @@ -0,0 +1 @@ +*.html diff --git a/chef/cookbooks/mysql/test/cookbooks/mysql_test/README.md b/chef/cookbooks/mysql/test/cookbooks/mysql_test/README.md new file mode 100644 index 0000000..d710160 --- /dev/null +++ b/chef/cookbooks/mysql/test/cookbooks/mysql_test/README.md @@ -0,0 +1,63 @@ +Description +=========== + +This cookbook defines acceptance tests for MySQL. It includes: + +* A `features` sub-directory where the Cucumber features for the database + are defined. + +* Creation of a simple test database for the tests to run against. + +Usage +===== + +Set environment variable `TEST_SERVER_HOST` to specify the MySQL server to +connect to. You can optionally set `TEST_CLIENT_HOST` which will test a client +install by running the same features from a remote client. + +Requirements +============ + +## Cookbooks: + +This cookbook depends on the `mysql` cookbook. It also uses the `database` +cookbook to create the test database and relies on the `yum` cookbook in order +to add the EPEL repository on RHEL-derived distributions. + +## Platforms: + +* Ubuntu +* CentOS + +Attributes +========== + +* `node['mysql_test']['database']` - The name of the test database to create. +* `node['mysql_test']['username']` - The username of the datbase user. +* `node['mysql_test']['password']` - The password of the database user. + +Recipes +======= + +* `client` - Simply includes `mysql::client` for a vanilla mysql client install. +* `server` - Includes `mysql::server` to install the server and configures a + test database. + +License and Authors +=================== + +Author:: Andrew Crump + + Copyright:: 2012, 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/chef/cookbooks/mysql/test/cookbooks/mysql_test/attributes/default.rb b/chef/cookbooks/mysql/test/cookbooks/mysql_test/attributes/default.rb new file mode 100644 index 0000000..0826761 --- /dev/null +++ b/chef/cookbooks/mysql/test/cookbooks/mysql_test/attributes/default.rb @@ -0,0 +1,27 @@ +# +# Cookbook Name:: mysql_test +# Attributes:: default +# +# Copyright 2012, 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. +# + +# Must be specified for chef-solo for successful re-converge +override['mysql']['server_root_password'] = 'ebrilvOpCethHienRoj7' + +default['mysql_test']['database'] = 'mysql_test' +default['mysql_test']['username'] = 'test_user' +default['mysql_test']['password'] = 'neshFiapog' + +override['mysql']['bind_address'] = 'localhost' diff --git a/chef/cookbooks/mysql/test/cookbooks/mysql_test/files/default/tests/minitest/server_test.rb b/chef/cookbooks/mysql/test/cookbooks/mysql_test/files/default/tests/minitest/server_test.rb new file mode 100644 index 0000000..2850708 --- /dev/null +++ b/chef/cookbooks/mysql/test/cookbooks/mysql_test/files/default/tests/minitest/server_test.rb @@ -0,0 +1,36 @@ +require File.expand_path('../support/helpers.rb', __FILE__) + +describe 'mysql::server' do + + include Helpers::Mysql + + it 'has a secure operating system password' do + assert_secure_password(:debian) + end + it 'has a secure root password' do + assert_secure_password(:root) + end + it 'has a secure replication password' do + assert_secure_password(:repl) + end + it 'installs the mysql packages' do + node['mysql']['server']['packages'].each do |package_name| + package(package_name).must_be_installed + end + end + it 'has a config directory' do + directory(node['mysql']['confd_dir']).must_exist.with(:owner, 'mysql').and(:group, 'mysql') + end + it 'runs as a daemon' do + service(node['mysql']['service_name']).must_be_running + end + it 'creates a my.cnf' do + file("#{node['mysql']['conf_dir']}/my.cnf").must_exist + end + describe 'debian' do + it 'creates a config file for service control' do + skip unless ['debian'].include?(node['platform_family']) + file("#{node['mysql']['conf_dir']}/debian.cnf").must_exist + end + end +end diff --git a/chef/cookbooks/mysql/test/cookbooks/mysql_test/files/default/tests/minitest/support/helpers.rb b/chef/cookbooks/mysql/test/cookbooks/mysql_test/files/default/tests/minitest/support/helpers.rb new file mode 100644 index 0000000..c8b3fa2 --- /dev/null +++ b/chef/cookbooks/mysql/test/cookbooks/mysql_test/files/default/tests/minitest/support/helpers.rb @@ -0,0 +1,11 @@ +module Helpers + module Mysql + include MiniTest::Chef::Assertions + include MiniTest::Chef::Context + include MiniTest::Chef::Resources + + def assert_secure_password(type) + node["mysql"]["server_#{type}_password"].length.must_be_close_to(20, 8) + end + end +end diff --git a/chef/cookbooks/mysql/test/cookbooks/mysql_test/metadata.rb b/chef/cookbooks/mysql/test/cookbooks/mysql_test/metadata.rb new file mode 100644 index 0000000..0a66cbd --- /dev/null +++ b/chef/cookbooks/mysql/test/cookbooks/mysql_test/metadata.rb @@ -0,0 +1,9 @@ +maintainer "Andrew Crump" +maintainer_email "andrew@kotirisoftware.com" +license "Apache 2.0" +description "Acceptance tests for mysql" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) +version "0.1.0" + +depends "database" +depends "yum" diff --git a/chef/cookbooks/mysql/test/cookbooks/mysql_test/recipes/client.rb b/chef/cookbooks/mysql/test/cookbooks/mysql_test/recipes/client.rb new file mode 100644 index 0000000..235a67c --- /dev/null +++ b/chef/cookbooks/mysql/test/cookbooks/mysql_test/recipes/client.rb @@ -0,0 +1,20 @@ +# +# Cookbook Name:: mysql_test +# Recipe:: client +# +# Copyright 2012, 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 "yum::epel" if platform_family?('rhel') diff --git a/chef/cookbooks/mysql/test/cookbooks/mysql_test/recipes/server.rb b/chef/cookbooks/mysql/test/cookbooks/mysql_test/recipes/server.rb new file mode 100644 index 0000000..2473ee4 --- /dev/null +++ b/chef/cookbooks/mysql/test/cookbooks/mysql_test/recipes/server.rb @@ -0,0 +1,62 @@ +# +# Cookbook Name:: mysql_test +# Recipe:: server +# +# Copyright 2012, 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. +# + +node.set['mysql']['server_debian_password'] = "ilikerandompasswords" +node.set['mysql']['server_root_password'] = "ilikerandompasswords" +node.set['mysql']['server_repl_password'] = "ilikerandompasswords" + +include_recipe "mysql::ruby" +include_recipe "yum::epel" if platform_family?('rhel') + +file "/etc/sysconfig/network" do + content "NETWORKING=yes" + action :create_if_missing + only_if { platform_family?('rhel', 'fedora') } +end + +include_recipe 'mysql::server' + +mysql_connection = {:host => "localhost", :username => 'root', + :password => node['mysql']['server_root_password']} + +mysql_database node['mysql_test']['database'] do + connection mysql_connection + action :create +end + +mysql_database_user node['mysql_test']['username'] do + connection mysql_connection + password node['mysql_test']['password'] + database_name node['mysql_test']['database'] + host 'localhost' + privileges [:select,:update,:insert, :delete] + action [:create, :grant] +end + +mysql_conn_args = "--user=root --password=#{node['mysql']['server_root_password']}" + +execute 'create-sample-data' do + command %Q{mysql #{mysql_conn_args} #{node['mysql_test']['database']} <= 0.10.10') + +group :integration do + gem 'berkshelf', '~> 1.3.1' + gem 'test-kitchen', '~> 1.0.0.alpha.5' + gem 'kitchen-vagrant', '~> 0.9.0' +end diff --git a/chef/cookbooks/rvm/README.md b/chef/cookbooks/rvm/README.md new file mode 100644 index 0000000..1fe1a3a --- /dev/null +++ b/chef/cookbooks/rvm/README.md @@ -0,0 +1,1535 @@ +# chef-rvm [![Build Status](https://secure.travis-ci.org/fnichol/chef-rvm.png?branch=master)](http://travis-ci.org/fnichol/chef-rvm) + +## Description + +Manages system-wide and per-user [RVM][rvm]s and manages installed Rubies. +Several lightweight resources and providers ([LWRP][lwrp]) are also defined. + +## Usage + +### RVM Installed System-Wide with Rubies + +Most likely, this is the typical case. Include `recipe[rvm::system]` in your +run_list and override the defaults you want changed. See below for more +details. + +### RVM Installed For A Specific User with Rubies + +If you want a per-user install (like on a Mac/Linux workstation for +development), include `recipe[rvm::user]` in your run_list and add a user +hash to the `user_installs` attribute list. For example: + + node['rvm']['user_installs'] = [ + { 'user' => 'wigglebottom', + 'default_ruby' => 'rbx', + 'rubies' => ['1.9.2', '1.8.7'] + } + ] + +See below for more details. + +### RVM Installed System-Wide and LWRPs Defined + +If you want to manage your own RVM environment with the provided [LWRP][lwrp]s, +then include `recipe[rvm::system_install]` in your run_list to prevent +a default RVM Ruby being installed. See the **Resources and Providers** +section for more details. + +### RVM Installed For A Specific User and LWRPs Defined + +If you want to manage your own RVM environment for users with the provided +LWRPs, then include `recipe[rvm::user_install]` in your run_list and add a +user hash to the `user_installs` attribute list. For example: + + node['rvm']['user_installs'] = [ + { 'user' => 'wigglebottom' } + ] + +See the **Resources and Providers** section for more details. + +### Ultra-Minimal Access To LWRPs + +Simply include `recipe[rvm]` in your run_list and the LWRPs will be available +to use in other cookbooks. See the **Resources and Providers** section for +more details. + +### Other Use Cases + +* If node is running in a Vagrant VM, then including `recipe[rvm::vagrant]` +in your run_list can help with resolving the *chef-solo* binary on subsequent +provision executions. +* If you want other Chef cookbooks to install RubyGems in RVM-managed Rubies, +you can try including `recipe[rvm::gem_package]` in your run_list. Please +read the recipe details before attempting. + +## Requirements + +### Chef + +Tested on 0.10.2/0.10.4 and 0.9.16 but newer and older versions (of 0.9.x) +should work just fine. Due to the `rvm_gem` implementation, versions 0.8.x +of Chef currently will **not** work (see [GH-50][gh50]). + +File an [issue][issues] if this isn't the case. + +### Platform + +The following platforms have been tested with this cookbook, meaning that +the recipes and LWRPs run on these platforms without error: + +* ubuntu (10.04/10.10/11.04/12.04) +* debian (6.0) +* mac_os_x (10.6/10.7) (See [Platform Notes](#platform-notes-osx)) +* mac_os_x_server (See [Platform Notes](#platform-notes-osx)) +* suse (openSUSE, SLES) +* centos +* amazon (2011.09) +* scientific +* redhat +* fedora + +Please [report][issues] any additional platforms so they can be added. + +### Platform Notes + +#### OSX + +This cookbook suggests the [homebrew](http://community.opscode.com/cookbooks/homebrew) cookbook, which is needed to install +any additional packages needed to compile ruby. RVM now ships binary rubies, +but will require homebrew to install any additional libraries. + +### Cookbooks + +This cookbook depends on the following external cookbooks: + +* [chef\_gem][chef_gem_cb] + +If you are installing [JRuby][jruby] then a Java runtime will need to be +installed. The Opscode [java cookbook][java_cb] can be used on supported +platforms. + +## Installation + +Depending on the situation and use case there are several ways to install +this cookbook. All the methods listed below assume a tagged version release +is the target, but omit the tags to get the head of development. A valid +Chef repository structure like the [Opscode repo][chef_repo] is also assumed. + +### Using Berkshelf + +[Berkshelf][berkshelf] is a way to manage a cookbook or an application's +cookbook dependencies. Include the cookbook in your Berksfile, and then run +`berks install`. To install using Berkshelf: + + gem install berkshelf + cd chef-repo + berks init + echo "cookbook 'rvm', github: 'fnichol/chef-rvm'" >> Berksfile + berks install + +### Using Librarian-Chef + +[Librarian-Chef][librarian] is a bundler for your Chef cookbooks. +Include a reference to the cookbook in a [Cheffile][cheffile] and run +`librarian-chef install`. To install Librarian-Chef: + + gem install librarian + cd chef-repo + librarian-chef init + cat >> Cheffile < 'git://github.com/fnichol/chef-rvm.git', :ref => 'v0.9.0' + END_OF_CHEFFILE + librarian-chef install + +### Using knife-github-cookbooks + +The [knife-github-cookbooks][kgc] gem is a plugin for *knife* that supports +installing cookbooks directly from a GitHub repository. To install with the +plugin: + + gem install knife-github-cookbooks + cd chef-repo + knife cookbook github install fnichol/chef-rvm/v0.9.0 + +### As a Git Submodule + +A common practice (which is getting dated) is to add cookbooks as Git +submodules. This is accomplishes like so: + + cd chef-repo + git submodule add git://github.com/fnichol/chef-rvm.git cookbooks/rvm + git submodule init && git submodule update + +**Note:** the head of development will be linked here, not a tagged release. + +### As a Tarball + +If the cookbook needs to downloaded temporarily just to be uploaded to a Chef +Server or Opscode Hosted Chef, then a tarball installation might fit the bill: + + cd chef-repo/cookbooks + curl -Ls https://github.com/fnichol/chef-rvm/tarball/v0.9.0 | tar xfz - && \ + mv fnichol-chef-rvm-* rvm + +### From the Opscode Community Platform + +This cookbook is not currently available on the site due to the flat +namespace for cookbooks. There is some community work to be done here. + +## Recipes + +### default + +Installs the RVM gem and initializes Chef to use the Lightweight Resources +and Providers ([LWRPs][lwrp]). + +Use this recipe explicitly if you only want access to the LWRPs provided. + +### system_install + +Installs the RVM codebase system-wide (that is, into `/usr/local/rvm`). This +recipe includes *default*. + +Use this recipe by itself if you want RVM installed system-wide but want +to handle installing Rubies, invoking LWRPs, etc.. + +### system + +Installs the RVM codebase system-wide (that is, into `/usr/local/rvm`) and +installs Rubies, global gems, and specific gems driven off attribute metadata. +This recipe includes *default* and *system_install*. + +Use this recipe by itself if you want RVM system-wide with Rubies installed, +etc. + +### user_install + +Installs the RVM codebase for a list of users (selected from the +`node['rvm']['user_installs']` hash). This recipe includes *default*. + +Use this recipe by itself if you want RVM installed for specific users in +isolation but want each user to handle installing Rubies, invoking LWRPs, etc. + +### user + +Installs the RVM codebase for a list of users (selected from the +`node['rvm']['user_installs']` hash) and installs Rubies, global gems, and +specific gems driven off attribute metadata. This recipe includes *default* +and *user_install*. + +Use this recipe by itself if you want RVM installed for specific users in +isolation with Rubies installed, etc. + +### vagrant + +An optional recipe if Chef is installed in a non-RVM Ruby in a +[Vagrant][vagrant] virtual machine. This recipe adds the default *vagrant* +user to the RVM unix group and installs a `chef-solo` wrapper script so Chef +doesn't need to be re-installed in the default RVM Ruby. + +### gem_package + +An experimental recipe that patches the [gem_package resource][gem_package] +to use the `Chef::Provider::Package::RVMRubygems` provider. An attribute +`rvm/gem_package/rvm_string` will determine which RVM Ruby is used for +install/remove/upgrade/purge actions. This may help when using a third +party or upstream cookbook that assumes a non-RVM managed system Ruby. + +**Note:** When this recipe is included it will force RVM to be +installed in the [compilation phase][compilation]. This will ensure that all +Rubies can be available if any `gem_package` resource calls are issued from +other cookbooks during the compilation phase. + +**Warning:** [Here be dragons][dragons]! This is either brilliant or the +dumbest idea ever, so feedback is appreciated. + +## Attributes + +### default_ruby + +The default Ruby for RVM installed system-wide. If the RVM Ruby is not +installed, it will be built as a pre-requisite. The value can also contain a +gemset in the form of `"ruby-1.8.7-p352@awesome"`. + +The default is `"ruby-2.0.0-p0"`. To disable a default Ruby from being +set, use an empty string (`""`) or a value of `"system"`. + +### user_default_ruby + +The default Ruby for RVMs installed per-user when not explicitly set for that +user. If the RVM Ruby is not installed, it will be built as a pre-requisite. +The value can also contain a gemset in the form of `"ruby-1.8.7-p352@awesome"`. + +The default is `"ruby-2.0.0-p0"`. To disable a default Ruby from being +set, use an empty string (`""`) or a value of `"system"`. + +### rubies + +A list of additional RVM system-wide Rubies to be built and installed. This +list does not need to necessarily contain your default Ruby as the +`rvm_default_ruby` resource will take care of installing itself. You may also +include patch info and a rubygems version. For example: + + node['rvm']['rubies'] = [ + "ree-1.8.7", + "jruby", + { + 'version' => '1.9.3-p125-perf', + 'patch' => 'falcon', + 'rubygems_version' => '1.5.2' + } + ] + +The default is an empty array: `[]`. + +### user_rubies + +A list of additional RVM Rubies to be built and installed per-user when not +explicitly set. This list does not need to necessarily contain your default +Ruby as the `rvm_default_ruby` resource will take care of installing itself. +For example: + + node['rvm']['user_rubies'] = [ "ree-1.8.7", "jruby" ] + +The default is an empty array: `[]`. + +### global_gems + +A list of gem hashes to be installed into the *global* gemset in each +installed RVM Ruby sytem-wide. The **global.gems** files will be added to and +all installed Rubies will be iterated over to ensure full installation +coverage. See the `rvm_gem` resource for more details about the options for +each gem hash. + +The default puts bundler and rake in each Ruby: + + node['rvm']['global_gems'] = [ + { 'name' => 'bundler' }, + { 'name' => 'rake', + 'version' => '0.9.2' + }, + { 'name' => 'rubygems-bundler', + 'action' => 'remove' + } + ] + +### user_global_gems + +A list of gem hashes to be installed into the *global* gemset in each +installed RVM Ruby for each user when not explicitly set. The +**global.gems** files will be added to and all installed Rubies will be +iterated over to ensure full installation coverage. See the `rvm_gem` +resource for more details about the options for each gem hash. + +The default puts bundler and rake in each Ruby: + + node['rvm']['user_global_gems'] = [ + { 'name' => 'bundler' }, + { 'name' => 'rake', + 'version' => '0.9.2' + }, + { 'name' => 'rubygems-bundler', + 'action' => 'remove' + } + ] + +### gems + +A list of gem hashes to be installed into arbitrary RVM Rubies and gemsets +system-wide. See the `rvm_gem` resource for more details about the options for +each gem hash and target Ruby environment. For example: + + node['rvm']['gems'] = { + 'ruby-1.9.2-p280' => [ + { 'name' => 'vagrant' }, + { 'name' => 'veewee' }, + { 'name' => 'rake', + 'version' => '0.9.2' + } + ], + 'ruby-1.9.2-p280@empty-gemset' => [], + 'jruby' => [ + { 'name' => 'nokogiri', + 'version' => '1.5.0.beta.2' + }, + { 'name' => 'warbler' } + ] + } + +The default is an empty hash: `{}`. + +### user_gems + +A list of gem hashes to be installed into arbitrary RVM Rubies and gemsets +for each user when not explicitly set. See the `rvm_gem` resource for more +details about the options for each gem hash and target Ruby environment. See +the `gems` attribute for an example. + +The default is an empty hash: `{}`. + +### rvmrc + +A hash of system-wide `rvmrc` options. The key is the RVM setting name +(in String or Symbol form) and the value is the desired setting value. +An example used on a build box might be: + + node['rvm']['rvmrc'] = { + 'rvm_project_rvmrc' => 1, + 'rvm_gemset_create_on_use_flag' => 1, + 'rvm_trust_rvmrcs_flag' => 1 + } + +The default is an empty hash: `{}`. + +### user_installs + +A list of user specific RVM installation hashes. The `user_install` and +`user` recipes use this attribute to determine per-user installation settings. +The hash keys correspond to the default/system equivalents. For example: + + node['rvm']['user_installs'] = [ + { 'user' => 'jdoe', + 'upgrade' => "head", + 'default_ruby' => 'ree', + 'rvm_gem_options' => "", + 'global_gems' => [ + { 'name' => 'bundler', + 'version' => '1.1.pre.7' + }, + { 'name' => 'rake' }, + { 'name' => 'rubygems-bundler', + 'action' => 'remove' + } + ] + }, + { 'user' => 'jenkins', + 'version' => '1.7.0', + 'default_ruby' => 'jruby-1.6.3', + 'rubies' => [ + "ree-1.8.7", + "jruby", + { + 'version' => '1.9.3-p125-perf', + 'patch' => "falcon", + 'rubygems_version' => '1.5.2' + } + ], + 'rvmrc' => { + 'rvm_project_rvmrc' => 1, + 'rvm_gemset_create_on_use_flag' => 1, + 'rvm_pretty_print_flag' => 1 + }, + 'global_gems' => [ + { 'name' => 'bundler', + 'version' => '1.1.pre.7' + }, + { 'name' => 'rake', + 'version' => '0.8.7' + }, + { 'name' => 'rubygems-bundler', + 'action' => 'remove' + } + ] + } + ] + +The default is an empty list: `[]`. + +### installer_url + +The URL that provides the RVM installer. + +The default is `"https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer"`. + +### branch + +A specific git branch to use when installing system-wide. For example: + + node['rvm']['branch'] = "crazy" + +The default is `"stable"` which corresponds to the stable release branch. + +### version + +A specific tagged version or head of a branch to use when installing +system-wide. This value is passed directly to the `rvm-installer` script and +current valid values are: + +* `"head"` - the default, last git commit on a branch +* a specific tagged version of the form `"1.2.3"`. + +You may want to use a specific version of RVM to prevent differences in +deployment from one day to the next (RVM head moves pretty darn quickly). + +**Note** that if a version number is used, then `"none"` should be the value +of the `branch` attribute. For example: + + node['rvm']['version'] = "1.13.4" + node['rvm']['branch'] = "none" + +The default is `"head"`. + +### upgrade + +Determines how to handle installing updates to the RVM framework system-wide. +The value of this string is passed to `rvm get`. The possible values include: + +* `"none"`, `false`, or `nil`: will not update RVM and leave it in its + current state. +* Any other value is passed to `rvm get` as described on the + [upgrading][rvm_upgrading] page. For example: `"latest"`, `"stable"`, + and `"branch mpapis/shoes"`. + +The default is `"none"`. + +### root_path + +The path prefix to RVM in a system-wide installation. + +The default is `"/usr/local/rvm"`. + +### group_id + +The Unix *GID* to be used for the `rvm` group. If this attribute is set, +the group will be created in the compilation phase to avoid any collisions +with expected *GID*s in other cookbooks. If left at the default value, +the RVM installer will create this group as normal. + +The default is `default`. + +### group_users + +A list of users that will be added to the `rvm` group. These users +will then be able to manage RVM in a system-wide installation. + +The default is an empty list: `[]`. + +### rvm_gem_options + +These options are passed to the *gem* command in an RVM environment. +In the interest of speed, rdoc and ri docs will not be generated by default. +To re-enable the documentation generation set: + + node['rvm']['rvm_gem_options'] = "--rdoc --ri" + +The default is `"--no-rdoc --no-ri"`. + +### install_rubies (Future Deprecation) + +Can enable or disable installation of a default Ruby and additional Rubies +system-wide. For example: + + node['rvm']['install_rubies'] = "false" + +The default is `"true"`. + +**Note:** This remains a legacy setting and will be deprecated in +the next minor version release. + +### iuser_install_rubies (Future Deprecation) + +Can enable or disable installation of a default Ruby and additional Rubies +per user. For example: + + node['rvm']['user_install_rubies'] = "false" + +The default is `"true"`. + +**Note:** This remains a legacy setting and will be deprecated in +the next minor version release. + +### gem_package/rvm_string + +If using the `gem_package` recipe, this determines which Ruby or Rubies will +be used by the `gem_package` resource in other cookbooks. The value can be +either a *String* (for example `ruby-1.8.7-p334`) or an *Array* of RVM Ruby +strings (for example `['ruby-1.8.7-p334', 'system']`). To target an underlying +unmanaged system Ruby you can use `system`. + +The default is the value of the `default_ruby` attribute. + +### vagrant/system_chef_solo + +If using the `vagrant` recipe, this sets the path to the package-installed +*chef-solo* binary. + +The default is `"/opt/ruby/bin/chef-solo"`. + +## Resources and Providers + +### rvm_ruby + +#### Actions + + + + + + + + + + + + + + + + + + + + + + + + + + +
ActionDescriptionDefault
install + Build and install an RVM Ruby. See RVM rubies/installing(1) + for more details. + Yes
remove + Remove the Ruby, source files and optional gemsets/archives. See RVM + rubies/removing(2) for more details. +  
uninstall + Just remove the Ruby and leave everything else. See RVM rubies/removing(3) for more details. +  
+ +1. [RVM rubies/installing][rvm_install] +2. [RVM rubies/removing][rvm_remove] +3. [RVM rubies/removing][rvm_remove] + +#### Attributes + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionDefault Value
ruby_string + Name attribute: an RVM Ruby string that could contain a gemset. + If a gemset is given (for example, + "ruby-1.8.7-p330@awesome"), then it will be stripped. + nil
user + A users's isolated RVM installation on which to apply an action. The + default value of nil denotes a system-wide RVM + installation is being targeted. Note: if specified, the user + must already exist. + nil
+ +#### Examples + +##### Install Ruby + + rvm_ruby "ree" do + action :install + end + + rvm_ruby "jruby-1.6.3" + +**Note:** the install action is default, so the second example is a more common +usage. + +##### Remove Ruby + + rvm_ruby "ree-1.8.7-2011.01" do + action :remove + end + +**Note:** the RVM documentation mentions that this method is far preferred to +using uninstall since it purges almost everything. + +##### Uninstall Ruby + + rvm_ruby "ree-1.8.7-2011.01" do + action :uninstall + user "jenkins" + end + +**Note:** The RVM installation for the *jenkins* user will be acted upon. + +### rvm_default_ruby + +This resource sets the default RVM Ruby, optionally with gemset. The given +Ruby will be installed if it isn't already and a gemset will be created in +none currently exist. If multiple declarations are used then the last executed +one "wins". + +#### Actions + + + + + + + + + + + + + + + + +
ActionDescriptionDefault
create + Set the default RVM Ruby. See RVM rubies/default(1) for + more details. + Yes
+ +1. [RVM rubies/default][rvm_default] + +#### Attributes + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionDefault Value
ruby_string + Name attribute: an RVM Ruby string that could contain a gemset. + If a gemset is given (for example, + "ruby-1.8.7-p330@awesome"), then it will be included. + nil
user + A users's isolated RVM installation on which to apply an action. The + default value of nil denotes a system-wide RVM + installation is being targeted. Note: if specified, the + user must already exist. + nil
+ +#### Examples + +##### Setting The Default Ruby + + rvm_default_ruby "ree" do + action :create + end + + rvm_default_ruby "jruby-1.5.6" + +**Note:** the create action is default, so the second example is a more common +usage. + +### rvm_environment + +This resource ensures that the specified RVM Ruby is installed and the optional +gemset is created. It is a convenience resource which wraps `rvm_ruby` and +`rvm_gemset` so it can be used as a sort of *über Ruby* resource which +parallels the `rvm_default_ruby` resource. + +#### Actions + + + + + + + + + + + + + + + + +
ActionDescriptionDefault
createInstalls the specified RVM Ruby and gemset.Yes
+ +#### Attributes + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionDefault Value
ruby_string + Name attribute: an RVM Ruby string that could contain a gemset. + If a gemset is given (for example, + "ruby-1.8.7-p330@awesome"), then it will be used. + nil
user + A users's isolated RVM installation on which to apply an action. The + default value of nil denotes a system-wide RVM + installation is being targeted. Note: if specified, the + user must already exist. + nil
+ +#### Examples + +##### Creating A Passenger Environment In Production + + rvm_environment "ree-1.8.7-2011.01@passenger" + +### rvm_gemset + +See [RVM gemsets][rvm_gemsets] for more background concerning gemsets. + +#### Actions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ActionDescriptionDefault
create + Creates a new gemset in a given RVM Ruby. See RVM + gemsets/creating(1) for more details. + Yes
update + Update all gems installed to the gemset in a given RVM Ruby. +  
empty + Remove all gems installed to the gemset in a given RVM Ruby. See RVM + gemsets/emptying(2) for more details. +  
delete + Delete gemset from the given RVM Ruby. See RVM + gemsets/deleting(3) for more details. +  
+ +1. [RVM gemsets/creating][rvm_create_gemset] +2. [RVM gemsets/emptying][rvm_empty_gemset] +3. [RVM gemsets/deleting][rvm_delete_gemset] + +#### Attributes + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionDefault Value
gemset + Name attribute: Either an RVM Ruby string containing a gemset + or a bare gemset name. If only the gemset name is given, then the + ruby_string attribute must be used to indicate which + RVM Ruby to target. + nil
ruby_string + An RVM Ruby string that should not contain a gemset. + nil
user + A users's isolated RVM installation on which to apply an action. The + default value of nil denotes a system-wide RVM + installation is being targeted. Note: if specified, the + user must already exist. + nil
+ +#### Examples + +##### Creating A Gemset + + rvm_gemset "rails" do + ruby_string "ruby-1.9.2-p136" + action :create + end + + rvm_gemset "ruby-1.9.2-p136@rails" + +**Note:** the create action is default, so the second example is a more common +usage. + +##### Updating A Gemset + + rvm_gemset "jruby-1.6.0.RC2@development" do + action :update + end + +##### Emptying A Gemset + + rvm_gemset "development" do + ruby_string "jruby-1.6.3" + action :empty + end + +##### Deleting A Gemset + + rvm_gemset "ruby-1.9.2-p136@rails" do + action :delete + end + +### rvm_gem + +This resource is a close analog to the `gem_package` provider/resource which +is RVM-aware. See the Opscode [package resource][package_resource] and +[gem package options][gem_package_options] pages for more details. + +#### Actions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ActionDescriptionDefault
install + Install a gem - if version is provided, install that specific version. + Yes
upgrade + Upgrade a gem - if version is provided, upgrade to that specific + version +  
remove + Remove a gem. +  
purge + Purge a gem. +  
+ +#### Attributes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionDefault Value
package_name + Name attribute: the name of the gem to install. + nil
version + The specific version of the gem to install/upgrade. + nil
options + Add additional options to the underlying gem command. + nil
source + Provide an additional source for gem providers (such as RubyGems). + nil
gem_binary + A gem_package attribute to specify a gem binary. + "gem"
user + A users's isolated RVM installation on which to apply an action. The + default value of nil denotes a system-wide RVM + installation is being targeted. Note: if specified, the + user must already exist. + nil
+ +#### Examples + +##### Install A Gem + + rvm_gem "thor" do + ruby_string "ruby-1.8.7-p352" + action :install + end + + rvm_gem "json" do + ruby_string "ruby-1.8.7-p330@awesome" + end + + rvm_gem "nokogiri" do + ruby_string "jruby-1.5.6" + version "1.5.0.beta.4" + action :install + end + +**Note:** the install action is default, so the second example is a more common +usage. Gemsets can also be specified. + +##### Install A Gem From A Local File + + rvm_gem "json" do + ruby_string "ree@project" + source "/tmp/json-1.5.1.gem" + version "1.5.1" + end + +##### Keep A Gem Up To Date + + rvm_gem "homesick" do + action :upgrade + end + +**Note:** the default RVM Ruby will be targeted if no `ruby_string` attribute +is given. + +##### Remove A Gem + + rvm_gem "nokogiri" do + ruby_string "jruby-1.5.6" + version "1.4.4.2" + action :remove + end + +### rvm_global_gem + +This resource will use the `rvm_gem` resource to manage a gem in the *global* +gemset accross all RVM Rubies. An entry will also be made/removed in RVM's +*global.gems* file. See the Opscode [package resource][package_resource] and +[gem package options][gem_package_options] pages for more details. + +#### Actions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ActionDescriptionDefault
install + Install a gem across all Rubies - if version is provided, install that + specific version. + Yes
upgrade + Upgrade a gem across all Rubies - if version is provided, upgrade to + that specific version. +  
remove + Remove a gem across all Rubies. +  
purge + Purge a gem across all Rubies. +  
+ +#### Attributes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionDefault Value
package_name + Name attribute: the name of the gem to install. + nil
ruby_string + An RVM Ruby string that could contain a gemset. If a gemset is given + (for example, "ruby-1.8.7-p330@awesome"), then it will + be used. + "default"
version + The specific version of the gem to install/upgrade. + nil
options + Add additional options to the underlying gem command. + nil
source + Provide an additional source for gem providers (such as RubyGems). + This can also include a file system path to a .gem file + such as /tmp/json-1.5.1.gem. + nil
user + A users's isolated RVM installation on which to apply an action. The + default value of nil denotes a system-wide RVM + installation is being targeted. Note: if specified, the + user must already exist. + nil
+ +### rvm_shell + +This resource is a wrapper for the `script` resource which wraps the code block +in an RVM-aware environment.. See the Opscode +[script resource][script_resource] page for more details. + +#### Actions + + + + + + + + + + + + + + + + + + + + + +
ActionDescriptionDefault
runRun the scriptYes
nothingDo not run this command 
+ +Use `action :nothing` to set a command to only run if another resource +notifies it. + +#### Attributes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionDefault Value
name + Name attribute: Name of the command to execute. + name
ruby_string + An RVM Ruby string that could contain a gemset. If a gemset is given + (for example, "ruby-1.8.7-p330@awesome"), then it will + be used. + "default"
code + Quoted script of code to execute. + nil
creates + A file this command creates - if the file exists, the command will not + be run. + nil
cwd + Current working director to run the command from. + nil
environment + A hash of environment variables to set before running this command. + nil
group + A group or group ID that we should change to before running this command. + nil
path + An array of paths to use when searching for the command. + nil, uses system path
returns + The return value of the command (may be an array of accepted values) - + this resource raises an exception if the return value(s) do not match. + 0
timeout + How many seconds to let the command run before timing out. + nil
user + A user name or user ID that we should change to before running this command. + nil
user + A users's isolated RVM installation on which to apply an action. The + default value of nil denotes a system-wide RVM + installation is being targeted. Note: if specified, the + user must already exist. + nil
umask + Umask for files created by the command. + nil
+ +#### Examples + +##### Run A Rake Task + + rvm_shell "migrate_rails_database" do + ruby_string "1.8.7-p352@webapp" + user "deploy" + group "deploy" + cwd "/srv/webapp/current" + code %{rake RAILS_ENV=production db:migrate} + end + +### rvm_wrapper + +This resource creates a wrapper script for a binary or list of binaries in +a given RVM Ruby (and optional gemset). The given Ruby will be installed if +it isn't already and a gemset will be created in none currently exist. + +#### Actions + + + + + + + + + + + + + + + + +
ActionDescriptionDefault
createCreates on or more wrapper scripts.Yes
+ +#### Attributes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionDefault Value
prefix + Name attribute: a prefix string for the wrapper script name. + nil
ruby_string + An RVM Ruby string that could contain a gemset. If a gemset is given + (for example, "ruby-1.8.7-p330@awesome"), then it will + be used. + nil
binary + A single binary to be wrapped. If this attribute is used do not set + values for the binaries attribute. + nil
binaries + A list of binaries to be wrapped. If this attribute is used do not set + a value for the binary attribute. + nil
user + A users's isolated RVM installation on which to apply an action. The + default value of nil denotes a system-wide RVM + installation is being targeted. Note: if specified, the user + must already exist. + nil
+ +**Note:** only `binary` or `binaries` should be used by themselves (never at +the same time). + +#### Examples + +##### Wrapping A Ruby CLI + + rvm_wrapper "sys" do + ruby_string "jruby@utils" + binary "thor" + end + +This will create a wrapper script called `sys_thor` in the `bin` directory +under `node['rvm']['root_path']`. + +##### Wrapping A List Of Binaries + + rvm_wrapper "test" do + ruby_string "default@testing" + binaries [ "rspec", "cucumber" ] + action :create + end + +## Contributing + +* Source hosted at [GitHub][repo] +* Report issues/Questions/Feature requests on [GitHub Issues][issues] + +Pull requests are very welcome! Make sure your patches are well tested. +Ideally create a topic branch for every seperate change you make. + +### Testing + +Make sure you have the following requirements setup: + +* [Vagrant](http://www.vagrantup.com/) +* [vagrant-verkshelf](https://github.com/riotgames/vagrant-berkshelf) + +After you `bundle install` run `rake` for unit tests and `kitchen test` for +integration level tests. + +## License and Author + +Author:: [Fletcher Nichol][fnichol] () [![endorse](http://api.coderwall.com/fnichol/endorsecount.png)](http://coderwall.com/fnichol) + + +Contributors:: https://github.com/fnichol/chef-rvm/contributors + +Copyright:: 2010, 2011, Fletcher Nichol + +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. + +[berkshelf]: http://berkshelf.com +[chef_gem_cb]: http://community.opscode.com/cookbooks/chef_gem +[chef_repo]: https://github.com/opscode/chef-repo +[cheffile]: https://github.com/applicationsonline/librarian/blob/master/lib/librarian/chef/templates/Cheffile +[compilation]: http://wiki.opscode.com/display/chef/Evaluate+and+Run+Resources+at+Compile+Time +[dragons]: http://en.wikipedia.org/wiki/Here_be_dragons +[gem_package]: http://wiki.opscode.com/display/chef/Resources#Resources-Package +[gem_package_options]: http://wiki.opscode.com/display/chef/Resources#Resources-GemPackageOptions +[gh50]: https://github.com/fnichol/chef-rvm/issues/50 +[fnichol]: https://github.com/fnichol +[java_cb]: http://community.opscode.com/cookbooks/java +[jruby]: http://jruby.org/ +[kgc]: https://github.com/websterclay/knife-github-cookbooks#readme +[librarian]: https://github.com/applicationsonline/librarian#readme +[lwrp]: http://wiki.opscode.com/display/chef/Lightweight+Resources+and+Providers+%28LWRP%29 +[package_resource]: http://wiki.opscode.com/display/chef/Resources#Resources-Package +[rvm]: https://rvm.io +[rvm_create_gemset]: https://rvm.io/gemsets/creating/ +[rvm_delete_gemset]: https://rvm.io/gemsets/deleting/ +[rvm_empty_gemset]: https://rvm.io/gemsets/emptying/ +[rvm_default]: https://rvm.io/rubies/default/ +[rvm_gemsets]: https://rvm.io/gemsets/ +[rvm_install]: https://rvm.io/rubies/installing/ +[rvm_remove]: https://rvm.io/rubies/removing/ +[rvm_upgrading]: https://rvm.io/rvm/upgrading/ +[script_resource]: http://wiki.opscode.com/display/chef/Resources#Resources-Script +[vagrant]: http://vagrantup.com + +[repo]: https://github.com/fnichol/chef-rvm +[issues]: https://github.com/fnichol/chef-rvm/issues diff --git a/chef/cookbooks/rvm/Rakefile b/chef/cookbooks/rvm/Rakefile new file mode 100644 index 0000000..7c1c8f0 --- /dev/null +++ b/chef/cookbooks/rvm/Rakefile @@ -0,0 +1,25 @@ +#!/usr/bin/env rake + +require 'foodcritic' +require 'rake/testtask' + +# FC041 is excluded because we want to preserve the official RVM installation +# process as much as possible, i.e. using curl to download the installer. +FoodCritic::Rake::LintTask.new do |t| + t.options = { :fail_tags => ['any'], :tags => ['~FC041'] } +end + +Rake::TestTask.new do |t| + t.name = "unit" + t.test_files = FileList['test/unit/**/*_spec.rb'] + t.verbose = true +end + +begin + require 'kitchen/rake_tasks' + Kitchen::RakeTasks.new +rescue LoadError + puts ">>>>> Kitchen gem not loaded, omitting tasks" unless ENV['CI'] +end + +task :default => [:foodcritic, :unit] diff --git a/chef/cookbooks/rvm/attributes/.gitkeep b/chef/cookbooks/rvm/attributes/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/chef/cookbooks/rvm/attributes/default.rb b/chef/cookbooks/rvm/attributes/default.rb new file mode 100644 index 0000000..5cefc4f --- /dev/null +++ b/chef/cookbooks/rvm/attributes/default.rb @@ -0,0 +1,75 @@ +# +# Cookbook Name:: rvm +# Attributes:: default +# +# Author:: Fletcher Nichol +# +# Copyright 2010, 2011, Fletcher Nichol +# +# 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. +# + +# ruby that will get installed and set to `rvm use default`. +default['rvm']['default_ruby'] = "ruby-1.9.3-p327" +default['rvm']['user_default_ruby'] = "ruby-1.9.3-p327" + +# list of additional rubies that will be installed +default['rvm']['rubies'] = [] +default['rvm']['user_rubies'] = [] + +# list of gems to be installed in global gemset of all rubies +_global_gems_ = [ + { 'name' => 'bundler' } +] +default['rvm']['global_gems'] = _global_gems_.dup +default['rvm']['user_global_gems'] = _global_gems_.dup + +# hash of gemsets and their list of additional gems to be installed. +default['rvm']['gems'] = Hash.new +default['rvm']['user_gems'] = Hash.new + +# hash of rvmrc options +default['rvm']['rvmrc'] = Hash.new + +# a list of user hashes, each an isolated per-user RVM installation +default['rvm']['user_installs'] = [] + +# system-wide installer options +default['rvm']['installer_url'] = "https://get.rvm.io" +default['rvm']['branch'] = "stable" +default['rvm']['version'] = "head" +default['rvm']['upgrade'] = "none" + +# extra system-wide tunables +default['rvm']['root_path'] = "/usr/local/rvm" +default['rvm']['group_id'] = 'default' +default['rvm']['group_users'] = [] + +# default rvm_gem_options (skip rdoc/ri generation) +default['rvm']['rvm_gem_options'] = "--no-rdoc --no-ri" + +# a hook to disable installing any default/additional rubies +default['rvm']['install_rubies'] = "true" +default['rvm']['user_install_rubies'] = "true" + +case platform +when "redhat","centos","fedora","scientific","amazon" + node.set['rvm']['install_pkgs'] = %w{sed grep tar gzip bzip2 bash curl git} + default['rvm']['user_home_root'] = '/home' +when "debian","ubuntu","suse" + node.set['rvm']['install_pkgs'] = %w{sed grep tar gzip bzip2 bash curl git-core} + default['rvm']['user_home_root'] = '/home' +when "mac_os_x", "mac_os_x_server" + node.set['rvm']['install_pkgs'] = %w{git} + default['rvm']['user_home_root'] = '/Users' +end diff --git a/chef/cookbooks/rvm/attributes/gem_package.rb b/chef/cookbooks/rvm/attributes/gem_package.rb new file mode 100644 index 0000000..f734329 --- /dev/null +++ b/chef/cookbooks/rvm/attributes/gem_package.rb @@ -0,0 +1,23 @@ +# +# Cookbook Name:: rvm +# Attributes:: gem_package +# +# Author:: Fletcher Nichol +# +# Copyright 2010, 2011, Fletcher Nichol +# +# 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. +# + +# rvm ruby that will be used for gem_package resources +default['rvm']['gem_package']['rvm_string'] = node['rvm']['default_ruby'] diff --git a/chef/cookbooks/rvm/attributes/vagrant.rb b/chef/cookbooks/rvm/attributes/vagrant.rb new file mode 100644 index 0000000..f0fb575 --- /dev/null +++ b/chef/cookbooks/rvm/attributes/vagrant.rb @@ -0,0 +1,23 @@ +# +# Cookbook Name:: rvm +# Attributes:: vagrant +# +# Author:: Fletcher Nichol +# +# Copyright 2010, 2011, Fletcher Nichol +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +default['rvm']['vagrant']['system_chef_client'] = "/opt/vagrant_ruby/bin/chef-client" +default['rvm']['vagrant']['system_chef_solo'] = "/opt/vagrant_ruby/bin/chef-solo" diff --git a/chef/cookbooks/rvm/libraries/chef_rvm_environment_helpers.rb b/chef/cookbooks/rvm/libraries/chef_rvm_environment_helpers.rb new file mode 100644 index 0000000..c218224 --- /dev/null +++ b/chef/cookbooks/rvm/libraries/chef_rvm_environment_helpers.rb @@ -0,0 +1,55 @@ +# +# Cookbook Name:: rvm +# Library:: Chef::RVM::EnvironmentHelpers +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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. +# + +class Chef + module RVM + module RubyHelpers + # stub to satisfy EnvironmentHelpers (library load order not guarenteed) + end + + module GemsetHelpers + # stub to satisfy EnvironmentHelpers (library load order not guarenteed) + end + + module EnvironmentHelpers + include RubyHelpers + include GemsetHelpers + + ## + # Determines whether or not and ruby/gemset environment exists + # + # @param [String, #to_s] the fully qualified RVM ruby string + # @return [Boolean] does this environment exist? + def env_exists?(ruby_string) + return true if system_ruby?(ruby_string) + + rubie = select_ruby(ruby_string) + gemset = select_gemset(ruby_string) + + if gemset + gemset_exists?(:ruby => rubie, :gemset => gemset) + else + ruby_installed?(rubie) + end + end + end + end +end diff --git a/chef/cookbooks/rvm/libraries/chef_rvm_gemset_helpers.rb b/chef/cookbooks/rvm/libraries/chef_rvm_gemset_helpers.rb new file mode 100644 index 0000000..461f7ff --- /dev/null +++ b/chef/cookbooks/rvm/libraries/chef_rvm_gemset_helpers.rb @@ -0,0 +1,67 @@ +# +# Cookbook Name:: rvm +# Library:: Chef::RVM::GemsetHelpers +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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. +# + +class Chef + module RVM + module GemsetHelpers + ## + # Lists all gemsets for a given RVM Ruby. + # + # **Note** that these values are cached for lookup speed. To flush these + # values and force an update, call #update_installed_gemsets. + # + # @param [String, #to_s] the RVM Ruby string + # @return [Array] a cached list of gemset names + def installed_gemsets(rubie) + @installed_gemsets = Hash.new if @installed_gemsets.nil? + @installed_gemsets[rubie] ||= update_installed_gemsets(rubie) + end + + ## + # Updates the list of all gemsets for a given RVM Ruby on the system + # + # @param [String, #to_s] the RVM Ruby string + # @return [Array] the current list of gemsets + def update_installed_gemsets(rubie) + original_rubie = @rvm_env.environment_name + @rvm_env.use rubie + + @installed_gemsets ||= {} + @installed_gemsets[rubie] = @rvm_env.gemset_list + @rvm_env.use original_rubie if original_rubie != rubie + @installed_gemsets[rubie] + end + + ## + # Determines whether or not a gemset exists for a given Ruby + # + # @param [Hash] the options to query a gemset with + # @option opts [String] :ruby the Ruby the query within + # @option opts [String] :gemset the gemset to look for + def gemset_exists?(opts={}) + return false if opts[:ruby].nil? || opts[:gemset].nil? + return false unless ruby_installed?(opts[:ruby]) + + installed_gemsets(opts[:ruby]).include?(opts[:gemset]) + end + end + end +end diff --git a/chef/cookbooks/rvm/libraries/chef_rvm_recipe_helpers.rb b/chef/cookbooks/rvm/libraries/chef_rvm_recipe_helpers.rb new file mode 100644 index 0000000..49b8263 --- /dev/null +++ b/chef/cookbooks/rvm/libraries/chef_rvm_recipe_helpers.rb @@ -0,0 +1,225 @@ +# +# Cookbook Name:: rvm +# Library:: Chef::RVM::RecipeHelpers +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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. +# + +class Chef + module RVM + module RecipeHelpers + def build_script_flags(branch, version = "head") + if version =~ /\A\d+\.\d+\.\d+/ && %w{stable master none}.include?(branch) + " -s -- --version #{version}" + else + " -s -- --branch #{branch} --version #{version}" + end + end + + def build_upgrade_strategy(strategy) + if strategy.nil? || strategy == false + "none" + else + strategy + end + end + + def install_pkg_prereqs(install_now = node.recipe?("rvm::gem_package")) + return if mac_with_no_homebrew + + node['rvm']['install_pkgs'].each do |pkg| + p = package pkg do + # excute in compile phase if gem_package recipe is requested + if install_now + action :nothing + else + action :install + end + end + p.run_action(:install) if install_now + end + end + + def install_rvm(opts = {}) + install_now = node.recipe?("rvm::gem_package") + + if opts[:user] + user_dir = opts[:rvm_prefix] + exec_name = "install user RVM for #{opts[:user]}" + exec_env = { 'USER' => opts[:user], 'HOME' => user_dir, 'TERM' => 'dumb' } + else + user_dir = nil + exec_name = "install system-wide RVM" + exec_env = { 'TERM' => 'dumb' } + end + + rvm_installed_check = rvm_wrap_cmd( + %{type rvm | cat | head -1 | grep -q '^rvm is a function$'}, user_dir + ) + install_command = "curl -L #{opts[:installer_url]} | bash #{opts[:script_flags]}" + install_user = opts[:user] || "root" + + log "Performing RVM install with [#{install_command}] (as #{install_user})" + + i = execute exec_name do + user install_user + command install_command + environment(exec_env) + + # excute in compile phase if gem_package recipe is requested + if install_now + action :nothing + else + action :run + end + + not_if rvm_installed_check, :environment => exec_env + end + i.run_action(:run) if install_now + end + + def upgrade_rvm(opts = {}) + install_now = node.recipe?("rvm::gem_package") + + if opts[:user] + user_dir = opts[:rvm_prefix] + exec_name = "upgrade user RVM for #{opts[:user]} to " + + opts[:upgrade_strategy] + exec_env = { 'USER' => opts[:user], 'HOME' => user_dir } + else + user_dir = nil + exec_name = "upgrade system-wide RVM to " + + opts[:upgrade_strategy] + exec_env = nil + end + + upgrade_cmd = rvm_wrap_cmd( + %{rvm get #{opts[:upgrade_strategy]}}, user_dir + ) + + u = execute exec_name do + user opts[:user] || "root" + command upgrade_cmd + environment(exec_env) + + # excute in compile phase if gem_package recipe is requested + if install_now + action :nothing + else + action :run + end + + not_if { opts[:upgrade_strategy] == "none" } + end + u.run_action(:run) if install_now + end + + def rvmrc_template(opts = {}) + install_now = node.recipe?("rvm::gem_package") + + if opts[:user] + system_install = false + rvmrc_file = "#{opts[:rvm_prefix]}/.rvmrc" + rvm_path = "#{opts[:rvm_prefix]}/.rvm" + else + system_install = true + rvmrc_file = "/etc/rvmrc" + rvm_path = "#{opts[:rvm_prefix]}/rvm" + end + + t = template rvmrc_file do + source "rvmrc.erb" + owner opts[:user] || "root" + mode "0644" + variables :system_install => system_install, + :rvm_path => rvm_path, + :rvm_gem_options => opts[:rvm_gem_options], + :rvmrc => opts[:rvmrc] + + # excute in compile phase if gem_package recipe is requested + if install_now + action :nothing + else + action :create + end + end + t.run_action(:create) if install_now + end + + def install_rubies(opts = {}) + # install additional rubies + opts[:rubies].each do |rubie| + if rubie.is_a?(Hash) + ruby = rubie.fetch("version") + ruby_patch = rubie.fetch("patch", nil) + ruby_rubygems_version = rubie.fetch("rubygems_version", nil) + else + ruby = rubie + ruby_patch = nil + ruby_rubygems_version = nil + end + + rvm_ruby ruby do + patch ruby_patch + user opts[:user] + rubygems_version ruby_rubygems_version + end + end + + # set a default ruby + rvm_default_ruby opts[:default_ruby] do + user opts[:user] + end + + # install global gems + opts[:global_gems].each do |gem| + rvm_global_gem gem[:name] do + user opts[:user] + [:version, :action, :options, :source].each do |attr| + send(attr, gem[attr]) if gem[attr] + end + end + end + + # install additional gems + opts[:gems].each_pair do |rstring, gems| + rvm_environment rstring do + user opts[:user] + end + + gems.each do |gem| + rvm_gem gem[:name] do + ruby_string rstring + user opts[:user] + [:version, :action, :options, :source].each do |attr| + send(attr, gem[attr]) if gem[attr] + end + end + end + end + end + + private + + def mac_with_no_homebrew + %w{ mac_os_x mac_os_x_server }.include?(node['platform']) && + Chef::Platform.find_provider_for_node(node, :package) != + Chef::Provider::Package::Homebrew + end + end + end +end diff --git a/chef/cookbooks/rvm/libraries/chef_rvm_ruby_helpers.rb b/chef/cookbooks/rvm/libraries/chef_rvm_ruby_helpers.rb new file mode 100644 index 0000000..2fbbec1 --- /dev/null +++ b/chef/cookbooks/rvm/libraries/chef_rvm_ruby_helpers.rb @@ -0,0 +1,95 @@ +# +# Cookbook Name:: rvm +# Library:: Chef::RVM::RubyHelpers +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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. +# + +class Chef + module RVM + module RubyHelpers + ## + # Lists all installed RVM Rubies on the system. + # + # **Note** that these values are cached for lookup speed. To flush these + # values and force an update, call #update_installed_rubies. + # + # @return [Array] the cached list of currently installed RVM Rubies + def installed_rubies + @installed_rubies ||= update_installed_rubies + end + + ## + # Updates the list of all installed RVM Rubies on the system + # + # @return [Array] the list of currently installed RVM Rubies + def update_installed_rubies + @installed_rubies = @rvm_env.list_strings + @installed_rubies + end + + ## + # Determines whether or not the given Ruby is already installed + # + # @param [String, #to_s] the RVM Ruby string + # @return [Boolean] is this Ruby installed? + def ruby_installed?(rubie) + ! installed_rubies.select { |r| r.end_with?(rubie) }.empty? + end + + ## + # Fetches the current default Ruby string, potentially with gemset + # + # @return [String] the RVM Ruby string, nil if none is set + def current_ruby_default + @rvm_env.list_default + end + + ## + # Determines whether or not the given Ruby is the default one + # + # @param [String, #to_s] the RVM Ruby string + # @return [Boolean] is this Ruby the default one? + def ruby_default?(rubie) + current_default = current_ruby_default + + if current_default.nil? + if rubie == "system" + return true + else + return false + end + end + + current_default.start_with?(rubie) + end + + ## + # Determines whether or not the given Ruby could be considered the + # system Ruby. + # + # @param [String, #to_s] the RVM Ruby string + # @return [Boolean] is this Ruby string the a system Ruby? + def system_ruby?(rubie) + return true if rubie.nil? # nil should be system + return true if rubie.empty? # an empty string should be system + return true if rubie == "system" # keyword system should be system + return false # anything else does not represent system + end + end + end +end diff --git a/chef/cookbooks/rvm/libraries/chef_rvm_set_helpers.rb b/chef/cookbooks/rvm/libraries/chef_rvm_set_helpers.rb new file mode 100644 index 0000000..6392438 --- /dev/null +++ b/chef/cookbooks/rvm/libraries/chef_rvm_set_helpers.rb @@ -0,0 +1,16 @@ +class Chef + module RVM + module SetHelpers + def rvm_do(user = nil) + # Use Gem's version comparing code to compare the two strings + rvm_version = VersionCache.fetch_version(user).gsub(/(-|_|#)/, '.') + if Gem::Version.new(rvm_version) < Gem::Version.new("1.8.6") + "exec" + else + "do" + end + end + + end + end +end diff --git a/chef/cookbooks/rvm/libraries/chef_rvm_shell_helpers.rb b/chef/cookbooks/rvm/libraries/chef_rvm_shell_helpers.rb new file mode 100644 index 0000000..a01fedc --- /dev/null +++ b/chef/cookbooks/rvm/libraries/chef_rvm_shell_helpers.rb @@ -0,0 +1,57 @@ +# +# Cookbook Name:: rvm +# Library:: Chef::RVM::ShellHelpers +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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. +# + +class Chef + module RVM + module ShellHelpers + ## + # Finds the correct shell profile to source to init an RVM-aware + # shell environment + # + # @param [String] a user's home directory path if this is for a user or + # nil if it is in a system context + # @return [String] full path the shell profile + def find_profile_to_source(user_dir = nil) + if user_dir + "#{user_dir}/.rvm/scripts/rvm" + else + if ::File.directory?("/etc/profile.d") + "/etc/profile.d/rvm.sh" + else + "/etc/profile" + end + end + end + + ## + # Returns a shell command that is RVM-aware + # + # @param [String, #to_s] the shell command to be wrapped + # @param [String] A user's home directory path if this is for a user or + # nil if it is in a system context + # @return [String] the command wrapped in RVM-initialized bash command + def rvm_wrap_cmd(cmd, user_dir = nil) + profile = find_profile_to_source(user_dir) + %{bash -c "source #{profile} && #{cmd.gsub(/"/, '\"')}"} + end + end + end +end diff --git a/chef/cookbooks/rvm/libraries/chef_rvm_string_cache.rb b/chef/cookbooks/rvm/libraries/chef_rvm_string_cache.rb new file mode 100644 index 0000000..6258248 --- /dev/null +++ b/chef/cookbooks/rvm/libraries/chef_rvm_string_cache.rb @@ -0,0 +1,104 @@ +# +# Cookbook Name:: rvm +# Library:: Chef::RVM::StringCache +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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 'chef/mixin/command' + +class Chef + module RVM + module ShellHelpers + # stub to satisfy StringCache (library load order not guarenteed) + end + + class StringCache + class << self + include Chef::Mixin::Command + include Chef::RVM::ShellHelpers + end + + ## + # Returns a fully qualified RVM Ruby string for the given input string + # + # @param [String] a string that can interpreted by RVM + # @param [String] the username if this is for a user install or nil if + # it is a system install + # @return [String] a fully qualified RVM Ruby string + def self.fetch(str, user = nil) + @@strings ||= Hash.new + rvm_install = user || "system" + @@strings[rvm_install] ||= Hash.new + + return @@strings[rvm_install][str] if @@strings[rvm_install].has_key?(str) + + result = canonical_ruby_string(str, user) + # cache everything except default environment + if str == 'default' + result + else + @@strings[rvm_install][str] = result + end + end + + protected + + def self.canonical_ruby_string(str, user) + Chef::Log.debug("Fetching canonical RVM string for: #{str} " + + "(#{user || 'system'})") + if user + user_dir = Etc.getpwnam(user).dir + else + user_dir = nil + end + + cmd = ["source #{find_profile_to_source(user_dir)}", + "rvm_ruby_string='#{str}'", "__rvm_ruby_string", + "echo $rvm_ruby_string"].join(" && ") + pid, stdin, stdout, stderr = popen4('bash', shell_params(user, user_dir)) + stdin.puts(cmd) + stdin.close + + result = stdout.read.split('\n').first.chomp + if result =~ /^-/ # if the result has a leading dash, value is bogus + Chef::Log.warn("Could not determine canonical RVM string for: #{str} " + + "(#{user || 'system'})") + nil + else + Chef::Log.debug("Canonical RVM string is: #{str} => #{result} " + + "(#{user || 'system'})") + result + end + end + + def self.shell_params(user, user_dir) + if user + { + :user => user, + :environment => { + 'USER' => user, + 'HOME' => user_dir + } + } + else + Hash.new + end + end + end + end +end diff --git a/chef/cookbooks/rvm/libraries/chef_rvm_string_helpers.rb b/chef/cookbooks/rvm/libraries/chef_rvm_string_helpers.rb new file mode 100644 index 0000000..f91706d --- /dev/null +++ b/chef/cookbooks/rvm/libraries/chef_rvm_string_helpers.rb @@ -0,0 +1,61 @@ +# +# Cookbook Name:: rvm +# Library:: Chef::RVM::StringHelpers +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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. +# + +class Chef + module RVM + module StringHelpers + ## + # Filters out any gemset declarations in an RVM Ruby string + # + # @param [String, #to_s] the RVM Ruby string + # @return [String] the Ruby string, minus gemset + def select_ruby(ruby_string) + ruby_string.split('@').first + end + + ## + # Filters out any Ruby declaration in an RVM Ruby string + # + # @param [String, #to_s] the RVM Ruby string + # @return [String] the gemset string, minus Ruby or nil if no gemset given + def select_gemset(ruby_string) + if ruby_string.include?('@') + ruby_string.split('@').last + else + nil + end + end + + ## + # Sanitizes a Ruby string so that it's more normalized. + # + # @param [String, #to_s] an RVM Ruby string + # @param [String] a specific user RVM or nil for system-wide + # @return [String] a fully qualified RVM Ruby string + def normalize_ruby_string(ruby_string, user = new_resource.user, patch = new_resource.patch) + return "system" if ruby_string == "system" + fetched_ruby_string = StringCache.fetch(ruby_string, user) + return "#{fetched_ruby_string} --patch #{patch}" if patch + fetched_ruby_string + end + end + end +end diff --git a/chef/cookbooks/rvm/libraries/chef_rvm_version_helpers.rb b/chef/cookbooks/rvm/libraries/chef_rvm_version_helpers.rb new file mode 100644 index 0000000..b513c5a --- /dev/null +++ b/chef/cookbooks/rvm/libraries/chef_rvm_version_helpers.rb @@ -0,0 +1,45 @@ +class Chef + module RVM + module ShellHelpers + # stub to satisfy VersionCache (library load order not guarenteed) + end + + module VersionHelpers + def rvm_version(user = nil) + VersionCache.fetch_version(user) + end + end + + class VersionCache + class << self + include Chef::Mixin::ShellOut + include Chef::RVM::ShellHelpers + end + + def self.fetch_version(user = nil) + @@versions ||= Hash.new + rvm_install = user || "system" + @@versions[rvm_install] ||= rvm_version(user) + end + + def self.rvm_version(user = nil) + cmd = "rvm version | cut -d ' ' -f 2" + + if user + user_dir = Etc.getpwnam(user).dir + environment = { 'USER' => user, 'HOME' => user_dir } + else + user_dir = nil + environment = nil + end + + version = shell_out!( + rvm_wrap_cmd(cmd, user_dir), :env => environment).stdout.strip + + Chef::Log.debug "RVM version = #{version} (#{user || 'system'})" + + version + end + end + end +end diff --git a/chef/cookbooks/rvm/libraries/gem_package_monkeypatch.rb b/chef/cookbooks/rvm/libraries/gem_package_monkeypatch.rb new file mode 100644 index 0000000..80e3c15 --- /dev/null +++ b/chef/cookbooks/rvm/libraries/gem_package_monkeypatch.rb @@ -0,0 +1,34 @@ +# +# Cookbook Name:: rvm +# Library: gem_package resource monkey patch +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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. +# + +## +# Patch Chef::Resource::GemPackage resource to use the RVMRubygems provider. +# This has potentially dangerous side effects and should be considered +# experimental. You have been warned. +def patch_gem_package + ::Chef::Resource::GemPackage.class_eval do + def initialize(name, run_context=nil) + super + @resource_name = :gem_package + @provider = Chef::Provider::Package::RVMRubygems + end + end +end diff --git a/chef/cookbooks/rvm/libraries/rvm_chef_user_environment.rb b/chef/cookbooks/rvm/libraries/rvm_chef_user_environment.rb new file mode 100644 index 0000000..84e37a4 --- /dev/null +++ b/chef/cookbooks/rvm/libraries/rvm_chef_user_environment.rb @@ -0,0 +1,55 @@ +# +# Cookbook Name:: rvm +# Library:: RVM::ChefUserEnvironment +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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. +# + +def create_rvm_chef_user_environment + klass = Class.new(::RVM::Environment) do + attr_reader :user, :source_environment + + def initialize(user = nil, environment_name = "default", options = {}) + @source_environment = options.delete(:source_environment) + @source_environment = true if @source_environment.nil? + @user = user + # explicitly set rvm_path if user is set + if @user.nil? + config['rvm_path'] = @@root_rvm_path + else + config['rvm_path'] = File.join(Etc.getpwnam(@user).dir, '.rvm') + end + + merge_config! options + @environment_name = environment_name + @shell_wrapper = ::RVM::Shell::ChefWrapper.new(@user) + @shell_wrapper.setup do |s| + if source_environment + source_rvm_environment + use_rvm_environment + end + end + end + + def self.root_rvm_path=(path) + @@root_rvm_path = path + end + end + ::RVM.const_set('ChefUserEnvironment', klass) + + ::RVM::ChefUserEnvironment.root_rvm_path = node['rvm']['root_path'] +end diff --git a/chef/cookbooks/rvm/libraries/rvm_rubygems_package.rb b/chef/cookbooks/rvm/libraries/rvm_rubygems_package.rb new file mode 100644 index 0000000..a789f0a --- /dev/null +++ b/chef/cookbooks/rvm/libraries/rvm_rubygems_package.rb @@ -0,0 +1,190 @@ +# +# Cookbook Name:: rvm +# Provider:: Chef::Provider::Package::RVMRubygems +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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. +# + +class Chef + module RVM + module ShellHelpers + # stub to satisfy RVMRubygems (library load order not guarenteed) + end + module SetHelpers + # stub to satisfy RVMRubygems (library load order not guarenteed) + end + end + + class Provider + class Package + class RVMRubygems < Chef::Provider::Package::Rubygems + include Chef::RVM::ShellHelpers + include Chef::RVM::SetHelpers + + class RVMGemEnvironment < AlternateGemEnvironment + include Chef::RVM::ShellHelpers + include Chef::RVM::SetHelpers + + attr_reader :ruby_strings, :user + + def initialize(gem_binary_location, ruby_strings, user = nil) + super(gem_binary_location) + @ruby_strings = ruby_strings + @user = user + end + + def gem_paths + cmd = "rvm #{ruby_strings.join(',')} " + cmd << "#{rvm_do(user)} #{@gem_binary_location} env gempath" + + if user + user_dir = Etc.getpwnam(user).dir + environment = { 'USER' => user, 'HOME' => user_dir } + else + user_dir = nil + environment = nil + end + + # shellout! is a fork/exec which won't work on windows + shell_style_paths = shell_out!( + rvm_wrap_cmd(cmd, user_dir), :env => environment).stdout + # on windows, the path separator is semicolon + paths = shell_style_paths.split( + ::File::PATH_SEPARATOR).map { |path| path.strip } + end + + def gem_platforms + cmd = "rvm #{ruby_strings.join(',')} " + cmd << "#{rvm_do(user)} #{@gem_binary_location} env" + + if user + user_dir = Etc.getpwnam(user).dir + environment = { 'USER' => user, 'HOME' => user_dir } + else + user_dir = nil + environment = nil + end + + gem_environment = shell_out!( + rvm_wrap_cmd(cmd, user_dir), :env => environment).stdout + if jruby = gem_environment[JRUBY_PLATFORM] + ['ruby', Gem::Platform.new(jruby)] + else + Gem.platforms + end + end + end + + def initialize(new_resource, run_context=nil) + original_gem_binary = new_resource.gem_binary + super + new_resource.gem_binary("gem") unless original_gem_binary + user = new_resource.respond_to?("user") ? new_resource.user : nil + @gem_env = RVMGemEnvironment.new(gem_binary_path, ruby_strings, user) + end + + ## + # Determine the array of RVM ruby strings to use in this provider. + # In most cases only a single string value will be specified, but + # an array is always returned to account for multiple rubies. + # + # @return [Array] an array of RVM ruby strings + def ruby_strings + @ruby_strings ||= begin + result = if new_resource.respond_to?("ruby_string") + # the resource understands `.ruby_string' natively + new_resource.ruby_string + else + # most likely the gem_package resource or another native one + node['rvm']['gem_package']['rvm_string'] + end + + # if the result is a String, then wrap in an Array, otherwise + # return the array + case result + when String; [ result ] + when Array; result + end + end + end + + def install_package(name, version) + # ensure each ruby is installed and gemset exists + ruby_strings.each do |rubie| + next if rubie == 'system' + e = rvm_environment rubie do + user gem_env.user if gem_env.user + action :nothing + end + e.run_action(:create) + end + + install_via_gem_command(name, version) + true + end + + def install_via_gem_command(name, version) + # Handle installing from a local file. + if source_is_remote? + src = @new_resource.source && + " --source=#{@new_resource.source} --source=http://rubygems.org" + else + name = @new_resource.source + end + + cmd = %{rvm #{ruby_strings.join(',')} #{rvm_do(gem_env.user)} #{gem_binary_path}} + cmd << %{ install #{name} -q --no-rdoc --no-ri -v "#{version}"} + cmd << %{#{src}#{opts}} + + if gem_env.user + user_dir = Etc.getpwnam(gem_env.user).dir + environment = { 'USER' => gem_env.user, 'HOME' => user_dir } + else + user_dir = nil + environment = nil + end + + shell_out!(rvm_wrap_cmd(cmd, user_dir), :env => environment) + end + + def remove_package(name, version) + uninstall_via_gem_command(name, version) + end + + def uninstall_via_gem_command(name, version) + cmd = %{rvm #{ruby_strings.join(',')} #{rvm_do(gem_env.user)} #{gem_binary_path}} + cmd << %{ uninstall #{name} -q -x -I} + if version + cmd << %{ -v "#{version}"#{opts}} + else + cmd << %{ -a#{opts}} + end + + if gem_env.user + user_dir = Etc.getpwnam(gem_env.user).dir + environment = { 'USER' => gem_env.user, 'HOME' => user_dir } + else + user_dir = nil + environment = nil + end + + shell_out!(rvm_wrap_cmd(cmd, user_dir), :env => environment) + end + end + end + end +end diff --git a/chef/cookbooks/rvm/libraries/rvm_shell_chef_wrapper.rb b/chef/cookbooks/rvm/libraries/rvm_shell_chef_wrapper.rb new file mode 100644 index 0000000..faf577e --- /dev/null +++ b/chef/cookbooks/rvm/libraries/rvm_shell_chef_wrapper.rb @@ -0,0 +1,99 @@ +# +# Cookbook Name:: rvm +# Library:: RVM::Shell::ChefWrapper +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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. +# + +def create_rvm_shell_chef_wrapper + require 'chef/mixin/command' + + klass = Class.new(::RVM::Shell::AbstractWrapper) do + include Chef::Mixin::Command + + attr_accessor :current + + def initialize(user = nil, sh = 'bash -l', &setup_block) + @user = user + super(sh, &setup_block) + end + + # Runs a given command in the current shell. + # Defaults the command to true if empty. + def run_command(command) + command = "true" if command.to_s.strip.empty? + with_shell_instance do + Chef::Log.debug("RVM::Shell::ChefWrapper executing: " + + "[#{wrapped_command(command)}]") + stdin.puts wrapped_command(command) + stdin.close + out, err = stdout.read, stderr.read + out, status, _ = raw_stdout_to_parts(out) + return status, out, err + end + end + + # Runs a command, ensuring no output is collected. + def run_command_silently(command) + with_shell_instance do + Chef::Log.debug("RVM::Shell::ChefWrapper silently executing: " + + "[#{wrapped_command(command)}]") + stdin.puts silent_command(command) + end + end + + protected + + # yields stdio, stderr and stdin for a shell instance. + # If there isn't a current shell instance, it will create a new one. + # In said scenario, it will also cleanup once it is done. + def with_shell_instance(&blk) + no_current = @current.nil? + if no_current + Chef::Log.debug("RVM::Shell::ChefWrapper subprocess executing with " + + "environment of: [#{shell_params.inspect}].") + @current = popen4(self.shell_executable, shell_params) + invoke_setup! + end + yield + ensure + @current = nil if no_current + end + + # Direct access to each of the named descriptors + def stdin; @current[1]; end + def stdout; @current[2]; end + def stderr; @current[3]; end + + def shell_params + if @user.nil? + Hash.new + else + { + :user => @user, + :environment => { + 'USER' => @user, + 'HOME' => Etc.getpwnam(@user).dir + } + } + end + end + end + ::RVM::Shell.const_set('ChefWrapper', klass) + + ::RVM::Shell.default_wrapper = ::RVM::Shell::ChefWrapper +end diff --git a/chef/cookbooks/rvm/metadata.rb b/chef/cookbooks/rvm/metadata.rb new file mode 100644 index 0000000..b13bd72 --- /dev/null +++ b/chef/cookbooks/rvm/metadata.rb @@ -0,0 +1,34 @@ +name "rvm" +maintainer "Fletcher Nichol" +maintainer_email "fnichol@nichol.ca" +license "Apache 2.0" +description "Manages system-wide and per-user RVMs and manages installed Rubies. Several lightweight resources and providers (LWRP) are also defined.Installs and manages RVM. Includes several LWRPs." +long_description "Please refer to README.md (it's long)." +version "0.9.1" + +recipe "rvm", "Installs the RVM gem and initializes Chef to use the Lightweight Resources and Providers (LWRPs). Use this recipe explicitly if you only want access to the LWRPs provided." +recipe "rvm::system_install", "Installs the RVM codebase system-wide (that is, into /usr/local/rvm). This recipe includes *default*. Use this recipe by itself if you want RVM installed system-wide but want to handle installing Rubies, invoking LWRPs, etc.." +recipe "rvm::system", "Installs the RVM codebase system-wide (that is, into /usr/local/rvm) and installs Rubies, global gems, and specific gems driven off attribute metadata. This recipe includes *default* and *system_install*. Use this recipe by itself if you want RVM system-wide with Rubies installed, etc." +recipe "rvm::user_install", "Installs the RVM codebase for a list of users (selected from the node['rvm']['user_installs'] hash). This recipe includes *default*. Use this recipe by itself if you want RVM installed for specific users in isolation but want each user to handle installing Rubies, invoking LWRPs, etc." +recipe "rvm::user", "Installs the RVM codebase for a list of users (selected from the node['rvm']['user_installs'] hash) and installs Rubies, global gems, and specific gems driven off attribute metadata. This recipe includes *default* and *user_install*. Use this recipe by itself if you want RVM installed for specific users in isolation with Rubies installed, etc." +recipe "rvm::vagrant", "An optional recipe to help if running in a Vagrant virtual machine" +recipe "rvm::gem_package", "An experimental recipe that patches the gem_package resource" + +# provides chef_gem resource to chef <= 0.10.8 and fixes for chef < 10.12.0 +depends "chef_gem" + +supports "debian" +supports "ubuntu" +supports "suse" +supports "centos" +supports "amazon" +supports "redhat" +supports "fedora" +supports "mac_os_x" +supports "mac_os_x_server" + +# if using jruby, java is required on system +recommends "java" + +# for installing on OSX, this is required for installation and compilation +suggests "homebrew" diff --git a/chef/cookbooks/rvm/providers/default_ruby.rb b/chef/cookbooks/rvm/providers/default_ruby.rb new file mode 100644 index 0000000..2dfc071 --- /dev/null +++ b/chef/cookbooks/rvm/providers/default_ruby.rb @@ -0,0 +1,63 @@ +# +# Cookbook Name:: rvm +# Provider:: default_ruby +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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 Chef::RVM::StringHelpers +include Chef::RVM::EnvironmentHelpers + +def load_current_resource + @rubie = normalize_ruby_string(select_ruby(new_resource.ruby_string)) + @gemset = select_gemset(new_resource.ruby_string) + @ruby_string = @gemset.nil? ? @rubie : "#{@rubie}@#{@gemset}" + @rvm_env = ::RVM::ChefUserEnvironment.new(new_resource.user) +end + +action :create do + next if skip_ruby? + + # ensure ruby is installed and gemset exists (if specified) + unless env_exists?(@ruby_string) + e = rvm_environment @ruby_string do + user new_resource.user + action :nothing + end + e.run_action(:create) + end + + Chef::Log.info("Setting default ruby to rvm_ruby[#{@ruby_string}]") + @rvm_env.rvm :use, @ruby_string, :default => true + new_resource.updated_by_last_action(true) +end + +private + +def skip_ruby? + if @rubie.nil? + Chef::Log.warn("#{self.class.name}: RVM ruby string `#{@rubie}' " + + "is not known. Use `rvm list known` to get a full list.") + true + elsif ruby_default?(@ruby_string) + Chef::Log.debug("#{self.class.name}: `#{@ruby_string}' is already default, " + + "so skipping") + true + else + false + end +end diff --git a/chef/cookbooks/rvm/providers/environment.rb b/chef/cookbooks/rvm/providers/environment.rb new file mode 100644 index 0000000..a410fd7 --- /dev/null +++ b/chef/cookbooks/rvm/providers/environment.rb @@ -0,0 +1,77 @@ +# +# Cookbook Name:: rvm +# Provider:: environment +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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 Chef::RVM::StringHelpers +include Chef::RVM::RubyHelpers +include Chef::RVM::GemsetHelpers + +def load_current_resource + @rubie = normalize_ruby_string(select_ruby(new_resource.ruby_string)) + @gemset = select_gemset(new_resource.ruby_string) + @ruby_string = @gemset.nil? ? @rubie : "#{@rubie}@#{@gemset}" + @rvm_env = ::RVM::ChefUserEnvironment.new(new_resource.user) +end + +action :create do + next if skip_environment? + + if @gemset + gemset_resource :create + else + ruby_resource :install + end +end + +private + +def skip_environment? + if @rubie.nil? + Chef::Log.warn("#{self.class.name}: RVM ruby string `#{@rubie}' " + + "is not known. Use `rvm list known` to get a full list.") + true + else + false + end +end + +def gemset_resource(exec_action) + # ensure gemset is created, if specified + unless gemset_exists?(:ruby => @rubie, :gemset => @gemset) + r = rvm_gemset @ruby_string do + user new_resource.user + action :nothing + end + r.run_action(exec_action) + new_resource.updated_by_last_action(true) if r.updated_by_last_action? + end +end + +def ruby_resource(exec_action) + # ensure ruby is installed + unless ruby_installed?(@rubie) + r = rvm_ruby @rubie do + user new_resource.user + action :nothing + end + r.run_action(exec_action) + new_resource.updated_by_last_action(true) if r.updated_by_last_action? + end +end diff --git a/chef/cookbooks/rvm/providers/gemset.rb b/chef/cookbooks/rvm/providers/gemset.rb new file mode 100644 index 0000000..f4dd68f --- /dev/null +++ b/chef/cookbooks/rvm/providers/gemset.rb @@ -0,0 +1,118 @@ +# +# Cookbook Name:: rvm +# Provider:: gemset +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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 Chef::RVM::StringHelpers +include Chef::RVM::RubyHelpers +include Chef::RVM::GemsetHelpers + +def load_current_resource + if new_resource.ruby_string + @rubie = normalize_ruby_string(select_ruby(new_resource.ruby_string)) + @gemset = new_resource.gemset + else + @rubie = normalize_ruby_string(select_ruby(new_resource.gemset)) + @gemset = select_gemset(new_resource.gemset) + end + @ruby_string = "#{@rubie}@#{@gemset}" + @rvm_env = ::RVM::ChefUserEnvironment.new(new_resource.user) +end + +action :create do + unless ruby_installed?(@rubie) + r = rvm_ruby @rubie do + user new_resource.user + action :nothing + end + r.run_action(:install) + end + + if gemset_exists?(:ruby => @rubie, :gemset => @gemset) + Chef::Log.debug("rvm_gemset[#{@ruby_string}] already exists, so skipping") + else + Chef::Log.info("Creating rvm_gemset[#{@ruby_string}]") + + @rvm_env.use @rubie + if @rvm_env.gemset_create @gemset + update_installed_gemsets(@rubie) + Chef::Log.debug("Creation of rvm_gemset[#{@ruby_string}] was successful.") + else + Chef::Log.warn("Failed to create rvm_gemset[#{@ruby_string}].") + end + + new_resource.updated_by_last_action(true) + end +end + +action :delete do + if gemset_exists?(:ruby => @rubie, :gemset => @gemset) + Chef::Log.info("Deleting rvm_gemset[#{@ruby_string}]") + + @rvm_env.use @rubie + if @rvm_env.gemset_delete @gemset + update_installed_gemsets(@rubie) + Chef::Log.debug("Deletion of rvm_gemset[#{@ruby_string}] was successful.") + new_resource.updated_by_last_action(true) + else + Chef::Log.warn("Failed to delete rvm_gemset[#{@ruby_string}].") + end + else + Chef::Log.debug("rvm_gemset[#{@ruby_string}] does not exist, so skipping") + end +end + +action :empty do + if gemset_exists?(:ruby => @rubie, :gemset => @gemset) + Chef::Log.info("Emptying rvm_gemset[#{@ruby_string}]") + + @rvm_env.use @ruby_string + if @rvm_env.gemset_empty + update_installed_gemsets(@rubie) + Chef::Log.debug("Emptying of rvm_gemset[#{@ruby_string}] was successful.") + new_resource.updated_by_last_action(true) + else + Chef::Log.warn("Failed to empty rvm_gemset[#{@ruby_string}].") + end + else + Chef::Log.debug("rvm_gemset[#{@ruby_string}] does not exist, so skipping") + end +end + +action :update do + Chef::Log.info("Updating rvm_gemset[#{@ruby_string}]") + + # create gemset if it doesn't exist + unless gemset_exists?(:ruby => @rubie, :gemset => @gemset) + c = rvm_gemset @ruby_string do + user new_resource.user + action :nothing + end + c.run_action(:create) + end + + @rvm_env.use @ruby_string + if @rvm_env.gemset_update + update_installed_gemsets(@rubie) + Chef::Log.debug("Updating of rvm_gemset[#{@ruby_string}] was successful.") + new_resource.updated_by_last_action(true) + else + Chef::Log.warn("Failed to update rvm_gemset[#{@ruby_string}].") + end +end diff --git a/chef/cookbooks/rvm/providers/global_gem.rb b/chef/cookbooks/rvm/providers/global_gem.rb new file mode 100644 index 0000000..cccf8ab --- /dev/null +++ b/chef/cookbooks/rvm/providers/global_gem.rb @@ -0,0 +1,97 @@ +# +# Cookbook Name:: rvm +# Provider:: global_gem +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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 Chef::RVM::RubyHelpers + +def load_current_resource + @rvm_env = ::RVM::ChefUserEnvironment.new(new_resource.user) +end + +[:install, :upgrade, :remove, :purge].each do |exec_action| + action exec_action do + # add gem entry into global.gems + update_global_gems_file exec_action + + # install gem in all rubies in global gemsets + installed_rubies.each do |rubie| + gem_package_wrapper exec_action, "#{rubie}@global" + end + end +end + +private + +## +# Wraps the rvm_gem resource +# +# @param [Symbol] action to be performed with gem_package provider +# @param [optional, String, #to_s] the fully qualifed rvm string +def gem_package_wrapper(exec_action, ruby_global_gemset) + g = rvm_gem new_resource.package_name do + ruby_string ruby_global_gemset + source new_resource.source if new_resource.source + options new_resource.options if new_resource.options + version new_resource.version if new_resource.version + gem_binary new_resource.gem_binary if new_resource.gem_binary + user new_resource.user + action :nothing + end + g.run_action(exec_action) + new_resource.updated_by_last_action(true) if g.updated_by_last_action? +end + +## +# Updates global.gems file to create or remove a gem entry +# +# @oaram [Symbol] action to :create or :remove the gem from the file +def update_global_gems_file(exec_action) + gem = if new_resource.version + "#{new_resource.package_name} -v#{new_resource.version}" + else + new_resource.package_name + end + user_dir = Etc.getpwnam(new_resource.user).dir if new_resource.user + global_gems_file = if new_resource.user + "#{user_dir}/.rvm/gemsets/global.gems" + else + "#{node['rvm']['root_path']}/gemsets/global.gems" + end + + if [:install, :upgrade].include?(exec_action) + e = execute "Add #{gem} to #{global_gems_file}" do + if new_resource.user + user new_resource.user + group Etc.getpwnam(new_resource.user).gid + environment ({ 'USER' => new_resource.user, 'HOME' => user_dir }) + else + user "root" + group "rvm" + end + + command %{echo "#{gem}" >> "#{global_gems_file}"} + action :nothing + + not_if %{grep -q "^#{gem}" "#{global_gems_file}"} + end + e.run_action(:run) + new_resource.updated_by_last_action(true) if e.updated_by_last_action? + end +end diff --git a/chef/cookbooks/rvm/providers/ruby.rb b/chef/cookbooks/rvm/providers/ruby.rb new file mode 100644 index 0000000..e1e088b --- /dev/null +++ b/chef/cookbooks/rvm/providers/ruby.rb @@ -0,0 +1,176 @@ +# +# Cookbook Name:: rvm +# Provider:: ruby +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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 Chef::RVM::StringHelpers +include Chef::RVM::RubyHelpers + +def load_current_resource + @rubie = normalize_ruby_string(select_ruby(new_resource.ruby_string)) + @ruby_string = new_resource.ruby_string + @rvm_env = ::RVM::ChefUserEnvironment.new( + new_resource.user, "default", + :rvm_rubygems_version => new_resource.rubygems_version, + :source_environment => false + ) +end + +action :install do + next if skip_ruby? + + if ruby_installed?(@ruby_string) + Chef::Log.debug("rvm_ruby[#{@rubie}] is already installed, so skipping") + else + install_start = Time.now + install_options = {:rvm_by_path => true} + install_options[:patch] = new_resource.patch if new_resource.patch + + install_ruby_dependencies @rubie + + Chef::Log.info("Building rvm_ruby[#{@rubie}], this could take awhile...") + + if @rvm_env.install(@rubie, install_options) + Chef::Log.info("Installation of rvm_ruby[#{@rubie}] was successful.") + @rvm_env.use @rubie + update_installed_rubies + new_resource.updated_by_last_action(true) + + Chef::Log.info("Importing initial gemsets for rvm_ruby[#{@rubie}]") + if @rvm_env.gemset_initial + Chef::Log.debug("Initial gemsets for rvm_ruby[#{@rubie}] are installed") + else + Chef::Log.warn( + "Failed to install initial gemsets for rvm_ruby[#{@rubie}] ") + end + else + Chef::Log.warn("Failed to install rvm_ruby[#{@rubie}]. " + + "Check logs in #{::RVM.path}/log/#{@rubie}") + end + + Chef::Log.info("rvm_ruby[#{@rubie}] build time was " + + "#{(Time.now - install_start)/60.0} minutes.") + end +end + +action :uninstall do + next if skip_ruby? + + if ruby_installed?(@rubie) + Chef::Log.info("Uninstalling rvm_ruby[#{@rubie}]") + + if @rvm_env.uninstall(@rubie, :rvm_by_path => true) + update_installed_rubies + Chef::Log.debug("Uninstallation of rvm_ruby[#{@rubie}] was successful.") + new_resource.updated_by_last_action(true) + else + Chef::Log.warn("Failed to uninstall rvm_ruby[#{@rubie}]. " + + "Check logs in #{::RVM.path}/log/#{@rubie}") + end + else + Chef::Log.debug("rvm_ruby[#{@rubie}] was not installed, so skipping") + end +end + +action :remove do + next if skip_ruby? + + if ruby_installed?(@rubie) + Chef::Log.info("Removing rvm_ruby[#{@rubie}]") + + if @rvm_env.remove(@rubie, :rvm_by_path => true) + update_installed_rubies + Chef::Log.debug("Removal of rvm_ruby[#{@rubie}] was successful.") + new_resource.updated_by_last_action(true) + else + Chef::Log.warn("Failed to remove rvm_ruby[#{@rubie}]. " + + "Check logs in #{::RVM.path}/log/#{@rubie}") + end + else + Chef::Log.debug("rvm_ruby[#{@rubie}] was not installed, so skipping") + end +end + +private + +def skip_ruby? + if @rubie.nil? + Chef::Log.warn("#{self.class.name}: RVM ruby string `#{@rubie}' " + + "is not known. Use `rvm list known` to get a full list.") + true + else + false + end +end + +## +# Installs any package dependencies needed by a given ruby +# +# @param [String, #to_s] the fully qualified RVM ruby string +def install_ruby_dependencies(rubie) + pkgs = [] + case rubie + when /^ruby-/, /^ree-/, /^rbx-/, /^kiji/ + case node['platform'] + when "debian","ubuntu" + pkgs = %w{ build-essential openssl libreadline6 libreadline6-dev + zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-dev + sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev + ncurses-dev automake libtool bison ssl-cert pkg-config libgdbm-dev libffi-dev} + pkgs += %w{ subversion } if rubie =~ /^ruby-head$/ + when "suse" + pkgs = %w{ gcc-c++ patch zlib zlib-devel libffi-devel + sqlite3-devel libxml2-devel libxslt-devel } + if node['platform_version'].to_f >= 11.0 + pkgs += %w{ libreadline5 readline-devel libopenssl-devel } + else + pkgs += %w{ readline readline-devel openssl-devel } + end + pkgs += %w{ git subversion autoconf } if rubie =~ /^ruby-head$/ + when "centos","redhat","fedora","scientific","amazon" + pkgs = %w{ gcc-c++ patch readline readline-devel zlib zlib-devel + libyaml-devel libffi-devel openssl-devel + make bzip2 autoconf automake libtool bison + libxml2 libxml2-devel libxslt libxslt-devel } + pkgs += %w{ git subversion autoconf } if rubie =~ /^ruby-head$/ + end + when /^jruby/ + begin + resource_collection.find("ruby_block[update-java-alternatives]"). + run_action(:create) + rescue Chef::Exceptions::ResourceNotFound + Chef::Log.debug( + "java cookbook not loaded or not on ubuntu/debian, so skipping") + end + + # TODO: need to figure out how to pull in java recipe only when needed. For + # now, users of jruby will have to add the "java" recipe to their run_list. + #include_recipe "java" + case node['platform'] + when "debian","ubuntu" + pkgs += %w{ g++ ant } + end + end + + pkgs.each do |pkg| + package pkg do + action :nothing + end.run_action(:install) + end +end diff --git a/chef/cookbooks/rvm/providers/shell.rb b/chef/cookbooks/rvm/providers/shell.rb new file mode 100644 index 0000000..6de757b --- /dev/null +++ b/chef/cookbooks/rvm/providers/shell.rb @@ -0,0 +1,120 @@ +# +# Cookbook Name:: rvm +# Provider:: shell +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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 Chef::RVM::StringHelpers +include Chef::RVM::EnvironmentHelpers +include Chef::RVM::ShellHelpers + +def load_current_resource + @user_rvm = user_installed_rvm? ? new_resource.user : nil + @rubie = normalize_ruby_string(select_ruby(new_resource.ruby_string), @user_rvm) + @gemset = select_gemset(new_resource.ruby_string) + @ruby_string = @gemset.nil? ? @rubie : "#{@rubie}@#{@gemset}" + @rvm_env = ::RVM::ChefUserEnvironment.new(@user_rvm) +end + +action :run do + user_rvm = @user_rvm + + # ensure ruby is installed and gemset exists + unless env_exists?(@ruby_string) + e = rvm_environment @ruby_string do + user user_rvm + action :nothing + end + e.run_action(:create) + end + + script_wrapper :run +end + +private + +## +# Wraps the script resource for RVM-dependent code. +# +# @param [Symbol] action to be performed with gem_package provider +def script_wrapper(exec_action) + profile = find_profile_to_source + + script_code = <<-CODE + if [ -s "${HOME}/.rvm/scripts/rvm" ]; then + source "${HOME}/.rvm/scripts/rvm" + elif [ -s "#{profile}" ]; then + source "#{profile}" + fi + + rvm use #{@ruby_string} + + #{new_resource.code} + CODE + + if new_resource.user + user_rvm = user_installed_rvm? + user_home = user_dir + end + + s = script new_resource.name do + interpreter "bash" + + if new_resource.user + user new_resource.user + if user_rvm && new_resource.environment + environment({ 'USER' => new_resource.user, 'HOME' => user_home }.merge( + new_resource.environment)) + elsif user_rvm + environment({ 'USER' => new_resource.user, 'HOME' => user_home }) + end + end + + code script_code + creates new_resource.creates if new_resource.creates + cwd new_resource.cwd if new_resource.cwd + group new_resource.group if new_resource.group + path new_resource.path if new_resource.path + returns new_resource.returns if new_resource.returns + timeout new_resource.timeout if new_resource.timeout + umask new_resource.umask if new_resource.umask + action :nothing + end + s.run_action(exec_action) + new_resource.updated_by_last_action(true) if s.updated_by_last_action? +end + +## +# Whether or not the user has an isolated RVM installation +# +# @return [true,false] does the user have RVM installed for themselves? +def user_installed_rvm? + return false unless new_resource.user + + ::File.exists?("#{user_dir}/.rvm/VERSION") +end + +## +# Determines the user's home directory +# +# @return [String] the path to the user's home directory +def user_dir + return nil unless new_resource.user + + Etc.getpwnam(new_resource.user).dir +end diff --git a/chef/cookbooks/rvm/providers/wrapper.rb b/chef/cookbooks/rvm/providers/wrapper.rb new file mode 100644 index 0000000..fa78232 --- /dev/null +++ b/chef/cookbooks/rvm/providers/wrapper.rb @@ -0,0 +1,72 @@ +# +# Cookbook Name:: rvm +# Provider:: wrapper +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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 Chef::RVM::StringHelpers +include Chef::RVM::EnvironmentHelpers + +def load_current_resource + @rubie = normalize_ruby_string(select_ruby(new_resource.ruby_string)) + @gemset = select_gemset(new_resource.ruby_string) + @ruby_string = @gemset.nil? ? @rubie : "#{@rubie}@#{@gemset}" + @rvm_env = ::RVM::ChefUserEnvironment.new(new_resource.user) + + if new_resource.binary.nil? + @binaries = new_resource.binaries || [] + else + @binaries = [ new_resource.binary ] || [] + end +end + +action :create do + # ensure ruby is installed and gemset exists + unless env_exists?(@ruby_string) + e = rvm_environment @ruby_string do + user new_resource.user + action :nothing + end + e.run_action(:create) + end + + @rvm_env.use @ruby_string + + @binaries.each { |b| create_wrapper(b) } +end + +private + +def create_wrapper(bin) + full_bin = "#{new_resource.prefix}_#{bin}" + resource_name = "rvm_wrapper[#{full_bin}::#{@ruby_string}]" + script = ::File.join(@rvm_env.config["rvm_path"], "bin", full_bin) + + if ::File.exists?(script) + Chef::Log.debug("#{resource_name} already exists, so updating") + else + Chef::Log.info("Creating #{resource_name}") + end + + if @rvm_env.wrapper @ruby_string, new_resource.prefix, bin + Chef::Log.debug("Creation/Update of #{resource_name} was successful.") + new_resource.updated_by_last_action(true) + else + Chef::Log.warn("Failed to create/update #{resource_name}.") + end +end diff --git a/chef/cookbooks/rvm/recipes/.gitkeep b/chef/cookbooks/rvm/recipes/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/chef/cookbooks/rvm/recipes/default.rb b/chef/cookbooks/rvm/recipes/default.rb new file mode 100644 index 0000000..9ac473d --- /dev/null +++ b/chef/cookbooks/rvm/recipes/default.rb @@ -0,0 +1,40 @@ +# +# Cookbook Name:: rvm +# Recipe:: default +# +# Copyright 2010, 2011, Fletcher Nichol +# +# 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. +# + +# install rvm api gem during chef compile phase +chef_gem 'rvm' do + action :install + version '>= 1.11.3.6' +end +require 'rvm' + +create_rvm_shell_chef_wrapper +create_rvm_chef_user_environment + +class Chef::Resource + # mix in #rvm_cmd_wrap helper into resources + include Chef::RVM::ShellHelpers +end + +class Chef::Recipe + # mix in recipe helpers + include Chef::RVM::ShellHelpers + include Chef::RVM::RecipeHelpers + include Chef::RVM::StringHelpers +end diff --git a/chef/cookbooks/rvm/recipes/gem_package.rb b/chef/cookbooks/rvm/recipes/gem_package.rb new file mode 100644 index 0000000..13b712c --- /dev/null +++ b/chef/cookbooks/rvm/recipes/gem_package.rb @@ -0,0 +1,33 @@ +# +# Cookbook Name:: rvm +# Recipe:: gem_package +# +# Copyright 2011, Fletcher Nichol +# +# 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_val = node['rvm']['gem_package']['rvm_string'] +case node_val +when String + rvm_descriptor = node_val + " RVM Ruby" +when Array + last = node_val.pop + rvm_descriptor = [ node_val.join(', '), last ].join(' & ') + " RVM Rubies" +end + +patch_gem_package + +::Chef::Log.info "gem_package resource has been patched to use provider " << + "Chef::Provider::Package::RVMRubygems and will install gems to " << + "the #{rvm_descriptor}." diff --git a/chef/cookbooks/rvm/recipes/system.rb b/chef/cookbooks/rvm/recipes/system.rb new file mode 100644 index 0000000..ef00155 --- /dev/null +++ b/chef/cookbooks/rvm/recipes/system.rb @@ -0,0 +1,37 @@ +# +# Cookbook Name:: rvm +# Recipe:: system +# +# Copyright 2010, 2011 Fletcher Nichol +# +# 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 "rvm::system_install" + +perform_install_rubies = node['rvm']['install_rubies'] == true || + node['rvm']['install_rubies'] == "true" + +if perform_install_rubies + install_rubies :rubies => node['rvm']['rubies'], + :default_ruby => node['rvm']['default_ruby'], + :global_gems => node['rvm']['global_gems'], + :gems => node['rvm']['gems'] +end + +# add users to rvm group +group 'rvm' do + members node['rvm']['group_users'] + + only_if { node['rvm']['group_users'].any? } +end diff --git a/chef/cookbooks/rvm/recipes/system_install.rb b/chef/cookbooks/rvm/recipes/system_install.rb new file mode 100644 index 0000000..6f246a0 --- /dev/null +++ b/chef/cookbooks/rvm/recipes/system_install.rb @@ -0,0 +1,52 @@ +# +# Cookbook Name:: rvm +# Recipe:: system_install +# +# Copyright 2010, 2011 Fletcher Nichol +# +# 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 'rvm' + +script_flags = build_script_flags(node['rvm']['branch'], node['rvm']['version']) +upgrade_strategy = build_upgrade_strategy(node['rvm']['upgrade']) +installer_url = node['rvm']['installer_url'] +rvm_prefix = ::File.dirname(node['rvm']['root_path']) +rvm_gem_options = node['rvm']['rvm_gem_options'] +rvmrc = node['rvm']['rvmrc'] + +install_pkg_prereqs + +# Build the rvm group ahead of time, if it is set. This allows avoiding +# collision with later processes which may set a guid explicitly +if node['rvm']['group_id'] != 'default' + g = group 'rvm' do + group_name 'rvm' + gid node['rvm']['group_id'] + action :nothing + end + g.run_action(:create) +end + +rvmrc_template :rvm_prefix => rvm_prefix, + :rvm_gem_options => rvm_gem_options, + :rvmrc => rvmrc, + :rvmrc_file => "/etc/rvmrc" + +install_rvm :rvm_prefix => rvm_prefix, + :installer_url => installer_url, + :script_flags => script_flags + +upgrade_rvm :rvm_prefix => rvm_prefix, + :upgrade_strategy => upgrade_strategy diff --git a/chef/cookbooks/rvm/recipes/user.rb b/chef/cookbooks/rvm/recipes/user.rb new file mode 100644 index 0000000..eb5d8e9 --- /dev/null +++ b/chef/cookbooks/rvm/recipes/user.rb @@ -0,0 +1,43 @@ +# +# Cookbook Name:: rvm +# Recipe:: user +# +# Copyright 2011 Fletcher Nichol +# +# 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 'rvm::user_install' + +Array(node['rvm']['user_installs']).each do |rvm_user| + perform_install_rubies = rvm_user['install_rubies'] == true || + rvm_user['install_rubies'] == "true" || + node['rvm']['user_install_rubies'] == true || + node['rvm']['user_install_rubies'] == "true" + rubies = rvm_user['rubies'] || + node['rvm']['user_rubies'] + default_ruby = rvm_user['default_ruby'] || + node['rvm']['user_default_ruby'] + global_gems = rvm_user['global_gems'] || + node['rvm']['user_global_gems'] + gems = rvm_user['gems'] || + node['rvm']['user_gems'] + + if perform_install_rubies + install_rubies :rubies => rubies, + :default_ruby => default_ruby, + :global_gems => global_gems, + :gems => gems, + :user => rvm_user['user'] + end +end diff --git a/chef/cookbooks/rvm/recipes/user_install.rb b/chef/cookbooks/rvm/recipes/user_install.rb new file mode 100644 index 0000000..f685fcb --- /dev/null +++ b/chef/cookbooks/rvm/recipes/user_install.rb @@ -0,0 +1,49 @@ +# +# Cookbook Name:: rvm +# Recipe:: user_install +# +# Copyright 2011 Fletcher Nichol +# +# 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 'rvm' + +install_pkg_prereqs + +Array(node['rvm']['user_installs']).each do |rvm_user| + version = rvm_user['version'] || node['rvm']['version'] + branch = rvm_user['branch'] || node['rvm']['branch'] + + script_flags = build_script_flags(branch, version) + upgrade_strategy = build_upgrade_strategy(rvm_user['upgrade']) + installer_url = rvm_user['installer_url'] || node['rvm']['installer_url'] + rvm_prefix = rvm_user['home'] || + "#{node['rvm']['user_home_root']}/#{rvm_user['user']}" + rvm_gem_options = rvm_user['rvm_gem_options'] || node['rvm']['rvm_gem_options'] + rvmrc = rvm_user['rvmrc'] || node['rvm']['rvmrc'] + + rvmrc_template :rvm_prefix => rvm_prefix, + :rvm_gem_options => rvm_gem_options, + :rvmrc => rvmrc, + :user => rvm_user['user'] + + install_rvm :rvm_prefix => rvm_prefix, + :installer_url => installer_url, + :script_flags => script_flags, + :user => rvm_user['user'] + + upgrade_rvm :rvm_prefix => rvm_prefix, + :upgrade_strategy => upgrade_strategy, + :user => rvm_user['user'] +end diff --git a/chef/cookbooks/rvm/recipes/vagrant.rb b/chef/cookbooks/rvm/recipes/vagrant.rb new file mode 100644 index 0000000..2493ab5 --- /dev/null +++ b/chef/cookbooks/rvm/recipes/vagrant.rb @@ -0,0 +1,37 @@ +# +# Cookbook Name:: rvm +# Recipe:: vagrant +# +# Copyright 2011, Fletcher Nichol +# +# 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 "/usr/local/bin/chef-client" do + source "vagrant-chef-client-wrapper.erb" + owner "root" + group "root" + mode "0755" +end + +template "/usr/local/bin/chef-solo" do + source "vagrant-chef-solo-wrapper.erb" + owner "root" + group "root" + mode "0755" +end + +group "rvm" do + members ["vagrant"] + append true +end diff --git a/chef/cookbooks/rvm/resources/default_ruby.rb b/chef/cookbooks/rvm/resources/default_ruby.rb new file mode 100644 index 0000000..1d15e02 --- /dev/null +++ b/chef/cookbooks/rvm/resources/default_ruby.rb @@ -0,0 +1,31 @@ +# +# Cookbook Name:: rvm +# Resource:: default_ruby +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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. +# + +actions :create + +attribute :ruby_string, :kind_of => String, :name_attribute => true +attribute :user, :kind_of => String +attribute :patch, :kind_of => String + +def initialize(*args) + super + @action = :create +end diff --git a/chef/cookbooks/rvm/resources/environment.rb b/chef/cookbooks/rvm/resources/environment.rb new file mode 100644 index 0000000..8523777 --- /dev/null +++ b/chef/cookbooks/rvm/resources/environment.rb @@ -0,0 +1,31 @@ +# +# Cookbook Name:: rvm +# Resource:: environment +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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. +# + +actions :create + +attribute :ruby_string, :kind_of => String, :name_attribute => true +attribute :user, :kind_of => String +attribute :patch, :kind_of => String + +def initialize(*args) + super + @action = :create +end diff --git a/chef/cookbooks/rvm/resources/gem.rb b/chef/cookbooks/rvm/resources/gem.rb new file mode 100644 index 0000000..517327c --- /dev/null +++ b/chef/cookbooks/rvm/resources/gem.rb @@ -0,0 +1,37 @@ +# +# Cookbook Name:: rvm +# Resource:: gem +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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. +# + +actions :install, :upgrade, :remove, :purge + +attribute :package_name, :kind_of => String, :name_attribute => true +attribute :version, :kind_of => String +attribute :ruby_string, :kind_of => String, :default => "default" +attribute :response_file, :kind_of => String +attribute :source, :kind_of => String +attribute :options, :kind_of => Hash +attribute :gem_binary, :kind_of => String +attribute :user, :kind_of => String + +def initialize(*args) + super + @action = :install + @provider = Chef::Provider::Package::RVMRubygems +end diff --git a/chef/cookbooks/rvm/resources/gemset.rb b/chef/cookbooks/rvm/resources/gemset.rb new file mode 100644 index 0000000..13774e5 --- /dev/null +++ b/chef/cookbooks/rvm/resources/gemset.rb @@ -0,0 +1,32 @@ +# +# Cookbook Name:: rvm +# Resource:: gemset +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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. +# + +actions :create, :delete, :empty, :update + +attribute :gemset, :kind_of => String, :name_attribute => true +attribute :ruby_string, :kind_of => String, :regex => /^[^@]+$/ +attribute :user, :kind_of => String +attribute :patch, :kind_of => String + +def initialize(*args) + super + @action = :create +end diff --git a/chef/cookbooks/rvm/resources/global_gem.rb b/chef/cookbooks/rvm/resources/global_gem.rb new file mode 100644 index 0000000..653dd88 --- /dev/null +++ b/chef/cookbooks/rvm/resources/global_gem.rb @@ -0,0 +1,34 @@ +# +# Cookbook Name:: rvm +# Resource:: global_gem +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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. +# + +actions :install, :upgrade, :remove, :purge + +attribute :package_name, :kind_of => String, :name_attribute => true +attribute :version, :kind_of => String +attribute :source, :kind_of => String +attribute :options, :kind_of => Hash +attribute :gem_binary, :kind_of => String +attribute :user, :kind_of => String + +def initialize(*args) + super + @action = :install +end diff --git a/chef/cookbooks/rvm/resources/ruby.rb b/chef/cookbooks/rvm/resources/ruby.rb new file mode 100644 index 0000000..cd4f29b --- /dev/null +++ b/chef/cookbooks/rvm/resources/ruby.rb @@ -0,0 +1,32 @@ +# +# Cookbook Name:: rvm +# Resource:: ruby +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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. +# + +actions :install, :uninstall, :remove + +attribute :ruby_string, :kind_of => String, :name_attribute => true +attribute :user, :kind_of => String +attribute :patch, :kind_of => String +attribute :rubygems_version, :kind_of => String + +def initialize(*args) + super + @action = :install +end diff --git a/chef/cookbooks/rvm/resources/shell.rb b/chef/cookbooks/rvm/resources/shell.rb new file mode 100644 index 0000000..517213d --- /dev/null +++ b/chef/cookbooks/rvm/resources/shell.rb @@ -0,0 +1,41 @@ +# +# Cookbook Name:: rvm +# Resource:: shell +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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. +# + +actions :run + +attribute :name, :kind_of => String, :name_attribute => true +attribute :ruby_string, :kind_of => String, :default => "default" +attribute :code, :kind_of => String +attribute :creates, :kind_of => String +attribute :cwd, :kind_of => String +attribute :environment, :kind_of => Hash +attribute :group, :kind_of => String +attribute :path, :kind_of => Array +attribute :returns, :kind_of => Array, :default => [ 0 ] +attribute :timeout, :kind_of => Integer +attribute :user, :kind_of => String +attribute :umask, :kind_of => String +attribute :patch, :kind_of => String + +def initialize(*args) + super + @action = :run +end diff --git a/chef/cookbooks/rvm/resources/wrapper.rb b/chef/cookbooks/rvm/resources/wrapper.rb new file mode 100644 index 0000000..e525321 --- /dev/null +++ b/chef/cookbooks/rvm/resources/wrapper.rb @@ -0,0 +1,34 @@ +# +# Cookbook Name:: rvm +# Resource:: wrapper +# +# Author:: Fletcher Nichol +# +# Copyright 2011, Fletcher Nichol +# +# 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. +# + +actions :create + +attribute :prefix, :kind_of => String, :name_attribute => true +attribute :ruby_string, :kind_of => String +attribute :binary, :kind_of => String +attribute :binaries, :kind_of => Array +attribute :user, :kind_of => String +attribute :patch, :kind_of => String + +def initialize(*args) + super + @action = :create +end diff --git a/chef/cookbooks/rvm/templates/default/rvmrc.erb b/chef/cookbooks/rvm/templates/default/rvmrc.erb new file mode 100644 index 0000000..be17f41 --- /dev/null +++ b/chef/cookbooks/rvm/templates/default/rvmrc.erb @@ -0,0 +1,16 @@ +# rvm configuration +# +# Generated by Chef for <%= node['fqdn'] %> +# Local modifications will be overwritten. +# +<% if @root_install -%> +umask g+w +<% end -%> +export rvm_path="<%= @rvm_path %>" + +<% unless @rvm_gem_options.empty? -%> +export rvm_gem_options="<%= @rvm_gem_options %>" +<% end -%> +<% @rvmrc.each_pair do |k,v| -%> +export <%= k %>=<%= v %> +<% end -%> diff --git a/chef/cookbooks/rvm/templates/default/vagrant-chef-client-wrapper.erb b/chef/cookbooks/rvm/templates/default/vagrant-chef-client-wrapper.erb new file mode 100644 index 0000000..def9df9 --- /dev/null +++ b/chef/cookbooks/rvm/templates/default/vagrant-chef-client-wrapper.erb @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +# RVM-aware chef-client wrapper +# +# Generated by Chef for <%= node['fqdn'] %> +# Local modifications will be overridden + +if [[ -d "<%= node['rvm']['root_path'] %>" ]] ; then +export PATH="/bin:<%= node['rvm']['root_path'] %>:$PATH" + rvm_path='<%= node['rvm']['root_path'] %>' + export rvm_path + unset RUBY_VERSION + unset GEM_HOME + unset GEM_PATH + unset MY_RUBY_HOME + unset IRBRC + rvm_ruby_string='system' + export rvm_ruby_string + unset rvm_gemset_name + unset MAGLEV_HOME +fi + +exec <%= node['rvm']['vagrant']['system_chef_client'] %> "$@" diff --git a/chef/cookbooks/rvm/templates/default/vagrant-chef-solo-wrapper.erb b/chef/cookbooks/rvm/templates/default/vagrant-chef-solo-wrapper.erb new file mode 100644 index 0000000..32300ff --- /dev/null +++ b/chef/cookbooks/rvm/templates/default/vagrant-chef-solo-wrapper.erb @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +# RVM-aware chef-solo wrapper +# +# Generated by Chef for <%= node['fqdn'] %> +# Local modifications will be overridden + +if [[ -d "<%= node['rvm']['root_path'] %>" ]] ; then +export PATH="/bin:<%= node['rvm']['root_path'] %>:$PATH" + rvm_path='<%= node['rvm']['root_path'] %>' + export rvm_path + unset RUBY_VERSION + unset GEM_HOME + unset GEM_PATH + unset MY_RUBY_HOME + unset IRBRC + rvm_ruby_string='system' + export rvm_ruby_string + unset rvm_gemset_name + unset MAGLEV_HOME +fi + +exec <%= node['rvm']['vagrant']['system_chef_solo'] %> "$@" diff --git a/chef/cookbooks/rvm/test/integration/data_bags/users/virgil1.json b/chef/cookbooks/rvm/test/integration/data_bags/users/virgil1.json new file mode 100644 index 0000000..953ff29 --- /dev/null +++ b/chef/cookbooks/rvm/test/integration/data_bags/users/virgil1.json @@ -0,0 +1,4 @@ +{ + "id": "virgil1" +} + diff --git a/chef/cookbooks/rvm/test/integration/data_bags/users/virgil2.json b/chef/cookbooks/rvm/test/integration/data_bags/users/virgil2.json new file mode 100644 index 0000000..e784628 --- /dev/null +++ b/chef/cookbooks/rvm/test/integration/data_bags/users/virgil2.json @@ -0,0 +1,4 @@ +{ + "id": "virgil2" +} + diff --git a/chef/cookbooks/rvm/test/integration/data_bags/users/wigglebottom.json b/chef/cookbooks/rvm/test/integration/data_bags/users/wigglebottom.json new file mode 100644 index 0000000..6283782 --- /dev/null +++ b/chef/cookbooks/rvm/test/integration/data_bags/users/wigglebottom.json @@ -0,0 +1,3 @@ +{ + "id": "wigglebottom" +} diff --git a/chef/cookbooks/rvm/test/integration/rubies/bats/_common.bash b/chef/cookbooks/rvm/test/integration/rubies/bats/_common.bash new file mode 100644 index 0000000..dbaf837 --- /dev/null +++ b/chef/cookbooks/rvm/test/integration/rubies/bats/_common.bash @@ -0,0 +1,16 @@ +setup() { + source /etc/profile.d/rvm.sh +} + +run_nokogiri_openssl_test() { + local rubie="$1" + local https_url="https://google.com" + local requires="require 'nokogiri';" + local script="$requires puts Nokogiri::HTML(open('$https_url')).css('input')" + + run rvm $rubie do gem install nokogiri --no-ri --no-rdoc + [ "$status" -eq 0 ] + + run rvm $rubie do ruby -rrubygems -ropen-uri -e "$script" + [ "$status" -eq 0 ] +} diff --git a/chef/cookbooks/rvm/test/integration/rubies/bats/verify_1.9.3.bats b/chef/cookbooks/rvm/test/integration/rubies/bats/verify_1.9.3.bats new file mode 100644 index 0000000..6e04c40 --- /dev/null +++ b/chef/cookbooks/rvm/test/integration/rubies/bats/verify_1.9.3.bats @@ -0,0 +1,9 @@ +#!/usr/bin/env bats + +rubie="1.9.3" + +load _common + +@test "RVM $rubie can use nokogiri with openssl" { + run_nokogiri_openssl_test $rubie +} diff --git a/chef/cookbooks/rvm/test/integration/rubies/bats/verify_jruby.bats b/chef/cookbooks/rvm/test/integration/rubies/bats/verify_jruby.bats new file mode 100644 index 0000000..81cd0f4 --- /dev/null +++ b/chef/cookbooks/rvm/test/integration/rubies/bats/verify_jruby.bats @@ -0,0 +1,12 @@ +#!/usr/bin/env bats + +rubie="jruby" + +load _common + +@test "RVM $rubie can use nokogiri with openssl" { + run rvm $rubie do gem install jruby-openssl --no-ri --no-rdoc + [ $status -eq 0 ] + + run_nokogiri_openssl_test $rubie +} diff --git a/chef/cookbooks/rvm/test/integration/rubies/bats/verify_patch_support.bats b/chef/cookbooks/rvm/test/integration/rubies/bats/verify_patch_support.bats new file mode 100644 index 0000000..ca04c85 --- /dev/null +++ b/chef/cookbooks/rvm/test/integration/rubies/bats/verify_patch_support.bats @@ -0,0 +1,19 @@ +#!/usr/bin/env bats + +rubie="1.9.3-p327-railsexpress" + +load _common + +@test "RVM $rubie can use nokogiri with openssl" { + run_nokogiri_openssl_test $rubie +} + +# For more details, please see: +# https://github.com/fnichol/chef-rvm/pull/137#issuecomment-12258247 +@test "RVM $rubie can use patched functionality" { + script="puts Thread.current.thread_variable_set :foo, 'bar'" + + run rvm $rubie do ruby -e "$script" + [ "$status" -eq 0 ] + [ "$output" = "bar" ] +} diff --git a/chef/cookbooks/rvm/test/integration/rubies/bats/verify_ree.bats b/chef/cookbooks/rvm/test/integration/rubies/bats/verify_ree.bats new file mode 100644 index 0000000..68eb155 --- /dev/null +++ b/chef/cookbooks/rvm/test/integration/rubies/bats/verify_ree.bats @@ -0,0 +1,9 @@ +#!/usr/bin/env bats + +export rubie="ree" + +load _common + +@test "RVM $rubie can use nokogiri with openssl" { + run_nokogiri_openssl_test $rubie +} diff --git a/chef/cookbooks/rvm/test/integration/rubies/bats/verify_rubygems_version_support.bats b/chef/cookbooks/rvm/test/integration/rubies/bats/verify_rubygems_version_support.bats new file mode 100644 index 0000000..bbfd327 --- /dev/null +++ b/chef/cookbooks/rvm/test/integration/rubies/bats/verify_rubygems_version_support.bats @@ -0,0 +1,15 @@ +#!/usr/bin/env bats + +rubie="1.8.7" + +load _common + +@test "RVM $rubie can use nokogiri with openssl" { + run_nokogiri_openssl_test $rubie +} + +@test "Installs RubyGems 1.6.0 in RVM $rubie" { + run rvm 1.8.7 do gem --version + [ "$status" -eq 0 ] + [ "$output" = "1.6.0" ] +} diff --git a/chef/cookbooks/rvm/test/integration/rvm_versions/bats/version_pinning.bats b/chef/cookbooks/rvm/test/integration/rvm_versions/bats/version_pinning.bats new file mode 100644 index 0000000..60acd21 --- /dev/null +++ b/chef/cookbooks/rvm/test/integration/rvm_versions/bats/version_pinning.bats @@ -0,0 +1,13 @@ +#!/usr/bin/env bats + +@test "virgil1 user has rvm-1.17.10" { + run sudo -u virgil1 -i rvm version + [ $status -eq 0 ] + [ "$(echo $output | awk '{print $2}')" = "1.17.10" ] +} + +@test "virgil2 user has rvm-1.16.20" { + run sudo -u virgil2 -i rvm version + [ $status -eq 0 ] + [ "$(echo $output | awk '{print $2}')" = "1.16.20" ] +} diff --git a/chef/cookbooks/rvm/test/integration/stock_system_and_user/bats/system.bats b/chef/cookbooks/rvm/test/integration/stock_system_and_user/bats/system.bats new file mode 100644 index 0000000..6f1be2f --- /dev/null +++ b/chef/cookbooks/rvm/test/integration/stock_system_and_user/bats/system.bats @@ -0,0 +1,45 @@ +#!/usr/bin/env bats + +default_ruby="ruby-1.9.3-p194" +https_url="https://google.com" + +setup() { + source /etc/profile.d/rvm.sh +} + +@test "creates RVM directory" { + [ -d "/usr/local/rvm" ] +} + +@test "sources into environment" { + [ "$(type rvm | head -1)" = "rvm is a function" ] +} + +@test "installs $default_ruby" { + run rvm list strings + [ $status -eq 0 ] + [ $output = "$default_ruby" ] +} + +@test "sets $default_ruby as the default" { + run rvm list default string + [ $status -eq 0 ] + [ ${lines[0]} = "$default_ruby" ] +} + +@test "default Ruby can use openssl from stdlib" { + expr="puts OpenSSL::PKey::RSA.new(32).to_pem" + run rvm $default_ruby do ruby -ropenssl -e "$expr" + [ $status -eq 0 ] +} + +@test "default Ruby can install nokogiri gem" { + run rvm $default_ruby do gem install nokogiri --no-ri --no-rdoc + [ $status -eq 0 ] +} + +@test "default Ruby can use nokogiri with openssl" { + expr="puts Nokogiri::HTML(open('$https_url')).css('input')" + run rvm $default_ruby do ruby -ropen-uri -rnokogiri -e "$expr" + [ $status -eq 0 ] +} diff --git a/chef/cookbooks/rvm/test/unit/chef/rvm/recipe_helpers_spec.rb b/chef/cookbooks/rvm/test/unit/chef/rvm/recipe_helpers_spec.rb new file mode 100644 index 0000000..d31cc3f --- /dev/null +++ b/chef/cookbooks/rvm/test/unit/chef/rvm/recipe_helpers_spec.rb @@ -0,0 +1,73 @@ +# +# Cookbook Name:: rvm +# Library:: Chef::RVM::RecipeHelpers +# +# Author:: Fletcher Nichol +# +# Copyright 2013, Fletcher Nichol +# +# 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. +# + +def require_library(name) + require File.expand_path(File.join( + File.dirname(__FILE__), '../../../../libraries', "#{name}.rb" + )) +end + +require 'minitest/autorun' +require_library 'chef_rvm_recipe_helpers' + +class Dummy + include Chef::RVM::RecipeHelpers +end + +describe 'Chef::RVM::RecipeHelpers' do + + subject do + Dummy.new + end + + describe '.build_script_flags' do + + it 'sets branch and version flags' do + subject.build_script_flags("stable", "head"). + must_equal " -s -- --branch stable --version head" + end + + it 'sets a missing branch to "head"' do + subject.build_script_flags("cool"). + must_equal " -s -- --branch cool --version head" + end + + it 'only emits version with branch=stable and version=x.y.z' do + subject.build_script_flags("stable", "1.2.3"). + must_equal " -s -- --version 1.2.3" + end + + it 'only emits version with branch=master and version=x.y.z' do + subject.build_script_flags("master", "4.5.6"). + must_equal " -s -- --version 4.5.6" + end + + it 'only emits version with branch=none and version=x.y.z' do + subject.build_script_flags("none", "7.3.5"). + must_equal " -s -- --version 7.3.5" + end + + it 'emits version and branch with branch not stable|master and version=x.y.z' do + subject.build_script_flags("foo/bar", "0.9.8"). + must_equal " -s -- --branch foo/bar --version 0.9.8" + end + end +end diff --git a/readme.md b/readme.md index fa58c18..3638c60 100644 --- a/readme.md +++ b/readme.md @@ -48,6 +48,16 @@ TWITTER_CONSUMER_SECRET=your_info_here TWITTER_OAUTH_TOKEN=your_info_here TWITTER_OAUTH_TOKEN_SECRET=your_info_here ``` +### Using Vagrant + +A Vagrantfile is included for development and testing using Vagrant. + +If you already have Vagrant installed, from the Showbot directory issue +the command `vagrant up` and you will get a virtual machine with most of +the dependencies installed. You will need to ssh into the virtual machine +with `vagrant ssh`, change to the `/vagrant` directory, and run +`bundle`, `rake db:migrate`, create your `.env` file, then +`bundle exec foreman start -f Procfile.local`. ### Configuring IRC