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