diff --git a/.kitchen.cloud.yml b/.kitchen.cloud.yml new file mode 100644 index 0000000..6b86dd8 --- /dev/null +++ b/.kitchen.cloud.yml @@ -0,0 +1,72 @@ +--- +driver_plugin: vagrant +driver_plugin: digitalocean +driver_config: + digitalocean_client_id: <%= ENV['DIGITAL_OCEAN_CLIENT_ID'] %> + digitalocean_api_key: <%= ENV['DIGITAL_OCEAN_API_KEY'] %> + aws_access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %> + aws_secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %> + aws_ssh_key_id: <%= ENV['AWS_KEYPAIR_NAME'] %> + ssh_key: <%= ENV['AWS_PRIVATE_KEY_PATH'] %> + rackspace_username: <%= ENV['RACKSPACE_USERNAME'] %> + rackspace_api_key: <%= ENV['RACKSPACE_API_KEY'] %> + require_chef_omnibus: latest + +platforms: +- name: centos-5.8 + driver_plugin: digitalocean + driver_config: + image_id: 1601 + flavor_id: 63 + region_id: 1 + ssh_key_ids: <%= ENV['DIGITAL_OCEAN_SSH_KEY_IDS'] %> + +- name: centos-6.4 + driver_plugin: digitalocean + driver_config: + image_id: 562354 + flavor_id: 63 + region_id: 1 + ssh_key_ids: <%= ENV['DIGITAL_OCEAN_SSH_KEY_IDS'] %> + +- name: amazon-2013.09 + driver_plugin: ec2 + driver_config: + image_id: ami-3be4bc52 + username: ec2-user + +# - name: fedora-19 +# driver_plugin: digitalocean +# driver_config: +# image_id: 696598 +# flavor_id: 63 +# region_id: 1 +# ssh_key_ids: <%= ENV['DIGITAL_OCEAN_SSH_KEY_IDS'] %> + +- name: ubuntu-1004 + driver_plugin: digitalocean + driver_config: + image_id: 14097 + flavor_id: 63 + region_id: 1 + ssh_key_ids: <%= ENV['DIGITAL_OCEAN_SSH_KEY_IDS'] %> + run_list: + - recipe[apt] + +- name: ubuntu-1204 + driver_plugin: digitalocean + driver_config: + image_id: 1505447 + flavor_id: 63 + region_id: 1 + ssh_key_ids: <%= ENV['DIGITAL_OCEAN_SSH_KEY_IDS'] %> + run_list: + - recipe[apt] + +suites: + - name: default + run_list: + - recipe[memcached::default] + - name: instance + run_list: + - recipe[fake::instance] diff --git a/.kitchen.yml b/.kitchen.yml index 6b86dd8..b30d4de 100644 --- a/.kitchen.yml +++ b/.kitchen.yml @@ -1,65 +1,23 @@ --- driver_plugin: vagrant -driver_plugin: digitalocean -driver_config: - digitalocean_client_id: <%= ENV['DIGITAL_OCEAN_CLIENT_ID'] %> - digitalocean_api_key: <%= ENV['DIGITAL_OCEAN_API_KEY'] %> - aws_access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %> - aws_secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %> - aws_ssh_key_id: <%= ENV['AWS_KEYPAIR_NAME'] %> - ssh_key: <%= ENV['AWS_PRIVATE_KEY_PATH'] %> - rackspace_username: <%= ENV['RACKSPACE_USERNAME'] %> - rackspace_api_key: <%= ENV['RACKSPACE_API_KEY'] %> - require_chef_omnibus: latest -platforms: -- name: centos-5.8 - driver_plugin: digitalocean - driver_config: - image_id: 1601 - flavor_id: 63 - region_id: 1 - ssh_key_ids: <%= ENV['DIGITAL_OCEAN_SSH_KEY_IDS'] %> +provisioner: + name: chef_zero -- name: centos-6.4 - driver_plugin: digitalocean - driver_config: - image_id: 562354 - flavor_id: 63 - region_id: 1 - ssh_key_ids: <%= ENV['DIGITAL_OCEAN_SSH_KEY_IDS'] %> +platforms: +- name: centos-5.10 -- name: amazon-2013.09 - driver_plugin: ec2 - driver_config: - image_id: ami-3be4bc52 - username: ec2-user +- name: centos-6.6 -# - name: fedora-19 -# driver_plugin: digitalocean -# driver_config: -# image_id: 696598 -# flavor_id: 63 -# region_id: 1 -# ssh_key_ids: <%= ENV['DIGITAL_OCEAN_SSH_KEY_IDS'] %> +- name: ubuntu-10.04 + run_list: + - recipe[apt] -- name: ubuntu-1004 - driver_plugin: digitalocean - driver_config: - image_id: 14097 - flavor_id: 63 - region_id: 1 - ssh_key_ids: <%= ENV['DIGITAL_OCEAN_SSH_KEY_IDS'] %> +- name: ubuntu-12.04 run_list: - recipe[apt] -- name: ubuntu-1204 - driver_plugin: digitalocean - driver_config: - image_id: 1505447 - flavor_id: 63 - region_id: 1 - ssh_key_ids: <%= ENV['DIGITAL_OCEAN_SSH_KEY_IDS'] %> +- name: ubuntu-14.04 run_list: - recipe[apt] diff --git a/Berksfile b/Berksfile index b3df8b4..4c06e45 100644 --- a/Berksfile +++ b/Berksfile @@ -1,4 +1,4 @@ -site 'https://supermarket.chef.io' +source 'https://supermarket.chef.io' metadata group :integration do diff --git a/README.md b/README.md index 042e3b1..d41bbc6 100644 --- a/README.md +++ b/README.md @@ -35,15 +35,17 @@ The following are node attributes passed to the template for the runit service. - `memcached['maxconn']` - maximum number of connections to accept (defaults to 1024) - `memcached['max_object_size']` - maximum size of an object to cache (defaults to 1MB) - `memcached['logfilename']` - logfile to which memcached output will be redirected in /var/log/$logfilename. - +- `memcached['threads']` - Number of threads to use to process incoming requests. The default is 4. +- `memcached['experimental_options']` - Comma separated list of extended or experimental options. (array) +- `memcached['ulimit']` - boolean `true` will set the ulimit to the `maxconn` value Usage ----- Simply set the attributes and it will configure the `/etc/memcached.conf` file. If you want to use multiple memcached instances, you'll need to modify the recipe to disable the startup script and the template in the default recipe. -Use the definition, `memcached_instance`, to set up a runit service for the named memcached instance. +Use the definition, `memcached_instance`, to set up a runit service for the named memcached instance. (If the instance name is `memcached` the service name will be `memcached` otherwise it will be `memcached-#{service_name}`) -```ruby +``` memcached_instance 'myproj' ``` diff --git a/attributes/default.rb b/attributes/default.rb index cedac73..d0e9426 100644 --- a/attributes/default.rb +++ b/attributes/default.rb @@ -17,12 +17,14 @@ # limitations under the License. # +default['memcached']['version'] = nil default['memcached']['memory'] = 64 default['memcached']['port'] = 11_211 default['memcached']['udp_port'] = 11_211 default['memcached']['listen'] = '0.0.0.0' default['memcached']['maxconn'] = 1024 default['memcached']['max_object_size'] = '1m' +default['memcached']['logfilepath'] = '/var/log/' default['memcached']['logfilename'] = 'memcached.log' case node['platform_family'] diff --git a/definitions/memcached_instance.rb b/definitions/memcached_instance.rb index 983d07d..d763e10 100644 --- a/definitions/memcached_instance.rb +++ b/definitions/memcached_instance.rb @@ -18,21 +18,28 @@ # define :memcached_instance do - include_recipe 'runit::default' - include_recipe 'memcached::default' + include_recipe 'runit' + include_recipe 'memcached::package' + + instance_name = params[:name] == 'memcached' || params[:name] == nil ? 'memcached' : "memcached-#{params[:name]}" opts = params - runit_service "memcached-#{params[:name]}" do + runit_service instance_name do run_template_name 'memcached' default_logger true cookbook 'memcached' options({ - :memory => node['memcached']['memory'], - :port => node['memcached']['port'], - :listen => node['memcached']['listen'], - :maxconn => node['memcached']['maxconn'], - :user => node['memcached']['user'] + :memory => node['memcached']['memory'], + :port => node['memcached']['port'], + :udp_port => node['memcached']['udp_port'], + :listen => node['memcached']['listen'], + :maxconn => node['memcached']['maxconn'], + :user => node['memcached']['user'], + :threads => node['memcached']['threads'], + :max_object_size => node['memcached']['max_object_size'], + :experimental_options => Array(node['memcached']['experimental_options']), + :ulimit => node['memcached']['ulimit'] }.merge(opts)) end -end + end diff --git a/recipes/configure.rb b/recipes/configure.rb new file mode 100644 index 0000000..301b477 --- /dev/null +++ b/recipes/configure.rb @@ -0,0 +1,77 @@ +# +# Cookbook Name:: memcached +# Recipe:: default +# +# Copyright 2009-2013, Chef Software, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +directory node['memcached']['logfilepath'] + +service 'memcached' do + action :enable + supports :status => true, :start => true, :stop => true, :restart => true, :enable => true +end + +case node['platform_family'] +when 'rhel', 'fedora', 'suse' + family = node['platform_family'] == 'suse' ? 'suse' : 'redhat' + template '/etc/sysconfig/memcached' do + source "memcached.sysconfig.#{family}.erb" + owner 'root' + group 'root' + mode '0644' + variables( + :listen => node['memcached']['listen'], + :user => node['memcached']['user'], + :group => node['memcached']['group'], + :port => node['memcached']['port'], + :udp_port => node['memcached']['udp_port'], + :maxconn => node['memcached']['maxconn'], + :memory => node['memcached']['memory'], + :logfilepath => node['memcached']['logfilepath'], + :logfilename => node['memcached']['logfilename'], + :threads => node['memcached']['threads'], + :max_object_size => node['memcached']['max_object_size'] + ) + notifies :restart, 'service[memcached]' + end +when 'smartos' + # SMF directly configures memcached with no opportunity to alter settings + # If you need custom parameters, use the memcached_instance provider + service 'memcached' do + action :enable + end +else + template '/etc/memcached.conf' do + source 'memcached.conf.erb' + owner 'root' + group 'root' + mode '0644' + variables( + :listen => node['memcached']['listen'], + :user => node['memcached']['user'], + :port => node['memcached']['port'], + :udp_port => node['memcached']['udp_port'], + :maxconn => node['memcached']['maxconn'], + :memory => node['memcached']['memory'], + :logfilepath => node['memcached']['logfilepath'], + :logfilename => node['memcached']['logfilename'], + :threads => node['memcached']['threads'], + :max_object_size => node['memcached']['max_object_size'], + :experimental_options => Array(node['memcached']['experimental_options']) + ) + notifies :restart, 'service[memcached]' + end +end diff --git a/recipes/default.rb b/recipes/default.rb index 5082729..50f3a11 100644 --- a/recipes/default.rb +++ b/recipes/default.rb @@ -17,75 +17,5 @@ # limitations under the License. # -# include epel on redhat/centos 5 and below in order to get the memcached packages -include_recipe 'yum-epel' if node['platform_family'] == 'rhel' && node['platform_version'].to_i == 5 - -package 'memcached' - -package 'libmemcache-dev' do - case node['platform_family'] - when 'rhel', 'fedora' - package_name 'libmemcached-devel' - when 'smartos' - package_name 'libmemcached' - when 'suse' - if node['platform_version'].to_f < 12 - package_name 'libmemcache-devel' - else - package_name 'libmemcached-devel' - end - else - package_name 'libmemcache-dev' - end -end - -service 'memcached' do - action :enable - supports :status => true, :start => true, :stop => true, :restart => true, :enable => true -end - -case node['platform_family'] -when 'rhel', 'fedora', 'suse' - family = node['platform_family'] == 'suse' ? 'suse' : 'redhat' - template '/etc/sysconfig/memcached' do - source "memcached.sysconfig.#{family}.erb" - owner 'root' - group 'root' - mode '0644' - variables( - :listen => node['memcached']['listen'], - :user => node['memcached']['user'], - :group => node['memcached']['group'], - :port => node['memcached']['port'], - :udp_port => node['memcached']['udp_port'], - :maxconn => node['memcached']['maxconn'], - :memory => node['memcached']['memory'], - :max_object_size => node['memcached']['max_object_size'], - :logfilename => node['memcached']['logfilename'] - ) - notifies :restart, 'service[memcached]' - end -when 'smartos' - # SMF directly configures memcached with no opportunity to alter settings - # If you need custom parameters, use the memcached_instance provider - service 'memcached' do - action :enable - end -else - template '/etc/memcached.conf' do - source 'memcached.conf.erb' - owner 'root' - group 'root' - mode '0644' - variables( - :listen => node['memcached']['listen'], - :user => node['memcached']['user'], - :port => node['memcached']['port'], - :udp_port => node['memcached']['udp_port'], - :maxconn => node['memcached']['maxconn'], - :memory => node['memcached']['memory'], - :max_object_size => node['memcached']['max_object_size'] - ) - notifies :restart, 'service[memcached]' - end -end +include_recipe 'memcached::package' +include_recipe 'memcached::configure' diff --git a/recipes/package.rb b/recipes/package.rb new file mode 100644 index 0000000..fcade0c --- /dev/null +++ b/recipes/package.rb @@ -0,0 +1,64 @@ +# +# Cookbook Name:: memcached +# Recipe:: default +# +# Copyright 2009-2013, Chef Software, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# include epel on redhat/centos 5 and below in order to get the memcached packages +include_recipe 'yum-epel' if node['platform_family'] == 'rhel' && node['platform_version'].to_i == 5 + +if node['platform_family'] == 'debian' && shell_out('dpkg -l memcached | grep "^ii memcached"').error? + # dpkg, imma let you finish but don't start services automatically + # https://jpetazzo.github.io/2013/10/06/policy-rc-d-do-not-start-services-automatically/ + execute 'disable auto-start' do + command 'echo exit 101 > /usr/sbin/policy-rc.d ; chmod +x /usr/sbin/policy-rc.d' + end + + package 'memcached' do + version node['memcached']['version'] + action :install + end + + execute 'undo service disable hack' do + command 'echo exit 0 > /usr/sbin/policy-rc.d' + end + +else + package 'memcached' do + version node['memcached']['version'] + action :install + end +end + + +package 'libmemcache-dev' do + case node['platform_family'] + when 'rhel', 'fedora' + package_name 'libmemcached-devel' + when 'smartos' + package_name 'libmemcached' + when 'suse' + if node['platform_version'].to_f < 12 + package_name 'libmemcache-devel' + else + package_name 'libmemcached-devel' + end + when 'debian' + package_name 'libmemcached-dev' + else + package_name 'libmemcache-dev' + end +end diff --git a/templates/default/memcached.conf.erb b/templates/default/memcached.conf.erb index 9455979..78b7f76 100644 --- a/templates/default/memcached.conf.erb +++ b/templates/default/memcached.conf.erb @@ -12,7 +12,7 @@ -d # Log memcached's output to /var/log/memcached -logfile /var/log/memcached.log +logfile <%= @logfilepath %><%= @logfilename %> # Be verbose -v @@ -52,3 +52,9 @@ logfile /var/log/memcached.log # Max object size -I <%= @max_object_size %> + +# Number of threads to use to process incoming requests. The default is 4. +<% if @threads %>-t <%= @threads %><% end %> + +# Comma separated list of extended or experimental options. +<% if @experimental_options.any? %>-o <%= @experimental_options.join(', ') %><% end %> diff --git a/templates/default/memcached.sysconfig.redhat.erb b/templates/default/memcached.sysconfig.redhat.erb index 98cde35..9f1d422 100644 --- a/templates/default/memcached.sysconfig.redhat.erb +++ b/templates/default/memcached.sysconfig.redhat.erb @@ -10,4 +10,4 @@ PORT="<%= @port %>" USER="<%= @user %>" MAXCONN="<%= @maxconn %>" CACHESIZE="<%= @memory %>" -OPTIONS="-U <%= @udp_port %> -l <%= @listen %> -I <%= @max_object_size %> >> /var/log/<%= @logfilename %> 2>&1" +OPTIONS="-U <%= @udp_port %> -l <%= @listen %> -I <%= @max_object_size %> <% if @threads %>-t <%= @threads %><% end %> >> /var/log/<%= @logfilename %> 2>&1" diff --git a/templates/default/sv-memcached-run.erb b/templates/default/sv-memcached-run.erb index 01c68ad..780c55d 100644 --- a/templates/default/sv-memcached-run.erb +++ b/templates/default/sv-memcached-run.erb @@ -1,3 +1,17 @@ #!/bin/sh exec 2>&1 -exec chpst -u <%= @options[:user] %> /usr/bin/memcached -v -m <%= @options[:memory] %> -U <%= @options[:udp_port] %> -p <%= @options[:port] %> -u <%= @options[:user] %> -l <%= @options[:listen] %> -c <%= @options[:maxconn] %> + +<% if @options[:ulimit] == true %>ulimit -n <%= @options[:maxconn] %><% end %> + +exec chpst -u <%= @options[:user] %> \ + /usr/bin/memcached -v \ + -m <%= @options[:memory] %> \ + -U <%= @options[:udp_port] %> \ + -p <%= @options[:port] %> \ + -u <%= @options[:user] %> \ + -l <%= @options[:listen] %> \ + -c <%= @options[:maxconn] %> \ + -I <%= @options[:max_object_size] %><% if @options[:experimental_options].any? %> \ + -o <%= @options[:experimental_options].join(', ') %><% end %><% if @options[:threads] %> \ + -t <%= @options[:threads] %> + <% end %> diff --git a/test/fixtures/cookbooks/fake/recipes/instance.rb b/test/fixtures/cookbooks/fake/recipes/instance.rb index 5fd0574..c89cdf4 100644 --- a/test/fixtures/cookbooks/fake/recipes/instance.rb +++ b/test/fixtures/cookbooks/fake/recipes/instance.rb @@ -1,9 +1,9 @@ -include_recipe 'memcached::default' +#include_recipe 'memcached::default' # m = resources('service[memcached]') # m.action :stop -memcached_instance 'myproj' do - port 11_212 +memcached_instance 'memcached' do + port 11212 memory 128 end diff --git a/test/integration/default/serverspec/default_spec.rb b/test/integration/default/serverspec/default_spec.rb new file mode 100644 index 0000000..7470bd3 --- /dev/null +++ b/test/integration/default/serverspec/default_spec.rb @@ -0,0 +1,16 @@ +require 'spec_helper' + +set :path, '$PATH:/sbin' if os[:family] == 'redhat' && os[:release].match(/^5\.\d+/) + +describe package('memcached') do + it { should be_installed } +end + +describe service('memcached') do + it { should be_enabled } + it { should be_running } +end + +describe port(11211) do + it { should be_listening.with('tcp') } +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..37af1b4 --- /dev/null +++ b/test/integration/helpers/serverspec/spec_helper.rb @@ -0,0 +1,3 @@ +require 'serverspec' + +set :backend, :exec diff --git a/test/integration/instance/serverspec/instance_spec.rb b/test/integration/instance/serverspec/instance_spec.rb index 80688a8..8516851 100644 --- a/test/integration/instance/serverspec/instance_spec.rb +++ b/test/integration/instance/serverspec/instance_spec.rb @@ -1,10 +1,19 @@ -require 'serverspec' -include Serverspec::Helper::Exec -include Serverspec::Helper::DetectOS - -describe 'memcached_instance definition' do - it 'is running with the correct attributes' do - expect(service('memcached')).to be_running - expect(port(11_211)).to be_listening - end +require 'spec_helper' + +set :path, '$PATH:/sbin' if os[:family] == 'redhat' && os[:release].match(/^5\.\d+/) + +describe package('memcached') do + it { should be_installed } +end + +describe service('memcached') do + it { should be_running } +end + +describe command('service memcached status') do + its(:stdout) { should match /^run: memcached/ } +end + +describe port(11212) do + it { should be_listening.with('tcp') } end