diff --git a/.gitignore b/.gitignore index 54e2457..2046da8 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ metadata.json +.kitchen/ +.kitchen.local.yml diff --git a/.kitchen.yml b/.kitchen.yml new file mode 100644 index 0000000..a81fdf9 --- /dev/null +++ b/.kitchen.yml @@ -0,0 +1,30 @@ +--- +busser: + root_path: /var/tmp/kitchen + +driver: + name: vagrant + +provisioner: + name: chef_solo + kitchen_root: /var/tmp/kitchen + +platforms: + - name: ubuntu-12.04 + - name: centos-6.4 + +suites: + - name: package + run_list: + - recipe[redis2::default_instance] + attributes: + redis2: + install_from: package + excludes: + - centos-6.4 + - name: source + run_list: + - recipe[redis2::default_instance] + attributes: + redis2: + install_from: source diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..16f9cdb --- /dev/null +++ b/.rspec @@ -0,0 +1,2 @@ +--color +--format documentation diff --git a/Berksfile b/Berksfile index c4bb297..2e1a070 100644 --- a/Berksfile +++ b/Berksfile @@ -1,3 +1,3 @@ -site :opscode +source "https://api.berkshelf.com" metadata diff --git a/Berksfile.lock b/Berksfile.lock new file mode 100644 index 0000000..1c8d2ec --- /dev/null +++ b/Berksfile.lock @@ -0,0 +1,30 @@ +DEPENDENCIES + redis2 + path: . + metadata: true + +GRAPH + 7-zip (1.0.2) + windows (>= 1.2.2) + ark (0.9.0) + 7-zip (>= 0.0.0) + windows (>= 0.0.0) + build-essential (2.0.6) + chef_handler (1.1.6) + ohai (2.0.1) + redis2 (0.5.1) + ark (>= 0.0.0) + build-essential (>= 0.0.0) + runit (>= 1.0.0) + sysctl (>= 0.0.0) + runit (1.5.10) + build-essential (>= 0.0.0) + yum (~> 3.0) + yum-epel (>= 0.0.0) + sysctl (0.6.0) + ohai (>= 0.0.0) + windows (1.34.6) + chef_handler (>= 0.0.0) + yum (3.3.2) + yum-epel (0.5.1) + yum (~> 3.0) diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..5b7cb4b --- /dev/null +++ b/Gemfile @@ -0,0 +1,7 @@ +source 'https://rubygems.org' + +gem 'berkshelf' +gem 'test-kitchen' +gem 'busser-serverspec' +gem 'kitchen-vagrant' +gem 'chefspec' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..1097003 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,193 @@ +GEM + remote: https://rubygems.org/ + specs: + addressable (2.3.6) + berkshelf (3.1.3) + addressable (~> 2.3.4) + berkshelf-api-client (~> 1.2) + buff-config (~> 1.0) + buff-extensions (~> 1.0) + buff-shell_out (~> 0.1) + celluloid (~> 0.16.0.pre) + celluloid-io (~> 0.16.0.pre) + faraday (~> 0.9.0) + minitar (~> 0.5.4) + octokit (~> 3.0) + retryable (~> 1.3.3) + ridley (~> 4.0) + solve (~> 1.1) + thor (~> 0.18) + berkshelf-api-client (1.2.0) + faraday (~> 0.9.0) + buff-config (1.0.1) + buff-extensions (~> 1.0) + varia_model (~> 0.4) + buff-extensions (1.0.0) + buff-ignore (1.1.1) + buff-ruby_engine (0.1.0) + buff-shell_out (0.1.1) + buff-ruby_engine (~> 0.1.0) + busser (0.6.0) + thor + busser-serverspec (0.2.6) + busser + celluloid (0.16.0.pre3) + timers (~> 4.0.0) + celluloid-io (0.16.0.pre2) + celluloid (>= 0.16.0.pre) + nio4r (>= 1.0.0) + chef (11.16.2) + chef-zero (~> 2.1, >= 2.1.4) + diff-lcs (~> 1.2, >= 1.2.4) + erubis (~> 2.7) + ffi-yajl (~> 1.0) + highline (~> 1.6, >= 1.6.9) + mime-types (~> 1.16) + mixlib-authentication (~> 1.3) + mixlib-cli (~> 1.4) + mixlib-config (~> 2.0) + mixlib-log (~> 1.3) + mixlib-shellout (~> 1.4) + net-ssh (~> 2.6) + net-ssh-multi (~> 1.1) + ohai (~> 7.4) + plist (~> 3.1.0) + pry (~> 0.9) + rest-client (>= 1.0.4, <= 1.6.7) + chef-zero (2.2) + hashie (~> 2.0) + json + mixlib-log (~> 1.3) + rack + chefspec (4.0.2) + chef (~> 11.12) + fauxhai (~> 2.0) + rspec (~> 3.0) + coderay (1.1.0) + dep-selector-libgecode (1.0.2) + dep_selector (1.0.3) + dep-selector-libgecode (~> 1.0) + ffi (~> 1.9) + diff-lcs (1.2.5) + erubis (2.7.0) + faraday (0.9.0) + multipart-post (>= 1.2, < 3) + fauxhai (2.2.0) + net-ssh + ohai + ffi (1.9.3) + ffi-yajl (1.1.0) + ffi (~> 1.5) + libyajl2 (~> 1.0) + hashie (2.1.2) + highline (1.6.21) + hitimes (1.2.2) + ipaddress (0.8.0) + json (1.8.1) + kitchen-vagrant (0.15.0) + test-kitchen (~> 1.0) + libyajl2 (1.0.1) + method_source (0.8.2) + mime-types (1.25.1) + minitar (0.5.4) + mixlib-authentication (1.3.0) + mixlib-log + mixlib-cli (1.5.0) + mixlib-config (2.1.0) + mixlib-log (1.6.0) + mixlib-shellout (1.4.0) + multipart-post (2.0.0) + net-http-persistent (2.9.4) + net-scp (1.2.1) + net-ssh (>= 2.6.5) + net-ssh (2.9.1) + net-ssh-gateway (1.2.0) + net-ssh (>= 2.6.5) + net-ssh-multi (1.2.0) + net-ssh (>= 2.6.5) + net-ssh-gateway (>= 1.2.0) + nio4r (1.0.0) + octokit (3.2.0) + sawyer (~> 0.5.3) + ohai (7.4.0) + ffi (~> 1.9) + ffi-yajl (~> 1.0) + ipaddress + mime-types (~> 1.16) + mixlib-cli + mixlib-config (~> 2.0) + mixlib-log + mixlib-shellout (~> 1.2) + systemu (~> 2.6.4) + wmi-lite (~> 1.0) + plist (3.1.0) + pry (0.10.1) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) + rack (1.5.2) + rest-client (1.6.7) + mime-types (>= 1.16) + retryable (1.3.5) + ridley (4.0.0) + addressable + buff-config (~> 1.0) + buff-extensions (~> 1.0) + buff-ignore (~> 1.1) + buff-shell_out (~> 0.1) + celluloid (~> 0.16.0.pre) + celluloid-io (~> 0.16.0.pre) + erubis + faraday (~> 0.9.0) + hashie (>= 2.0.2, < 3.0.0) + json (>= 1.7.7) + mixlib-authentication (>= 1.3.0) + net-http-persistent (>= 2.8) + retryable + semverse (~> 1.1) + varia_model (~> 0.4) + rspec (3.1.0) + rspec-core (~> 3.1.0) + rspec-expectations (~> 3.1.0) + rspec-mocks (~> 3.1.0) + rspec-core (3.1.5) + rspec-support (~> 3.1.0) + rspec-expectations (3.1.2) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.1.0) + rspec-mocks (3.1.2) + rspec-support (~> 3.1.0) + rspec-support (3.1.1) + safe_yaml (1.0.3) + sawyer (0.5.4) + addressable (~> 2.3.5) + faraday (~> 0.8, < 0.10) + semverse (1.2.1) + slop (3.6.0) + solve (1.2.0) + dep_selector (~> 1.0) + semverse (~> 1.1) + systemu (2.6.4) + test-kitchen (1.2.1) + mixlib-shellout (~> 1.2) + net-scp (~> 1.1) + net-ssh (~> 2.7) + safe_yaml (~> 1.0) + thor (~> 0.18) + thor (0.19.1) + timers (4.0.0) + hitimes + varia_model (0.4.0) + buff-extensions (~> 1.0) + hashie (>= 2.0.2, < 3.0.0) + wmi-lite (1.0.0) + +PLATFORMS + ruby + +DEPENDENCIES + berkshelf + busser-serverspec + chefspec + kitchen-vagrant + test-kitchen diff --git a/README.rdoc b/README.rdoc index 3caac9d..a6990b5 100644 --- a/README.rdoc +++ b/README.rdoc @@ -17,10 +17,11 @@ redis_instance "datastore" do port 8866 data_dir "/mnt/redis/datastore" master master_node + nofile 16384 end -_port_, data_dir and _master_ are the only attributes directly configurable using the definition syntax. Other attributes can be configured using the normal attribute interface under the node["redis2"]["instances"][instance_name] scope. Missing attributes will be merged from node["redis2"]["instances"]["default"] +_nofile_, _port_, data_dir and _master_ are the only attributes directly configurable using the definition syntax. Other attributes can be configured using the normal attribute interface under the node["redis2"]["instances"][instance_name] scope. Missing attributes will be merged from node["redis2"]["instances"]["default"] The _master_ attribute will set up redis as a slave of a the same redis instance on another server. It will not set node["redis2"]["instances"][instance_name]["replication"]["role"] (which can be _slave_ or _master_), because redis can be both at the same time (e.g. chained masters). diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..e9449f6 --- /dev/null +++ b/Rakefile @@ -0,0 +1,24 @@ +require 'rake' +require 'rspec/core/rake_task' + +task :spec => 'spec:all' +task :default => :spec + +namespace :spec do + targets = [] + Dir.glob('./spec/*').each do |dir| + next unless File.directory?(dir) + targets << File.basename(dir) + end + + task :all => targets + task :default => :all + + targets.each do |target| + desc "Run serverspec tests to #{target}" + RSpec::Core::RakeTask.new(target.to_sym) do |t| + ENV['TARGET_HOST'] = target + t.pattern = "spec/#{target}/*_spec.rb" + end + end +end diff --git a/Thorfile b/Thorfile new file mode 100644 index 0000000..b23ee16 --- /dev/null +++ b/Thorfile @@ -0,0 +1,12 @@ +# encoding: utf-8 + +require 'bundler' +require 'bundler/setup' +require 'berkshelf/thor' + +begin + require 'kitchen/thor_tasks' + Kitchen::ThorTasks.new +rescue LoadError + puts ">>>>> Kitchen gem not loaded, omitting tasks" unless ENV['CI'] +end diff --git a/chefignore b/chefignore new file mode 100644 index 0000000..a6de142 --- /dev/null +++ b/chefignore @@ -0,0 +1,96 @@ +# Put files/directories that should be ignored in this file when uploading +# or sharing to the community site. +# Lines that start with '# ' are comments. + +# OS generated files # +###################### +.DS_Store +Icon? +nohup.out +ehthumbs.db +Thumbs.db + +# SASS # +######## +.sass-cache + +# EDITORS # +########### +\#* +.#* +*~ +*.sw[a-z] +*.bak +REVISION +TAGS* +tmtags +*_flymake.* +*_flymake +*.tmproj +.project +.settings +mkmf.log + +## COMPILED ## +############## +a.out +*.o +*.pyc +*.so +*.com +*.class +*.dll +*.exe +*/rdoc/ + +# Testing # +########### +.watchr +.rspec +spec/* +spec/fixtures/* +test/* +features/* +Guardfile +Procfile + +# SCM # +####### +.git +*/.git +.gitignore +.gitmodules +.gitconfig +.gitattributes +.svn +*/.bzr/* +*/.hg/* +*/.svn/* + +# Berkshelf # +############# +Berksfile +Berksfile.lock +cookbooks/* +tmp + +# Cookbooks # +############# +CONTRIBUTING +CHANGELOG* + +# Strainer # +############ +Colanderfile +Strainerfile +.colander +.strainer + +# Vagrant # +########### +.vagrant +Vagrantfile + +# Travis # +########## +.travis.yml diff --git a/definitions/instance.rb b/definitions/instance.rb index d69ae51..5252c58 100644 --- a/definitions/instance.rb +++ b/definitions/instance.rb @@ -1,4 +1,10 @@ -define :redis_instance, :port => nil, :data_dir => nil, :master => nil, :service_timeouts => Hash.new do +define(:redis_instance, + :port => nil, + :data_dir => nil, + :master => nil, + :service_timeouts => Hash.new, + :nofile => 16384 +) do raise ::Chef::Exceptions::InvalidResourceSpecification, "redis instance name can't be \"default\"" \ if params[:name] == "default" include_recipe "redis2" @@ -75,9 +81,10 @@ log_template_name "redis" cookbook "redis2" options \ - :user => node["redis2"]["user"], + :user => node["redis2"]["user"], :config_file => ::File.join(node["redis2"]["conf_dir"], "#{instance_name}.conf"), - :timeouts => uplevel_params[:service_timeouts] + :timeouts => uplevel_params[:service_timeouts], + :nofile => uplevel_params[:nofile] end end diff --git a/metadata.rb b/metadata.rb index 95a1c5a..300fc8d 100644 --- a/metadata.rb +++ b/metadata.rb @@ -4,7 +4,7 @@ description "Installs/Configures redis" long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) name "redis2" -version "0.5.0" +version "0.5.1" supports "ubuntu", ">= 9.04" supports "debian", ">= 6.0" @@ -13,6 +13,7 @@ depends "runit", ">= 1.0.0" depends "build-essential" depends "ark" +depends "sysctl" recipe "redis2", "Installs and configures redis" recipe "redis2::auto", "Configures and activates redis instances defined by attributes" diff --git a/recipes/default.rb b/recipes/default.rb index b98a86e..f6e8052 100644 --- a/recipes/default.rb +++ b/recipes/default.rb @@ -17,6 +17,12 @@ # limitations under the License. # include_recipe "runit" +include_recipe "sysctl" + +sysctl_param "vm.overcommit_memory" do + value 1 +end + if node["redis2"]["install_from"] == "package" include_recipe "redis2::package" else diff --git a/spec/redis2_spec.rb b/spec/redis2_spec.rb new file mode 100644 index 0000000..8c34354 --- /dev/null +++ b/spec/redis2_spec.rb @@ -0,0 +1,34 @@ +require_relative 'spec_helper' + +describe "redis2::default" do + let(:chef_run) { ChefSpec::Runner.new } + + it "Runs redis2::source and correctly sets node['redis2']['daemon']" do + chef_run.node.set['redis2']['install_from'] = "source" + chef_run.converge(described_recipe) + expect(chef_run).to include_recipe("redis2::source") + expect(chef_run.node["redis2"]["daemon"]).to eq("/usr/local/bin/redis-server") + end + + it "Runs redis2::package if install_from is set to package" do + chef_run.node.set['redis2']['install_from'] = "package" + chef_run.converge(described_recipe) + expect(chef_run).to include_recipe("redis2::package") + end +end + +describe "redis2::package" do + let(:chef_run) { ChefSpec::Runner.new.converge(described_recipe) } + it "Install redis package" do + expect(chef_run).to install_package("redis-server") + end +end + +describe "redis2::default_instance" do + let(:chef_run) { ChefSpec::Runner.new.converge(described_recipe) } + it "Install redis-prime instance" do + #expect(chef_run).to enable_runit_service("redis_prime") + #expect(chef_run).to start_runit_service("redis_prime") + expect(chef_run).to create_directory("/var/lib/redis/prime") + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..cbd550c --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,24 @@ +require 'chefspec' +require 'chefspec/berkshelf' +ChefSpec::Coverage.start! + +RSpec.configure do |config| + # Specify the path for Chef Solo to find cookbooks (default: [inferred from + # the location of the calling spec file]) + #config.cookbook_path = 'berks-cookbooks' + + # Specify the path for Chef Solo to find roles (default: [ascending search]) + #config.role_path = 'roles' + + # Specify the Chef log_level (default: :warn) + #config.log_level = :warn + + # Specify the path to a local JSON file with Ohai data (default: nil) + #config.path = 'ohai.json' + + # Specify the operating platform to mock Ohai data from (default: nil) + config.platform = 'ubuntu' + + # Specify the operating version to mock Ohai data from (default: nil) + config.version = '12.04' +end diff --git a/templates/default/sv-redis-run.erb b/templates/default/sv-redis-run.erb index 7276c33..7241800 100644 --- a/templates/default/sv-redis-run.erb +++ b/templates/default/sv-redis-run.erb @@ -1,3 +1,3 @@ #!/bin/sh exec 2>&1 -exec chpst -u <%= @options[:user] %> <%= node["redis2"]["daemon"] %> <%= @options[:config_file] %> +exec chpst -o <%= @options[:nofile] %> -u <%= @options[:user] %> <%= node["redis2"]["daemon"] %> <%= @options[:config_file] %> diff --git a/test/integration/helpers/serverspec/main.rb b/test/integration/helpers/serverspec/main.rb new file mode 100644 index 0000000..54812f8 --- /dev/null +++ b/test/integration/helpers/serverspec/main.rb @@ -0,0 +1,49 @@ +require 'serverspec' + +set :backend, :exec + +shared_examples 'redis::default' do + describe "Redis instances pre-requisites" do + describe file("/etc/redis") do + it { should be_directory } + it { should be_owned_by "root" } + it { should be_mode "755" } + end + + describe file("/var/lib/redis") do + it { should be_directory } + it { should be_owned_by "redis" } + it { should be_mode "750" } + end + + describe file("/var/log/redis") do + it { should be_directory } + it { should be_owned_by "redis" } + it { should be_mode "750" } + end + end + + describe "Redis prime instance" do + + it "should have a data directory" do + expect(file("/var/lib/redis/prime")).to be_directory + expect(file("/var/lib/redis/prime")).to be_owned_by("redis") + expect(file("/var/lib/redis/prime")).to be_mode("750") + end + + it "should have a log file" do + expect(file("/var/log/redis/redis_prime.log")).to be_file + expect(file("/var/log/redis/redis_prime.log")).to be_owned_by("redis") + expect(file("/var/log/redis/redis_prime.log")).to be_mode("644") + end + + it "is listening on port 6379" do + expect(port(6379)).to be_listening + end + + it "has a running service of redis-prime" do + expect(service("redis-server")).to be_running + end + + end +end diff --git a/test/integration/helpers/serverspec/spec_helper.rb b/test/integration/helpers/serverspec/spec_helper.rb new file mode 100644 index 0000000..081a5d7 --- /dev/null +++ b/test/integration/helpers/serverspec/spec_helper.rb @@ -0,0 +1,5 @@ +require 'serverspec' +require_relative 'main' + +set :backend, :exec + diff --git a/test/integration/package/serverspec/.redis_server_spec.rb.swp b/test/integration/package/serverspec/.redis_server_spec.rb.swp new file mode 100644 index 0000000..f48e52e Binary files /dev/null and b/test/integration/package/serverspec/.redis_server_spec.rb.swp differ diff --git a/test/integration/package/serverspec/redis_server_spec.rb b/test/integration/package/serverspec/redis_server_spec.rb new file mode 100644 index 0000000..c31dbac --- /dev/null +++ b/test/integration/package/serverspec/redis_server_spec.rb @@ -0,0 +1,13 @@ +require_relative 'spec_helper' + +describe "Redis prime instance" do + include_examples "redis::default" + + it "should install package" do + expect(package("redis-server")).to be_installed + end + + describe process("redis-server") do + its(:args) { should match /\/etc\/redis\/redis_prime.conf/ } + end +end diff --git a/test/integration/source/serverspec/redis_server_spec.rb b/test/integration/source/serverspec/redis_server_spec.rb new file mode 100644 index 0000000..847e17e --- /dev/null +++ b/test/integration/source/serverspec/redis_server_spec.rb @@ -0,0 +1,14 @@ +require_relative 'spec_helper' + +describe "Redis prime instance" do + include_examples "redis::default" + + it "should install redis binary from source" do + expect(file("/usr/local/bin/redis-server")).to be_file + expect(file("/usr/local/bin/redis-server")).to be_mode "755" + end + + describe process("redis-server") do + its(:args) { should match /0.0.0.0:6379/ } + end +end