diff --git a/CHANGELOG.md b/CHANGELOG.md index 366ccb12fd..b38f26c29b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,24 @@ +# v3432 2016-01-20 +- Improve handling of special characters in bucket names +- Update s3_file to version 2.6.6 +- Skip mounting of volumes with no specified mount point +- Always restart Unicorn instead of a stop and start to prevent downtime during deploys +- Always update custom cookbook for setup command +- After creating RAID arrays update initramfs to prevent device mapping issues on reboot + +# v3431 2015-12-22 +- Fixed passenger and unicorn gem installation issue +- Updating the default 2.0, 2.1 and 2.2 versions of Ruby to 2.0.0p648, 2.1.8 and 2.2.4 +- Allow postgres package names to set in custom JSON. +- Update the Node.js default version to 0.12.9 + +# v3430 2015-11-25 +# v3429 2015-11-19 +- Improve robustness of s3_file resource (retries, caught exceptions). + +# v3428 2015-10-28 +- Adding postgres adapter detection based on the Gemfile, fixes https://github.com/aws/opsworks-cookbooks/issues/136 + # v3427 2015-09-11 - Updating the default 2.0, 2.1 and 2.2 versions of Ruby to 2.0.0p647, 2.1.7 and 2.2.3 diff --git a/README.md b/README.md index db6760b941..b41c14c80f 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,34 @@ opsworks-cookbooks ================== -**These are the standard Chef cookbooks used by AWS OpsWorks.** +**This repo contains cookbooks used by AWS OpsWorks for Chef versions 11.10, 11.4 and 0.9.** + +To get started with AWS OpsWorks cookbooks for all versions of Chef see the [cookbook documentation](https://docs.aws.amazon.com/opsworks/latest/userguide/workingcookbook.html). If you want to override any template (like the Rails database.yml or the Apache vhost definition), this is the place to look for the originals. -Branches for current Chef versions +Chef version 12 +------------------------------------ + +**For Chef 12.2 Windows and Chef 12 Linux there are no built-in cookbooks** + +Chef versions 11.10, 11.4 and 0.9 ---------------------------------- -These branches are currently used by OpsWorks on your instance. +These branches contain the cookbooks that are used by official OpsWorks releases: - **Chef 11.10**: [release-chef-11.10](https://github.com/aws/opsworks-cookbooks/tree/release-chef-11.10) -- **Chef 11.4**: [release-chef-11.4](https://github.com/aws/opsworks-cookbooks/tree/release-chef-11.4) -- **Chef 0.9**: [release-chef-0.9](https://github.com/aws/opsworks-cookbooks/tree/release-chef-0.9) +- **Chef 11.4**: [release-chef-11.4](https://github.com/aws/opsworks-cookbooks/tree/release-chef-11.4) (deprecated) +- **Chef 0.9**: [release-chef-0.9](https://github.com/aws/opsworks-cookbooks/tree/release-chef-0.9) (deprecated) -Upcoming changes ----------------- - -These branches reflect the upcoming changes for the next release. +These branches reflect the upcoming changes for the next release: - **Chef 11.10**: [master-chef-11.10](https://github.com/aws/opsworks-cookbooks/tree/master-chef-11.10) -- **Chef 11.4**: [master-chef-11.4](https://github.com/aws/opsworks-cookbooks/tree/master-chef-11.4) -- **Chef 0.9**: [master-chef-0.9](https://github.com/aws/opsworks-cookbooks/tree/master-chef-0.9) - +- **Chef 11.4**: [master-chef-11.4](https://github.com/aws/opsworks-cookbooks/tree/master-chef-11.4) (deprecated) +- **Chef 0.9**: [master-chef-0.9](https://github.com/aws/opsworks-cookbooks/tree/master-chef-0.9) (deprecated) -The `master` branch is no longer used since AWS OpsWorks supports multiple -configuration managers now. +The `master` branch is not used since AWS OpsWorks supports multiple configuration managers. See also diff --git a/VERSION b/VERSION index b8c8a635db..d0f1d7566f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3427 +3433 diff --git a/deploy/attributes/rails_stack.rb b/deploy/attributes/rails_stack.rb index 40d761e749..3e1a2d4257 100644 --- a/deploy/attributes/rails_stack.rb +++ b/deploy/attributes/rails_stack.rb @@ -25,7 +25,7 @@ normal[:opsworks][:rails_stack][:recipe] = "unicorn::rails" normal[:opsworks][:rails_stack][:needs_reload] = true normal[:opsworks][:rails_stack][:service] = 'unicorn' - normal[:opsworks][:rails_stack][:restart_command] = '../../shared/scripts/unicorn clean-restart' + normal[:opsworks][:rails_stack][:restart_command] = "../../shared/scripts/unicorn restart" else raise "Unknown stack: #{node[:opsworks][:rails_stack][:name].inspect}" end diff --git a/deploy/definitions/opsworks_deploy_dir.rb b/deploy/definitions/opsworks_deploy_dir.rb index 2e9ec1d5c5..7e00103532 100644 --- a/deploy/definitions/opsworks_deploy_dir.rb +++ b/deploy/definitions/opsworks_deploy_dir.rb @@ -18,6 +18,7 @@ done EOH ignore_failure true + only_if { infrastructure_class?("ec2") } end end end diff --git a/deploy/metadata.rb b/deploy/metadata.rb index 484127a62b..812c3e7c65 100644 --- a/deploy/metadata.rb +++ b/deploy/metadata.rb @@ -16,6 +16,7 @@ depends "opsworks_java" depends "php" depends "mysql" +depends "opsworks_postgresql" depends "opsworks_nodejs" depends "opsworks_aws_flow_ruby" diff --git a/deploy/recipes/rails.rb b/deploy/recipes/rails.rb index 5bc21eba3c..a1b7c4252d 100644 --- a/deploy/recipes/rails.rb +++ b/deploy/recipes/rails.rb @@ -7,6 +7,13 @@ next end + case deploy[:database][:type] + when "mysql" + include_recipe "mysql::client_install" + when "postgresql" + include_recipe "opsworks_postgresql::client_install" + end + opsworks_deploy_dir do user deploy[:user] group deploy[:group] diff --git a/ebs/recipes/raids.rb b/ebs/recipes/raids.rb index 0a314e03d4..7f476887e1 100644 --- a/ebs/recipes/raids.rb +++ b/ebs/recipes/raids.rb @@ -1,5 +1,6 @@ package 'mdadm' package 'lvm2' +require "mkmf" execute 'Load device mapper kernel module' do command 'modprobe dm-mod' @@ -71,15 +72,30 @@ pass 0 end - template 'mdadm configuration' do + execute "update initramfs" do + command value_for_platform_family( + "rhel" => "dracut -H -f /boot/initramfs-#{node["kernel"]["release"]}.img #{node["kernel"]["release"]}", + "debian" => "update-initramfs -u" + ) + only_if do + value_for_platform_family( + "rhel" => find_executable0("dracut"), + "debian" => find_executable0("update-initramfs") + ) + end + action :nothing + end + + template "mdadm configuration" do path value_for_platform( - ['centos','redhat','fedora','amazon'] => {'default' => '/etc/mdadm.conf'}, - 'default' => '/etc/mdadm/mdadm.conf' + ["centos","redhat","fedora","amazon"] => {"default" => "/etc/mdadm.conf"}, + "default" => "/etc/mdadm/mdadm.conf" ) - source 'mdadm.conf.erb' + source "mdadm.conf.erb" mode 0644 - owner 'root' - group 'root' + owner "root" + group "root" + notifies :run, "execute[update initramfs]", :immediately end template 'rc.local script' do diff --git a/ebs/recipes/volumes.rb b/ebs/recipes/volumes.rb index fbd966aafe..49b9bced12 100644 --- a/ebs/recipes/volumes.rb +++ b/ebs/recipes/volumes.rb @@ -16,6 +16,11 @@ mode "0755" end + if options[:mount_point].nil? || options[:mount_point].empty? + log "skip mounting volume #{device} because no mount_point specified" + next + end + mount options[:mount_point] do action [:mount, :enable] fstype options[:fstype] diff --git a/opsworks_agent_monit/templates/default/opsworks-agent.monitrc.erb b/opsworks_agent_monit/templates/default/opsworks-agent.monitrc.erb index 5fe5c85b25..08e8d3612c 100644 --- a/opsworks_agent_monit/templates/default/opsworks-agent.monitrc.erb +++ b/opsworks_agent_monit/templates/default/opsworks-agent.monitrc.erb @@ -1,3 +1,6 @@ +# +# This template can not be customized. +# check process opsworks-agent with pidfile "<%= node[:opsworks_agent][:shared_dir] %>/pid/opsworks-agent.pid" start program = "/etc/init.d/opsworks-agent start" stop program = "/etc/init.d/opsworks-agent stop" diff --git a/opsworks_agent_monit/templates/redhat-6/opsworks-agent.monitrc.erb b/opsworks_agent_monit/templates/redhat-6/opsworks-agent.monitrc.erb index ebfd8f5467..537632e3de 100644 --- a/opsworks_agent_monit/templates/redhat-6/opsworks-agent.monitrc.erb +++ b/opsworks_agent_monit/templates/redhat-6/opsworks-agent.monitrc.erb @@ -1,3 +1,6 @@ +# +# This template can not be customized. +# check process opsworks-agent with pidfile "<%= node[:opsworks_agent][:shared_dir] %>/pid/opsworks-agent.pid" start program = "/etc/init.d/opsworks-agent start" stop program = "/etc/init.d/opsworks-agent stop" diff --git a/opsworks_commons/libraries/monkey_patch_provider_mapping.rb b/opsworks_commons/libraries/monkey_patch_provider_mapping.rb index 688cded0cb..6251356a41 100644 --- a/opsworks_commons/libraries/monkey_patch_provider_mapping.rb +++ b/opsworks_commons/libraries/monkey_patch_provider_mapping.rb @@ -29,6 +29,11 @@ def patch_platform(pf) pf[:redhat][:default][:service] = Chef::Provider::Service::Systemd pf[:redhat]["< 7"] ||= {} pf[:redhat]["< 7"][:service] = Chef::Provider::Service::Redhat + + pf[:centos][:default][:service] = Chef::Provider::Service::Systemd + pf[:centos]["< 7"] ||= {} + pf[:centos]["< 7"][:service] = Chef::Provider::Service::Redhat + pf end end diff --git a/opsworks_commons/providers/assets_installer.rb b/opsworks_commons/providers/assets_installer.rb index 9e18395d97..ef19a3bd49 100644 --- a/opsworks_commons/providers/assets_installer.rb +++ b/opsworks_commons/providers/assets_installer.rb @@ -73,9 +73,12 @@ def local_asset asset_basedir = "#{download_basedir}/#{@new_resource.asset}" ::FileUtils.mkdir_p asset_basedir - local_asset_path = `#{downloader_script} -r #{@new_resource.max_fetch_retries} -u #{asset_url} -d "#{asset_basedir}"`.chomp + cmd = Mixlib::ShellOut.new("#{downloader_script} -r #{@new_resource.max_fetch_retries} -u #{asset_url} -d '#{asset_basedir}'") + cmd.run_command + local_asset_path = cmd.stdout.chomp + STDERR.puts cmd.stderr - if $?.success? && + if !cmd.error? && ::File.file?(local_asset_path) && ::File.fnmatch("#{asset_basedir}.*", ::File.dirname(local_asset_path)) @@ -85,7 +88,14 @@ def local_asset ::FileUtils.rm_rf(Dir["#{asset_basedir}.*"], :verbose => true) rescue Chef::Log.error "Couldn't cleanup downloaded assets for #{@new_resource.name}." elsif @new_resource.ignore_failure Chef::Log.error "Failed to download asset #{asset_name} for #{@new_resource.name} with url #{asset_url}." - elsif !@new_resource.ignore_failure - raise Chef::Exceptions::ResourceNotFound, "Failed to download asset #{@new_resource.asset} for #{@new_resource.name} with url #{asset_url}." + else + msg = ["Failed to download asset #{@new_resource.asset} for #{@new_resource.name} with url #{asset_url}."] + + if cmd.stderr.include?("403 Forbidden") + msg << "The asset is probably not available for your operating system (#{node[:platform]} #{node[:platform_version]})." + msg << "Please have a look what versions are supported for this operating system at:" + msg << "http://docs.aws.amazon.com/opsworks/latest/userguide/workinginstances-os-linux.html" + end + fail Chef::Exceptions::ResourceNotFound, msg.join("\n") end end diff --git a/opsworks_custom_cookbooks/recipes/load.rb b/opsworks_custom_cookbooks/recipes/load.rb index 12dd8c48bf..eb593c41e9 100644 --- a/opsworks_custom_cookbooks/recipes/load.rb +++ b/opsworks_custom_cookbooks/recipes/load.rb @@ -1,5 +1,9 @@ if node[:opsworks_custom_cookbooks][:enabled] - include_recipe "opsworks_custom_cookbooks::checkout" + if node[:opsworks][:activity] == "setup" + include_recipe "opsworks_custom_cookbooks::update" + else + include_recipe "opsworks_custom_cookbooks::checkout" + end else directory node[:opsworks_custom_cookbooks][:destination] do action :delete diff --git a/opsworks_delayed_job/CHANGELOG.md b/opsworks_delayed_job/CHANGELOG.md new file mode 100644 index 0000000000..326478344e --- /dev/null +++ b/opsworks_delayed_job/CHANGELOG.md @@ -0,0 +1,4 @@ +0.6 (in progress) +--- +* Restart workers directly rather than with `node[:opsworks][:rails_stack][:restart_command]`. Fixes [#9](https://github.com/joeyAghion/opsworks_delayed_job/issues/9) ([#10](https://github.com/joeyAghion/opsworks_delayed_job/pull/10)). Note that this may break timing of Chef deploy hooks. +* Change default path for delayed_job executable from `script` to `bin` ([#11](https://github.com/joeyAghion/opsworks_delayed_job/pull/11)). Set `node[:delayed_job][:path_to_script]` to `script` to achieve old behavior. diff --git a/opsworks_delayed_job/LICENSE b/opsworks_delayed_job/LICENSE new file mode 100644 index 0000000000..5a3729cc58 --- /dev/null +++ b/opsworks_delayed_job/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013-2015 Joey Aghion, Artsy + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/opsworks_delayed_job/README.md b/opsworks_delayed_job/README.md new file mode 100644 index 0000000000..cca2d6d7e7 --- /dev/null +++ b/opsworks_delayed_job/README.md @@ -0,0 +1,68 @@ +opsworks_delayed_job +==================== + +These recipes set up an [AWS OpsWorks](http://aws.amazon.com/opsworks/) instance to run [delayed_job](https://github.com/collectiveidea/delayed_job) workers for a Rails application. + + +Configuration Examples +---------------------- + +By default, **4** delayed_job workers will be configured. To customize this, you may override the `delayed_job.pool_size` attribute in your stack's custom JSON: + + { + "delayed_job": { "pool_size": 6 } + } + +Specify an alternate `delayed_job` script location by overriding the `delayed_job.path_to_script` attribute in your stack's custom JSON. The default, `bin` was added in Rails 4. For pre-Rails 4 projects, set it to `script`: + + { + "delayed_job": { "pool_size": 3, "path_to_script": "script" } + } + +By default, workers will read from all queues. You can also specify custom `queues` parameters by adding attributes corresponding to each instance name and worker process. A special `default` pool can be specified to supply configuration for instances that don't otherwise appear in the JSON: + + { + "delayed_job": { + "YOUR_APP_NAME": { + "pools": { + "worker1": { + "0": { "queues": "highpriority,images" }, + "1": { "queues": "emails" }, + "2": { "queues": "images" } + }, + "default": { + "0": { "queues": "emails" }, + "1": { "queues": "emails" }, + "2": { "queues": "emails" } + } + } + } + } + } + + +OpsWorks Set-Up +--------------- + +Create a custom layer for the delayed_job instances. Add the `AWS-OpsWorks-Rails-App-Server` security group to the layer, so that the instances have the usual cache and database access. Then, assign this cookbook's custom chef recipes to OpsWorks events as follows: + +* **Setup**: `opsworks_delayed_job::setup` +* **Configure**: `opsworks_delayed_job::configure` +* **Deploy**: `opsworks_delayed_job::deploy` +* **Undeploy**: `opsworks_delayed_job::undeploy` +* **Shutdown**: `opsworks_delayed_job::stop` + + +Changes +--- + +Defaults have changed with the current release. See the [CHANGELOG](CHANGELOG.md) for details. + + +To Do +----- + +* Attributes should be better structured (allowing customization without requiring all worker processes to be listed). + + +© 2013-2015 Joey Aghion, Artsy. [MIT License](LICENSE). diff --git a/opsworks_delayed_job/attributes/default.rb b/opsworks_delayed_job/attributes/default.rb new file mode 100644 index 0000000000..adfb5e486f --- /dev/null +++ b/opsworks_delayed_job/attributes/default.rb @@ -0,0 +1,29 @@ +include_attribute "deploy" + +default[:delayed_job] = {} +default[:delayed_job][:pool_size] = 4 + +case node[:platform_family] +when 'rhel', 'fedora', 'suse' + default[:monit][:includes_dir] = '/etc/monit.d' +else + default[:monit][:includes_dir] = '/etc/monit/conf.d' +end + +node[:deploy].each do |application, deploy| + + default[:delayed_job][application] = {} + default[:delayed_job][application][:path_to_script] = node[:delayed_job][:path_to_script] || 'bin' + default[:delayed_job][application][:pools] = {} + + # Default to node[:delayed_job][:pool_size] workers, each with empty ({}) config. + default[:delayed_job][application][:pools][:default] = Hash[node[:delayed_job][:pool_size].times.map{|i| [i.to_s, {}] }] + + # Use node[:delayed_job][application][:pools][HOSTNAME] if provided. + default[:delayed_job][application][:pool] = node[:delayed_job][application][:pools][node[:opsworks][:instance][:hostname]] || node[:delayed_job][application][:pools][:default] + Chef::Log.debug("Set delayed_job attributes for #{application} to #{node[:delayed_job][application].to_hash.inspect}") + + default[:delayed_job][application][:restart_command] = "sudo monit restart -g delayed_job_#{application}_group" + +end + diff --git a/opsworks_delayed_job/metadata.rb b/opsworks_delayed_job/metadata.rb new file mode 100644 index 0000000000..f273e13232 --- /dev/null +++ b/opsworks_delayed_job/metadata.rb @@ -0,0 +1,14 @@ +name "opsworks_delayed_job" +maintainer "Artsy" +maintainer_email "it@artsymail.com" +license "MIT" +description "Configure and deploy background job workers." +version "0.6" + +recipe 'opsworks_delayed_job::setup', 'Set up delayed_job worker.' +recipe 'opsworks_delayed_job::configure', 'Configure delayed_job worker.' +recipe 'opsworks_delayed_job::deploy', 'Deploy delayed_job worker.' +recipe 'opsworks_delayed_job::undeploy', 'Undeploy delayed_job worker.' +recipe 'opsworks_delayed_job::stop', 'Stop delayed_job worker.' + +depends 'deploy' diff --git a/opsworks_delayed_job/recipes/configure.rb b/opsworks_delayed_job/recipes/configure.rb new file mode 100644 index 0000000000..dd43b21028 --- /dev/null +++ b/opsworks_delayed_job/recipes/configure.rb @@ -0,0 +1,43 @@ +# Adapted from rails::configure: https://github.com/aws/opsworks-cookbooks/blob/master/rails/recipes/configure.rb + +include_recipe "deploy" +include_recipe "opsworks_delayed_job::service" + +node[:deploy].each do |application, deploy| + deploy = node[:deploy][application] + + node.default[:deploy][application][:database][:adapter] = OpsWorks::RailsConfiguration.determine_database_adapter(application, node[:deploy][application], "#{node[:deploy][application][:deploy_to]}/current", :force => node[:force_database_adapter_detection]) + + template "#{deploy[:deploy_to]}/shared/config/database.yml" do + source "database.yml.erb" + cookbook 'rails' + mode "0660" + group deploy[:group] + owner deploy[:user] + variables(:database => deploy[:database], :environment => deploy[:rails_env]) + + notifies :run, resources(:execute => "restart Rails app #{application}") + + only_if do + File.exists?("#{deploy[:deploy_to]}") && File.exists?("#{deploy[:deploy_to]}/shared/config/") + end + end + + template "#{deploy[:deploy_to]}/shared/config/memcached.yml" do + source "memcached.yml.erb" + cookbook 'rails' + mode "0660" + group deploy[:group] + owner deploy[:user] + variables( + :memcached => deploy[:memcached] || {}, + :environment => deploy[:rails_env] + ) + + notifies :run, resources(:execute => "restart Rails app #{application}") + + only_if do + File.exists?("#{deploy[:deploy_to]}") && File.exists?("#{deploy[:deploy_to]}/shared/config/") + end + end +end diff --git a/opsworks_delayed_job/recipes/deploy.rb b/opsworks_delayed_job/recipes/deploy.rb new file mode 100644 index 0000000000..03996ed08b --- /dev/null +++ b/opsworks_delayed_job/recipes/deploy.rb @@ -0,0 +1,40 @@ +# Adapted from deploy::rails: https://github.com/aws/opsworks-cookbooks/blob/master/deploy/recipes/rails.rb + +include_recipe 'deploy' + +node[:deploy].each do |application, deploy| + + if deploy[:application_type] != 'rails' + Chef::Log.debug("Skipping opsworks_delayed_job::deploy application #{application} as it is not an Rails app") + next + end + + opsworks_deploy_dir do + user deploy[:user] + group deploy[:group] + path deploy[:deploy_to] + end + + include_recipe "opsworks_delayed_job::setup" + + template "#{deploy[:deploy_to]}/shared/config/memcached.yml" do + cookbook "rails" + source "memcached.yml.erb" + mode 0660 + owner deploy[:user] + group deploy[:group] + variables(:memcached => (deploy[:memcached] || {}), :environment => deploy[:rails_env]) + end + + node.set[:opsworks][:rails_stack][:restart_command] = ':' + + opsworks_deploy do + deploy_data deploy + app application + end + + execute "restart delayed_job" do + command node[:delayed_job][application][:restart_command] + end + +end diff --git a/opsworks_delayed_job/recipes/service.rb b/opsworks_delayed_job/recipes/service.rb new file mode 100644 index 0000000000..72f4e31b6f --- /dev/null +++ b/opsworks_delayed_job/recipes/service.rb @@ -0,0 +1,16 @@ +service "monit" do + supports :status => false, :restart => true, :reload => true + action :nothing +end + + +node[:deploy].each do |application, deploy| + + # Overwrite the unicorn restart command declared elsewhere + # Apologies for the `sleep`, but monit errors with "Other action already in progress" on some boots. + execute "restart Rails app #{application}" do + command "sleep 300 && #{node[:delayed_job][application][:restart_command]}" + action :nothing + end + +end diff --git a/opsworks_delayed_job/recipes/setup.rb b/opsworks_delayed_job/recipes/setup.rb new file mode 100644 index 0000000000..e2c941d02f --- /dev/null +++ b/opsworks_delayed_job/recipes/setup.rb @@ -0,0 +1,38 @@ +# Adapted from unicorn::rails: https://github.com/aws/opsworks-cookbooks/blob/master/unicorn/recipes/rails.rb + +include_recipe "opsworks_delayed_job::service" + +# setup delayed_job service per app +node[:deploy].each do |application, deploy| + + if deploy[:application_type] != 'rails' + Chef::Log.debug("Skipping opsworks_delayed_job::setup application #{application} as it is not a Rails app") + next + end + + opsworks_deploy_user do + deploy_data deploy + end + + opsworks_deploy_dir do + user deploy[:user] + group deploy[:group] + path deploy[:deploy_to] + end + + # Allow deploy user to restart workers + template "/etc/sudoers.d/#{deploy[:user]}" do + mode 0440 + source "sudoer.erb" + variables :user => deploy[:user] + end + + template "#{node[:monit][:includes_dir]}/delayed_job_#{application}.monitrc" do + mode 0644 + source "delayed_job.monitrc.erb" + variables(:deploy => deploy, :application => application, :delayed_job => node[:delayed_job][application]) + + notifies :reload, resources(:service => "monit"), :immediately + end + +end diff --git a/opsworks_delayed_job/recipes/stop.rb b/opsworks_delayed_job/recipes/stop.rb new file mode 100644 index 0000000000..20027c906b --- /dev/null +++ b/opsworks_delayed_job/recipes/stop.rb @@ -0,0 +1,11 @@ +# Adapted from nginx::stop: https://github.com/aws/opsworks-cookbooks/blob/master/nginx/recipes/stop.rb + +include_recipe "opsworks_delayed_job::service" + +node[:deploy].each do |application, deploy| + + execute "stop Rails app #{application}" do + command "sudo monit stop -g delayed_job_#{application}_group" + end + +end diff --git a/opsworks_delayed_job/recipes/undeploy.rb b/opsworks_delayed_job/recipes/undeploy.rb new file mode 100644 index 0000000000..d7ab120aec --- /dev/null +++ b/opsworks_delayed_job/recipes/undeploy.rb @@ -0,0 +1,18 @@ +# Adapted from deploy::rails-undeploy: https://github.com/aws/opsworks-cookbooks/blob/master/deploy/recipes/rails-undeploy.rb + +include_recipe 'deploy' + +node[:deploy].each do |application, deploy| + if deploy[:application_type] != 'rails' + Chef::Log.debug("Skipping opsworks_delayed_job::undeploy application #{application} as it is not an Rails app") + next + end + + directory "#{deploy[:deploy_to]}" do + recursive true + action :delete + only_if do + File.exists?("#{deploy[:deploy_to]}") + end + end +end diff --git a/opsworks_delayed_job/templates/default/delayed_job.monitrc.erb b/opsworks_delayed_job/templates/default/delayed_job.monitrc.erb new file mode 100644 index 0000000000..904a42cc19 --- /dev/null +++ b/opsworks_delayed_job/templates/default/delayed_job.monitrc.erb @@ -0,0 +1,9 @@ +<% @delayed_job[:pool].each do |key, config| %> +<% identifier = "#{@application}-#{key}" %> +check process delayed_job.<%= identifier %> + with pidfile <%= @deploy[:deploy_to] %>/shared/pids/delayed_job.<%= identifier %>.pid + start program = "/bin/su - <%= @deploy[:user] %> -c 'cd <%= @deploy[:current_path] %> && RAILS_ENV=<%= @deploy[:rails_env] %> bundle exec <%= @delayed_job[:path_to_script] %>/delayed_job start --identifier=<%= identifier %> <%= ("--queues=#{config['queues']}" if config['queues']) %>'" + stop program = "/bin/su - <%= @deploy[:user] %> -c 'cd <%= @deploy[:current_path] %> && RAILS_ENV=<%= @deploy[:rails_env] %> bundle exec <%= @delayed_job[:path_to_script] %>/delayed_job stop --identifier=<%= identifier %>'" + group delayed_job_<%= @application %>_group + +<% end %> diff --git a/opsworks_delayed_job/templates/default/sudoer.erb b/opsworks_delayed_job/templates/default/sudoer.erb new file mode 100644 index 0000000000..18cdbc0b0b --- /dev/null +++ b/opsworks_delayed_job/templates/default/sudoer.erb @@ -0,0 +1,3 @@ +# This file is created by the opsworks_delayed_job cookbook. + +<%= @user%> ALL=NOPASSWD:/usr/bin/monit diff --git a/opsworks_nodejs/attributes/opsworks_nodejs.rb b/opsworks_nodejs/attributes/opsworks_nodejs.rb index 74d49cbd26..3d5bb55ffb 100644 --- a/opsworks_nodejs/attributes/opsworks_nodejs.rb +++ b/opsworks_nodejs/attributes/opsworks_nodejs.rb @@ -16,7 +16,7 @@ include_attribute 'deploy' -default[:opsworks_nodejs][:version] = '0.12.7' +default[:opsworks_nodejs][:version] = '0.12.10' default[:opsworks_nodejs][:pkgrelease] = '1' default[:opsworks_nodejs][:npm_install_options] = 'install --production' diff --git a/opsworks_postgresql/attributes/customize.rb b/opsworks_postgresql/attributes/customize.rb new file mode 100644 index 0000000000..59a567f624 --- /dev/null +++ b/opsworks_postgresql/attributes/customize.rb @@ -0,0 +1,13 @@ +### +# This is the place to override the opsworks_opsworks_postgresql cookbook's default attributes. +# +# Do not edit THIS file directly. Instead, create +# "opsworks_opsworks_postgresql/attributes/customize.rb" in your cookbook repository and +# put the overrides in YOUR customize.rb file. +### + +# The following shows how to override the postgres package names +# +#normal[:opsworks_postgresql][:client_package] = "postgresql93" +#normal[:opsworks_postgresql][:devel_package] = "postgresql93-devel" + diff --git a/opsworks_postgresql/attributes/default.rb b/opsworks_postgresql/attributes/default.rb new file mode 100644 index 0000000000..0d4846e87e --- /dev/null +++ b/opsworks_postgresql/attributes/default.rb @@ -0,0 +1,24 @@ +### +# Do not use this file to override the opsworks_opsworks_postgresql cookbook's default +# attributes. Instead, please use the customize.rb attributes file, +# which will keep your adjustments separate from the AWS OpsWorks +# codebase and make it easier to upgrade. +# +# However, you should not edit customize.rb directly. Instead, create +# "opsworks_opsworks_postgresql/attributes/customize.rb" in your cookbook repository and +# put the overrides in YOUR customize.rb file. +# +# Do NOT create an 'opsworks_opsworks_postgresql/attributes/default.rb' in your cookbooks. Doing so +# would completely override this file and might cause upgrade issues. +# +# See also: http://docs.aws.amazon.com/opsworks/latest/userguide/customizing.html +### +case node[:platform] +when "redhat","centos","fedora","amazon" + default[:opsworks_postgresql][:devel_package] = "postgresql-devel" + default[:opsworks_postgresql][:client_package] = "postgresql" +when "debian","ubuntu" + default[:opsworks_postgresql][:devel_package] = "libpq-dev" + default[:opsworks_postgresql][:client_package] = "postgresql-client" +end +include_attribute "opsworks_postgresql::customize" diff --git a/opsworks_postgresql/metadata.rb b/opsworks_postgresql/metadata.rb new file mode 100644 index 0000000000..3235580153 --- /dev/null +++ b/opsworks_postgresql/metadata.rb @@ -0,0 +1,7 @@ +name "opsworks_postgresql" +description "Installs and configures the Postgresql client" +maintainer "AWS OpsWorks" +license "Apache 2.0" +version "1.0.0" + +recipe "postgresql::client_install", "Installs the Postgresql client" diff --git a/opsworks_postgresql/recipes/client_install.rb b/opsworks_postgresql/recipes/client_install.rb new file mode 100644 index 0000000000..47f1636af2 --- /dev/null +++ b/opsworks_postgresql/recipes/client_install.rb @@ -0,0 +1,26 @@ +if node[:opsworks_postgresql] && ([:devel_package, :client_package].all? {|s| node[:opsworks_postgresql].key? s}) + # Only use the default package names if attributes exist and they are + # defined so we don't break anyone who has overriden this recipe + [node[:opsworks_postgresql][:devel_package], node[:opsworks_postgresql][:client_package]].each do |pkg| + package pkg do + action :install + end + end +else + # old behavior for backwards compatibility + package "postgresql-devel" do + package_name value_for_platform( + ["centos","redhat","fedora","amazon"] => {"default" => "postgresql-devel"}, + "ubuntu" => {"default" => "libpq-dev"} + ) + action :install + end + + package "postgresql-client" do + package_name value_for_platform( + ["centos","redhat","fedora","amazon"] => {"default" => "postgresql"}, + "default" => "postgresql-client" + ) + action :install + end +end diff --git a/opsworks_postgresql/specs/client_install_spec.rb b/opsworks_postgresql/specs/client_install_spec.rb new file mode 100644 index 0000000000..b2da2769f1 --- /dev/null +++ b/opsworks_postgresql/specs/client_install_spec.rb @@ -0,0 +1,17 @@ +require "minitest/spec" + +describe_recipe "postgresql::client_install" do + include MiniTest::Chef::Resources + include MiniTest::Chef::Assertions + + it "installs packages for client" do + case node[:platform] + when "centos","redhat","fedora","amazon" + package("postgresql-devel").must_be_installed + package("postgresql").must_be_installed + when "debian","ubuntu" + package("libpq-dev").must_be_installed + package("postgresql-client").must_be_installed + end + end +end diff --git a/opsworks_rubygems/recipes/default.rb b/opsworks_rubygems/recipes/default.rb index 8660032b4e..eeefa5ab0d 100644 --- a/opsworks_rubygems/recipes/default.rb +++ b/opsworks_rubygems/recipes/default.rb @@ -1,5 +1,5 @@ remote_file "/tmp/rubygems-#{node[:opsworks_rubygems][:version]}.tgz" do - source "http://production.cf.rubygems.org/rubygems/rubygems-#{node[:opsworks_rubygems][:version]}.tgz" + source "http://rubygems.org/rubygems/rubygems-#{node[:opsworks_rubygems][:version]}.tgz" not_if do ::File.exists?('/usr/local/bin/gem') && `/usr/local/bin/gem -v`.strip == node[:opsworks_rubygems][:version] end diff --git a/passenger_apache2/attributes/passenger.rb b/passenger_apache2/attributes/passenger.rb index ec006babb0..4d4d32b231 100644 --- a/passenger_apache2/attributes/passenger.rb +++ b/passenger_apache2/attributes/passenger.rb @@ -66,5 +66,6 @@ default[:passenger][:rails_spawn_method] = 'smart-lv2' default[:passenger][:max_pool_size] = 8 # usually will be set by OpsWorks directy. Override if you need a custom size default[:passenger][:friendly_error_pages] = 'off' +default[:passenger][:rack_version] = "1.6.4" include_attribute "passenger_apache2::customize" diff --git a/passenger_apache2/recipes/default.rb b/passenger_apache2/recipes/default.rb index 6bebe6edfb..52abf8e499 100644 --- a/passenger_apache2/recipes/default.rb +++ b/passenger_apache2/recipes/default.rb @@ -53,7 +53,8 @@ ruby_block "ensure only our passenger version is installed by deinstalling any other version" do block do - ensure_only_gem_version('passenger', node[:passenger][:version]) + ensure_only_gem_version("rack", node[:passenger][:rack_version]) + ensure_only_gem_version("passenger", node[:passenger][:version]) end end diff --git a/passenger_apache2/templates/default/web_app.conf.erb b/passenger_apache2/templates/default/web_app.conf.erb index 0635b252e4..678db00df1 100644 --- a/passenger_apache2/templates/default/web_app.conf.erb +++ b/passenger_apache2/templates/default/web_app.conf.erb @@ -18,7 +18,7 @@ > Options FollowSymLinks - AllowOverride None + AllowOverride All Order allow,deny Allow from all diff --git a/rails/libraries/rails_configuration.rb b/rails/libraries/rails_configuration.rb index 59f7cd5d07..4e392dfcf1 100644 --- a/rails/libraries/rails_configuration.rb +++ b/rails/libraries/rails_configuration.rb @@ -14,6 +14,9 @@ def self.determine_database_adapter(app_name, app_config, app_root_path, options adapter = if bundle_list.include?('mysql2') Chef::Log.info("Looks like #{app_name} uses mysql2 in its Gemfile") 'mysql2' + elsif bundle_list.include?("pg") + Chef::Log.info("Looks like #{app_name} uses pg in its Gemfile") + "postgresql" else Chef::Log.info("Gem mysql2 not found in the Gemfile of #{app_name}, defaulting to mysql") 'mysql' diff --git a/rails/recipes/configure.rb b/rails/recipes/configure.rb index 29f67d1ce9..feaf358134 100644 --- a/rails/recipes/configure.rb +++ b/rails/recipes/configure.rb @@ -12,6 +12,13 @@ node.default[:deploy][application][:database][:adapter] = OpsWorks::RailsConfiguration.determine_database_adapter(application, node[:deploy][application], "#{node[:deploy][application][:deploy_to]}/current", :force => node[:force_database_adapter_detection]) deploy = node[:deploy][application] + case node[:deploy][application][:database][:adapter] + when /mysql/ + include_recipe "mysql::client_install" + when "postgresql" + include_recipe "opsworks_postgresql::client_install" + end + template "#{deploy[:deploy_to]}/shared/config/database.yml" do source "database.yml.erb" cookbook 'rails' @@ -44,4 +51,4 @@ deploy[:memcached][:host].present? && File.directory?("#{deploy[:deploy_to]}/shared/config/") end end -end \ No newline at end of file +end diff --git a/ruby/attributes/ruby.rb b/ruby/attributes/ruby.rb index 7e589896a9..333558d69d 100644 --- a/ruby/attributes/ruby.rb +++ b/ruby/attributes/ruby.rb @@ -21,7 +21,7 @@ when "2.2" default[:ruby][:major_version] = '2' default[:ruby][:minor_version] = '2' - default[:ruby][:patch_version] = '3' + default[:ruby][:patch_version] = '4' default[:ruby][:pkgrelease] = '1' default[:ruby][:full_version] = [node[:ruby][:major_version], node[:ruby][:minor_version]].join(".") @@ -30,7 +30,7 @@ when "2.1" default[:ruby][:major_version] = '2' default[:ruby][:minor_version] = '1' - default[:ruby][:patch_version] = '7' + default[:ruby][:patch_version] = '8' default[:ruby][:pkgrelease] = '1' default[:ruby][:full_version] = [node[:ruby][:major_version], node[:ruby][:minor_version]].join(".") @@ -39,7 +39,7 @@ when "2.0.0" default[:ruby][:major_version] = '2' default[:ruby][:minor_version] = '0' - default[:ruby][:patch] = 'p647' # this attribute will disappear in favor of the sematic versioning schema + default[:ruby][:patch] = 'p648' # this attribute will disappear in favor of the sematic versioning schema default[:ruby][:patch_version] = node[:ruby][:patch] default[:ruby][:pkgrelease] = '1' diff --git a/s3_file/.gitignore b/s3_file/.gitignore index b4085f656b..354119c250 100644 --- a/s3_file/.gitignore +++ b/s3_file/.gitignore @@ -1,2 +1,7 @@ .DS_Store metadata.json +.kitchen.local.yml +.kitchen +.s3.yml +Berksfile.lock +*.iml diff --git a/s3_file/.kitchen.yml b/s3_file/.kitchen.yml new file mode 100644 index 0000000000..2d6447bde4 --- /dev/null +++ b/s3_file/.kitchen.yml @@ -0,0 +1,28 @@ +--- +driver: + name: vagrant + +provisioner: + name: chef_solo +<% s3 = YAML.load_file('.s3.yml') %> +platforms: +<% %w(11.16.4 12.0.1).each do |chef_version| + %w(ubuntu-12.04 ubuntu-14.04 centos-6.6 centos-7.0).each do |platform| + %> + - name: <%= platform %> + driver_config: + require_chef_omnibus: <%= chef_version %> +<% end +end %> +suites: + - name: default + run_list: + - recipe[s3_file_test::default] + attributes: + s3_file_test: + file: <%= s3['file'] %> + bucket: <%= s3['bucket'] %> + region: <%= s3['region'] %> + access_key: <%= s3['access_key'] %> + secret_key: <%= s3['secret_key'] %> + diff --git a/s3_file/Berksfile b/s3_file/Berksfile new file mode 100644 index 0000000000..8c0ce70034 --- /dev/null +++ b/s3_file/Berksfile @@ -0,0 +1,6 @@ +source 'https://supermarket.chef.io' + +metadata + +cookbook 's3_file_test', :path => 'test/fixtures/cookbooks/s3_file_test' + diff --git a/s3_file/README.rdoc b/s3_file/README.md similarity index 92% rename from s3_file/README.rdoc rename to s3_file/README.md index 5bf4aa5f6c..954357b545 100644 --- a/s3_file/README.rdoc +++ b/s3_file/README.md @@ -1,11 +1,11 @@ -= DESCRIPTION: +#DESCRIPTION An LWRP that can be used to fetch files from S3. I created this LWRP to solve the chicken-and-egg problem of fetching files from S3 on the first Chef run on a newly provisioned machine. Ruby libraries that are installed on that first run are not available to Chef during the run, so I couldn't use a library like Fog to get what I needed from S3. This LWRP has no dependencies beyond the Ruby standard library, so it can be used on the first run of Chef. -= REQUIREMENTS: +#REQUIREMENTS An Amazon Web Services account and something in S3 to fetch. Multi-part S3 uploads do not put the MD5 of the content in the ETag header. If x-amz-meta-digest is provided in User-Defined Metadata on the S3 Object it is processed as if it were a Digest header (RFC 3230). @@ -14,7 +14,7 @@ The MD5 of the local file will be checked against the MD5 from x-amz-meta-digest If credentials are not provided, s3_file will attempt to use the first instance profile associated with the instance. See documentation at http://docs.aws.amazon.com/IAM/latest/UserGuide/instance-profiles.html for more on instance profiles. -= USAGE: +#USAGE s3_file acts like other file resources. The only supported action is :create, which is the default. Attribute Parameters: @@ -46,14 +46,14 @@ Example: decrypted_file_checksum "SHA256 hex digest of decrypted file" end -= MD5 and Multi-Part Upload: +#MD5 and Multi-Part Upload s3_file compares the MD5 hash of a local file, if present, and the ETag header of the S3 object. If they do not match, then the remote object will be downloaded and notifiations will be fired. In most cases, the ETag of an S3 object will be identical to its MD5 hash. However, if the file was uploaded to S3 via multi-part upload, then the ETag will be set to the MD5 hash of the first uploaded part. In these cases, MD5 of the local file and remote object will never match. To work around this issue, set an X-Amz-Meta-Digest tag on your S3 object with value set to `md5=MD5 of the entire object`. s3_file will then use that value in place of the ETag value, and will skip downloading in case the MD5 of the local file matches the value of the X-Amz-Meta-Digest header. -= USING ENCRYPTED S3 FILES: +#USING ENCRYPTED S3 FILES s3_file can decrypt files that have been encrypted using an AES-256-CBC cipher. To use the decryption part of the resource, you must provide a decryption_key which can be generated by following the instructions below. You can also include an optional decrypted_file_checksum which allows Chef to check to see if it needs to redownload the encrypted file. Note that this checksum is different from the one in S3 because the file you compare to is already decrypted so a SHA256 checksum is used instead of the MD5. Instructions to generate the decrypted_file_checksum are below as well. To use s3_file with encrypted files: @@ -74,7 +74,7 @@ Try `bin/s3_crypto -g > my_new_key`. You can use the utility `bin/s3_crypto` to encrypt files prior to uploading to S3 and to decrypt files prior to make sure the encryption is working. -= ChefSpec matcher +#ChefSpec matcher s3_file comes with a matcher to use in {ChefSpec}[https://github.com/sethvargo/chefspec]. This spec checks the code from the USAGE example above: @@ -84,3 +84,14 @@ This spec checks the code from the USAGE example above: .with(bucket: "my-s3-bucket", remote_path: "/my/s3/key") end +#Testing + +This cookbook has Test Kitchen integration tests. To test, create a .s3.yml file with the following S3 details. + + file: file + bucket: bucket + region: xx-xxxx-x + access_key: XXXXXXXXXXXXXXXXXXXX + secret_key: XXXXXXXXXXXXXXXXXXXX + +If you're using the ChefDK then type `chef exec kitchen test`, otherwise `kitchen test`. diff --git a/s3_file/libraries/s3_file.rb b/s3_file/libraries/s3_file.rb index cce15b3379..ca23e318bd 100644 --- a/s3_file/libraries/s3_file.rb +++ b/s3_file/libraries/s3_file.rb @@ -87,7 +87,7 @@ def self.with_region_detect(region = nil) end def self.do_request(method, url, bucket, path, aws_access_key_id, aws_secret_access_key, token, region) - url = "https://#{bucket}.s3.amazonaws.com" if url.nil? + url = build_endpoint_url(bucket, region) if url.nil? with_region_detect(region) do |real_region| client.reset_before_execution_procs @@ -102,6 +102,20 @@ def self.do_request(method, url, bucket, path, aws_access_key_id, aws_secret_acc end end + def self.build_endpoint_url(bucket, region) + endpoint = if region && region != "us-east-1" + "s3-#{region}.amazonaws.com" + else + "s3.amazonaws.com" + end + + if bucket =~ /^[a-z0-9][a-z0-9-]+[a-z0-9]$/ + "https://#{bucket}.#{endpoint}" + else + "https://#{endpoint}/#{bucket}" + end + end + def self.get_md5_from_s3(bucket, url, path, aws_access_key_id, aws_secret_access_key, token, region = nil) get_digests_from_s3(bucket, url, path, aws_access_key_id, aws_secret_access_key, token, region)["md5"] end @@ -122,7 +136,8 @@ def self.get_from_s3(bucket, url, path, aws_access_key_id, aws_secret_access_key for attempts in 0..retries begin response = do_request("GET", url, bucket, path, aws_access_key_id, aws_secret_access_key, token, region) - break + return response + # break rescue client::MovedPermanently, client::Found, client::TemporaryRedirect => e uri = URI.parse(e.response.header['location']) path = uri.path @@ -130,18 +145,18 @@ def self.get_from_s3(bucket, url, path, aws_access_key_id, aws_secret_access_key url = uri.to_s retry rescue => e - raise e unless e.respond_to? :response + error = e.respond_to?(:response) ? e.response : e if attempts < retries - Chef::Log.warn e.response + Chef::Log.warn(error) + sleep 5 next else - Chef::Log.fatal e.response + Chef::Log.fatal(error) raise e end + raise e end end - - return response end def self.aes256_decrypt(key, file) @@ -200,6 +215,8 @@ def self.verify_md5_checksum(checksum, file) def self.client require 'rest-client' RestClient.proxy = ENV['http_proxy'] + RestClient.proxy = ENV['https_proxy'] + RestClient.proxy = ENV['no_proxy'] RestClient end end diff --git a/s3_file/metadata.rb b/s3_file/metadata.rb index d516051891..12af4ef7c1 100644 --- a/s3_file/metadata.rb +++ b/s3_file/metadata.rb @@ -3,5 +3,5 @@ maintainer_email "brandon.adams@me.com" license "MIT" description "Installs/Configures s3_file LWRP" -long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) -version "2.5.4" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) +version "2.6.6" diff --git a/s3_file/recipes/dependencies.rb b/s3_file/recipes/dependencies.rb index 62440bcf50..466d52890a 100644 --- a/s3_file/recipes/dependencies.rb +++ b/s3_file/recipes/dependencies.rb @@ -1,4 +1,5 @@ chef_gem 'rest-client' do version node['s3_file']['rest-client']['version'] action :install + compile_time true if Chef::Resource::ChefGem.instance_methods(false).include?(:compile_time) end diff --git a/s3_file/test/fixtures/cookbooks/s3_file_test/README.md b/s3_file/test/fixtures/cookbooks/s3_file_test/README.md new file mode 100644 index 0000000000..f91a55db3b --- /dev/null +++ b/s3_file/test/fixtures/cookbooks/s3_file_test/README.md @@ -0,0 +1,12 @@ +#Description + +This cookbook defines acceptance tests for `s3_file`. It simple attempts to fetch a file from S3. + +##Attributes + +- `node['s3_file_test']['bucket']` - The bucket where the test file resides +- `node['s3_file_test']['region']` - The AWS region for the bucket +- `node['s3_file_test']['file']` - The name of the test file +- `node['s3_file_test']['access_key']` - The AWS access key which allows us to fetch our test S3 file +- `node['s3_file_test']['secret_key']` - The AWS secret key which allows us to fetch our test S3 file + diff --git a/s3_file/test/fixtures/cookbooks/s3_file_test/metadata.rb b/s3_file/test/fixtures/cookbooks/s3_file_test/metadata.rb new file mode 100644 index 0000000000..155bc6d1e3 --- /dev/null +++ b/s3_file/test/fixtures/cookbooks/s3_file_test/metadata.rb @@ -0,0 +1,10 @@ +name 's3_file_test' +maintainer 'Brandon Adams' +maintainer_email 'brandon.adams@me.com' +license 'MIT' +description 'Tests s3_file LWRP' +long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) +version '0.1.0' + +depends 's3_file' + diff --git a/s3_file/test/fixtures/cookbooks/s3_file_test/recipes/default.rb b/s3_file/test/fixtures/cookbooks/s3_file_test/recipes/default.rb new file mode 100644 index 0000000000..4d92777c9c --- /dev/null +++ b/s3_file/test/fixtures/cookbooks/s3_file_test/recipes/default.rb @@ -0,0 +1,11 @@ + +s3_file '/root/kitchen-test' do + remote_path node['s3_file_test']['file'] + bucket node['s3_file_test']['bucket'] + aws_access_key_id node['s3_file_test']['access_key'] + aws_secret_access_key node['s3_file_test']['secret_key'] + mode 0600 + owner 'root' + group 'root' +end + diff --git a/s3_file/test/integration/default/serverspec/default_spec.rb b/s3_file/test/integration/default/serverspec/default_spec.rb new file mode 100755 index 0000000000..9ade432c94 --- /dev/null +++ b/s3_file/test/integration/default/serverspec/default_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe file('/root/kitchen-test') do + it { should be_file } +end diff --git a/s3_file/test/integration/default/serverspec/spec_helper.rb b/s3_file/test/integration/default/serverspec/spec_helper.rb new file mode 100755 index 0000000000..37af1b4599 --- /dev/null +++ b/s3_file/test/integration/default/serverspec/spec_helper.rb @@ -0,0 +1,3 @@ +require 'serverspec' + +set :backend, :exec diff --git a/scm_helper/libraries/archive.rb b/scm_helper/libraries/archive.rb index e74a9f6f00..02c6f5dbd8 100644 --- a/scm_helper/libraries/archive.rb +++ b/scm_helper/libraries/archive.rb @@ -20,6 +20,7 @@ def prepare_archive_checkouts(scm_options) remote_file "#{tmpdir}/archive" do source archive_url + retries 3 end execute 'extract files' do diff --git a/scm_helper/libraries/s3.rb b/scm_helper/libraries/s3.rb index 3c021acd70..de0e68b890 100644 --- a/scm_helper/libraries/s3.rb +++ b/scm_helper/libraries/s3.rb @@ -6,18 +6,22 @@ module S3 def self.parse_uri(uri) uri = URI.parse(uri) uri_path_components = uri.path.split("/").reject{|p| p.empty?} - virtual_host_match = uri.host.match(/\A(.+)\.s3(?:-(?:ap|eu|sa|us)-.+-\d)?\.amazonaws\.com/i) + virtual_host_match = uri.host.match(/\A(.+)\.s3(?:[-.](?:ap|eu|sa|us)-(?:.+-)\d|-external-1)?\.amazonaws\.com/i) + base_uri = uri.dup + if virtual_host_match # virtual-hosted-style: http://bucket.s3.amazonaws.com or http://bucket.s3-aws-region.amazonaws.com bucket = virtual_host_match[1] - remote_path = uri_path_components.join("/") + base_uri.path = "/" else # path-style: http://s3.amazonaws.com/bucket or http://s3-aws-region.amazonaws.com/bucket bucket = uri_path_components[0] - remote_path = uri_path_components[1..-1].join("/") + base_uri.path = "/#{uri_path_components.shift}" end - [bucket, remote_path] + remote_path = uri_path_components.join("/") # remote_path don't allow a "/" at the beginning + + [bucket, remote_path, base_uri.to_s.chomp("/")] # base_url don't allow a "/" at the end end def prepare_s3_checkouts(scm_options) @@ -33,7 +37,7 @@ def prepare_s3_checkouts(scm_options) mode 0755 end - s3_bucket, s3_key = OpsWorks::SCM::S3.parse_uri(scm_options[:repository]) + s3_bucket, s3_key, base_url = OpsWorks::SCM::S3.parse_uri(scm_options[:repository]) s3_file "#{tmpdir}/archive" do bucket s3_bucket @@ -43,6 +47,7 @@ def prepare_s3_checkouts(scm_options) owner "root" group "root" mode "0600" + s3_url base_url action :create end diff --git a/unicorn/attributes/default.rb b/unicorn/attributes/default.rb index c2707479b5..3a68fe5d9a 100644 --- a/unicorn/attributes/default.rb +++ b/unicorn/attributes/default.rb @@ -26,5 +26,6 @@ default[:unicorn][:tries] = 5 default[:unicorn][:delay] = 0.5 default[:unicorn][:accept_filter] = "httpready" +default[:unicorn][:rack_version] = "1.6.4" include_attribute "unicorn::customize" diff --git a/unicorn/recipes/default.rb b/unicorn/recipes/default.rb index 4de4ee988d..5ea699ada4 100644 --- a/unicorn/recipes/default.rb +++ b/unicorn/recipes/default.rb @@ -1,5 +1,6 @@ ruby_block "ensure only our unicorn version is installed by deinstalling any other version" do block do - ensure_only_gem_version('unicorn', node[:unicorn][:version]) + ensure_only_gem_version("rack", node[:unicorn][:rack_version]) + ensure_only_gem_version("unicorn", node[:unicorn][:version]) end end