Chef is an open-source systems integration framework built specifically for automating the cloud.
Knife is a powerful command-line interface (CLI) that comes with Chef.
gem install knife-solo
Kitchen is a place where you build and store recipes. And cook!
knife kitchen mychefrepo
The kitchen command simply takes a name of the directory to store the kitchen structure.
mykitchen/
├── cookbooks
├── data_bags
├── nodes
├── roles
├── site-cookbooks
└── solo.rb
knife prepare ubuntu@10.0.0.201
knife bootstrap --template-file bootstrap.centos.erb -u root 10.0.0.201
echo '{"run_list":[]}' > nodes/10.0.0.201.json
knife cook ubuntu@10.0.0.201
gem install librarian
librarian-chef init
librarian-chef install
├── Cheffile
├── Cheffile.lock
├── chefignore
├── cookbooks
├── data_bags
├── files
├── nodes
├── roles
├── site-cookbooks
├── solo.rb
└── tmp
$ cat Cheffile
#!/usr/bin/env ruby
#^syntax detection
site 'http://community.opscode.com/api/v1'
cookbook 'nginx',
:git => 'git://github.com/opscode-cookbooks/nginx.git'
cookbook 'rvm'
cookbook 'ruby_build'
cookbook 'rbenv',
:git => 'https://github.com/fnichol/chef-rbenv'
cookbook 'postgresql',
:git => 'git://github.com/opscode-cookbooks/postgresql.git'
├── CHANGELOG.md
├── CONTRIBUTING
├── Gemfile
├── LICENSE
├── README.md
├── attributes
├── definitions
├── files
├── metadata.rb
├── recipes
├── templates
└── test
$ cat attributes/default.rb
default['nginx']['version'] = "1.2.3"
default['nginx']['dir'] = "/etc/nginx"
default['nginx']['log_dir'] = "/var/log/nginx"
default['nginx']['binary'] = "/usr/sbin/nginx"
case node['platform']
when "debian","ubuntu"
default['nginx']['user'] = "www-data"
default['nginx']['init_style'] = "runit"
when "redhat","centos","scientific","amazon","oracle","fedora"
default['nginx']['user'] = "nginx"
default['nginx']['init_style'] = "init"
else
default['nginx']['user'] = "www-data"
default['nginx']['init_style'] = "init"
end
$ cat definitions/nginx_site.rb
define :nginx_site, :enable => true do
if params[:enable]
execute "nxensite #{params[:name]}" do
command "/usr/sbin/nxensite #{params[:name]}"
notifies :reload, resources(:service => "nginx")
not_if do ::File.symlink?("#{node['nginx']['dir']}/sites-enabled/#{params[:name]}") end
end
else
execute "nxdissite #{params[:name]}" do
command "/usr/sbin/nxdissite #{params[:name]}"
notifies :reload, resources(:service => "nginx")
only_if do ::File.symlink?("#{node['nginx']['dir']}/sites-enabled/#{params[:name]}") end
end
end
end
template "#{node[:nginx][:dir]}/sites-available/#{node[:app][:name]}.conf" do
source "nginx.conf.erb"
mode "0644"
end
nginx_site "#{node[:app][:name]}.conf"
$ cat nginx.conf.erb
upstream prod_unicorn {
server unix:<%= node[:app][:web_dir] %>/shared/tmp/sockets/unicorn.sock fail_timeout=0;
}
server {
listen 80 default;
...
├── authorized_ips.rb
├── commons.rb
├── default.rb
├── http_echo_module.rb
├── http_geoip_module.rb
├── http_gzip_static_module.rb
├── http_realip_module.rb
├── http_ssl_module.rb
├── http_stub_status_module.rb
├── naxsi_module.rb
├── ohai_plugin.rb
├── passenger.rb
├── source.rb
└── upload_progress_module.rb
$ cat source.rb
nginx_url = node['nginx']['source']['url'] ||
"http://nginx.org/download/nginx-#{node['nginx']['version']}.tar.gz"
unless(node['nginx']['source']['default_configure_flags'])
node.set['nginx']['source']['default_configure_flags'] = [
"--prefix=#{node['nginx']['source']['prefix']}",
"--conf-path=#{node['nginx']['dir']}/nginx.conf"
]
end
include_recipe "nginx::ohai_plugin"
include_recipe "build-essential"
"run_list": [
"nginx[source]"
]
or
include_recipe "nginx::source"
├── recipes
│ └── default.rb
└── templates
└── default
├── database.yml.erb
├── nginx.conf.erb
└── unicorn.rb.erb
# packages
package "git-core"
# curb gem
package "libcurl3"
package "libcurl3-gnutls"
package "libcurl4-openssl-dev"
# rmagick gem
package "imagemagick"
package "libmagickcore-dev"
package "libmagickwand-dev"
# ruby
include_recipe "ruby_build"
include_recipe "rbenv::system"
# nginx
include_recipe "nginx::source"
# gems
gem_package "bundler"
# nginx config
template "#{node[:nginx][:dir]}/sites-available/#{node[:app][:name]}.conf" do
source "nginx.conf.erb"
mode "0644"
end
nginx_site "#{node[:app][:name]}.conf"
# dirs
web_dir = node[:app][:web_dir]
directory web_dir do
owner node[:user][:name]
mode "0755"
end
%w{shared shared/log shared/config}.each do |dir|
directory "#{web_dir}/#{dir}" do
owner node[:user][:name]
mode "0755"
end
end
# folders
shared_config_dir = "#{node[:app][:web_dir]}/shared/config"
template "#{shared_config_dir}/database.yml" do
source "database.yml.erb"
mode "0644"
end
template "#{shared_config_dir}/unicorn.rb" do
source "unicorn.rb.erb"
mode "0644"
end
Celluloid is a concurrent object oriented programming framework for Ruby which lets you build multithreaded programs out of concurrent objects just as easily as you build sequential programs out of regular objects
gem install celluloid
require 'rss'
require 'open-uri'
class FeedParser
def initialize(url)
@url = url
end
def count
open(@url) do |f|
rss = RSS::Parser.parse(f.read, false)
count = rss.items.size
puts "#{count} in #{@url}"
count
end
end
end
counts = $*.map { |url| FeedParser.new(url).count }
total = counts.inject(:+)
puts "#{total} total" if total
$ ruby 1.rb http://feeds2.feedburner.com/Rubyflow http://feeds.feedburner.com/ualeopard http://feeds2.feedburner.com/Rubyflow http://feeds.feedburner.com/ualeopard http://feeds2.feedburner.com/Rubyflow http://feeds.feedburner.com/ualeopard http://feeds2.feedburner.com/Rubyflow http://feeds.feedburner.com/ualeopard http://feeds2.feedburner.com/Rubyflow http://feeds.feedburner.com/ualeopard
10 in http://feeds2.feedburner.com/Rubyflow
49 in http://feeds.feedburner.com/ualeopard
10 in http://feeds2.feedburner.com/Rubyflow
49 in http://feeds.feedburner.com/ualeopard
10 in http://feeds2.feedburner.com/Rubyflow
49 in http://feeds.feedburner.com/ualeopard
10 in http://feeds2.feedburner.com/Rubyflow
49 in http://feeds.feedburner.com/ualeopard
10 in http://feeds2.feedburner.com/Rubyflow
49 in http://feeds.feedburner.com/ualeopard
295 total
require 'rss'
require 'open-uri'
require 'celluloid'
class FeedParser
include Celluloid
def initialize(url)
@url = url
end
def count
open(@url) do |f|
rss = RSS::Parser.parse(f.read, false)
count = rss.items.size
puts "#{count} in #{@url}"
count
end
end
end
counts = $*.map { |url| FeedParser.new(url).future(:count) }
total = counts.map(&:value).inject(:+)
puts "#{total} total" if total
Thread.list.count ~ N * 10^3
require 'rss'
require 'open-uri'
require 'celluloid'
class FeedParser
include Celluloid
def count(url)
open(url) do |f|
rss = RSS::Parser.parse(f.read, false)
count = rss.items.size
puts "#{count} in #{url}"
count
end
end
end
pool = FeedParser.pool(size: 6)
futures = $*.map { |url| pool.future(:count, url) }
total = futures.map(&:value).inject(:+)
puts "#{total} total" if total
require 'celluloid'
class HardWorker
include Celluloid
def initialize(autolaunch = false)
run! if autolaunch
end
def run
puts "do something"
raise "111" if Random.rand(3) == 2
end
end
class Launcher
include Celluloid
trap_exit :relaunch
def launch_worker
HardWorker.new_link.run!
end
def relaunch(actor, reason)
launch_worker
end
end
Launcher.new.launch_worker
# app/workers/hard_worker.rb
class HardWorker
include Sidekiq::Worker
def perform(name, count)
puts 'Doing hard work'
end
end
HardWorker.perform_async('bob', 5)
Not perfect way:
config.active_record.whitelist_attributes = true
attr_accessible :name, :age
Usage:
params.require(:person).permit(:name, :age)
ActiveRecord::Base.send(:include, ActiveModel::ForbiddenAttributesProtection)
app/views/articles/show.rabl
object @article
attributes :id, :name, :published_at
if current_user.admin?
node(:edit_url) { |article| edit_article_url(article) }
end
child :author do
attributes :id, :name
node(:url) { |author| author_url(author) }
end
app/views/articles/index.rabl
collection @articles
extends "articles/show"
<%= render "tests/test", :mustache => {msg: "Test"} %> s
var content = SMT['tests/test']({msg: "Test"});
Contact information