├── .gitignore ├── CHANGELOG ├── LICENSE ├── README.textile ├── Rakefile ├── bin └── spatula ├── lib ├── spatula.rb └── spatula │ ├── cook.rb │ ├── prepare.rb │ ├── search.rb │ └── ssh_command.rb ├── scripts ├── forward_ports.rb ├── ssh_port └── ssh_to_virtualbox ├── spatula.gemspec └── test ├── integration └── spatula_test.rb ├── keys ├── spatula-integration └── spatula-integration.pub └── test-chef-repo ├── .gitignore ├── README ├── Rakefile ├── certificates └── README ├── config ├── client.rb.example ├── knife.rb.example ├── local.json ├── rake.rb ├── server.rb.example └── solo.rb ├── cookbooks ├── README └── test_cookbook │ ├── README.rdoc │ ├── metadata.rb │ └── recipes │ └── default.rb ├── roles ├── README └── base_example.rb └── site-cookbooks └── README /.gitignore: -------------------------------------------------------------------------------- 1 | pkg/* 2 | vms/* 3 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | Version: 0.0.12 2 | --------------- 3 | 4 | - Add support for arbitrary versions of ruby using 5 | the --ruby_version= flag (Thanks matschaffer) 6 | 7 | Version: 0.0.11 8 | --------------- 9 | 10 | - Properly secure ssh files (Thanks hectcastro) 11 | - Better ubuntu packages (Thanks erikh) 12 | 13 | Version: 0.0.10 14 | --------------- 15 | 16 | - Updated to latest rubygems and ruby (Thanks erikh). 17 | - Added support for alternate keyfiles using --keyfile (Thanks erikh). 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2009 Trotter Cashion 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.textile: -------------------------------------------------------------------------------- 1 | h1. Spatula 2 | 3 | Spatula is a command line helper app for use with "Chef":http://www.opscode.com/chef. It currently lets you search and install cookbooks from http://cookbooks.opscode.com. It does not yet implement the full API, but that will be coming in future versions (as I need it). If you need it to support the full API *right now*, please make it do so and send me a pull request :-) 4 | 5 | Spatula is really, really alpha. It does not handle errors at all, but it works pretty well given that you hand it the correct input. Please give it a try and pretty please fork it and make it better. 6 | 7 | h1. Installation 8 | 9 | You can get spatula from gemcutter. 10 | 11 |
12 | # Gemcutter:
13 | # Follow the instructions on http://gemcutter.org/ then...
14 | gem install spatula
15 | 
16 | 17 | h1. Usage 18 | 19 | Spatula currently supports 6 commands: search, show, install, prepare, and cook. 20 | 21 |
22 | $ spatula search apache2
23 | apache2 Installs and configures all aspects of apache2 using Debian style symlinks with helper definitions
24 | ... more output ...
25 | 
26 | $ spatula show apache2
27 | name:   apache2
28 | average_rating:
29 | category:       Web Servers
30 | created_at:     2009-10-25T23:47:55Z
31 | updated_at:     2009-10-25T23:47:55Z
32 | maintainer:     jtimberman
33 | latest_version: http://cookbooks.opscode.com/api/v1/cookbooks/apache2/versions/0_9_1
34 | external_url:
35 | versions:       http://cookbooks.opscode.com/api/v1/cookbooks/apache2/versions/0_9_1
36 | description:    Installs and configures all aspects of apache2 using Debian style symlinks with helper definitions
37 | 
38 | $ spatula install apache2
39 | ... downloads the apache2 cookbook and installs it into $(pwd)/cookbooks ...
40 | ... also creates a $(pwd)/cookbook_tarballs dir to store the download ...
41 | 
42 | $ spatula prepare user@192.168.1.101
43 | ... installs ruby, chef and dependencies on 192.168.1.101
44 | ... starts by adding your ssh public key to authorized_keys
45 | 
46 | $ spatula cook user@192.168.1.101 
47 | ... uploads all of the files in the current directory to /tmp/chef-solo/
48 | ... expects solo.rb and .json to live in ./config
49 | 
50 | 
51 | 52 | h1. About 53 | 54 | h2. Official Repo 55 | 56 | http://github.com/trotter/spatula 57 | 58 | h2. Author 59 | 60 | Trotter Cashion 61 | 62 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'rake' 3 | require 'rake/gempackagetask' 4 | load 'spatula.gemspec' 5 | 6 | Rake::GemPackageTask.new($spec) do |t| 7 | t.need_tar = true 8 | end 9 | -------------------------------------------------------------------------------- /bin/spatula: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | begin 4 | require 'spatula' 5 | rescue LoadError 6 | require 'rubygems' 7 | require 'spatula' 8 | end 9 | 10 | Spatula::Spatula.start 11 | 12 | -------------------------------------------------------------------------------- /lib/spatula.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'net/http' 3 | require 'uri' 4 | require 'json' 5 | require 'thor' 6 | 7 | module Spatula 8 | BASE_URL = "http://cookbooks.opscode.com/api/v1" 9 | 10 | class Spatula < Thor 11 | desc "show COOKBOOK", "Show information about a cookbook" 12 | def show(name) 13 | print_response(get_cookbook_info(name)) 14 | end 15 | 16 | desc "show_latest_version COOKBOOK", "Show the latest version for a cookbook" 17 | def show_latest_version(name) 18 | print_response(get_version_info(name)) 19 | end 20 | 21 | desc "install COOKBOOK", "Install the latest version of COOKBOOK into ./cookbooks" 22 | def install(name) 23 | file = JSON.parse(get_version_info(name))["file"] 24 | filename = File.basename(file) 25 | # Use ENV['HOME'] as the base here 26 | tarball_dir = "#{ENV['HOME']}/.spatula/cookbook_tarballs" 27 | FileUtils.mkdir_p(tarball_dir) 28 | system "curl #{file} -o #{tarball_dir}/#{filename}" 29 | system "tar xzvf #{tarball_dir}/#{filename} -C cookbooks" 30 | end 31 | 32 | desc "search QUERY", "Search cookbooks.opscode.com for cookbooks matching QUERY" 33 | method_options :start => 0, :count => 10 34 | def search(query) 35 | Search.run(query, options[:start], options[:count]) 36 | end 37 | 38 | desc "cook SERVER NODE", "Cook SERVER with the specification in config/NODE.js. Use local as the server to cook this box." 39 | method_options :port => nil 40 | method_options :login => nil 41 | method_options :identity => nil 42 | method_options :log_level => nil 43 | def cook(server, node) 44 | Cook.run(server, node, options[:port], options[:login], options[:identity], options[:log_level]) 45 | end 46 | 47 | desc "prepare SERVER", "Install software/libs required by chef on SERVER" 48 | method_options :port => nil 49 | method_options :login => nil 50 | method_options :identity => nil 51 | method_options :upload_key => nil 52 | method_options :keyfile => :string 53 | method_options :ruby_version => :string 54 | def prepare(server) 55 | Prepare.run(server, options[:port], options[:login], options[:identity], options[:upload_key], options[:keyfile], options[:ruby_version]) 56 | end 57 | 58 | private 59 | def get_cookbook_info(name) 60 | url = URI.parse("%s/cookbooks/%s" % [BASE_URL, name]) 61 | Net::HTTP.get(url) 62 | end 63 | 64 | def get_version_info(name) 65 | latest = JSON.parse(get_cookbook_info(name))["latest_version"] 66 | response = Net::HTTP.get(URI.parse(latest)) 67 | end 68 | 69 | def print_response(response) 70 | item = JSON.parse(response) 71 | item.each_pair do |k, v| 72 | puts "#{k}:\t#{v}" 73 | end 74 | end 75 | end 76 | end 77 | 78 | if __FILE__ == $0 79 | $: << File.dirname(__FILE__) 80 | end 81 | 82 | require 'spatula/ssh_command' 83 | require 'spatula/search' 84 | require 'spatula/prepare' 85 | require 'spatula/cook' 86 | 87 | if __FILE__ == $0 88 | Spatula::Spatula.start 89 | end 90 | -------------------------------------------------------------------------------- /lib/spatula/cook.rb: -------------------------------------------------------------------------------- 1 | module Spatula 2 | # TODO: Set REMOTE_CHEF_PATH using value for file_cache_path 3 | REMOTE_CHEF_PATH = "/tmp/chef-solo" # Where to find upstream cookbooks 4 | 5 | class Cook < SshCommand 6 | def initialize(server, node, port=nil, login=nil, identity=nil, log_level=nil) 7 | super(server, port, login, identity) 8 | @node = node 9 | @log_level = log_level 10 | end 11 | 12 | def run 13 | Dir["**/*.rb"].each do |recipe| 14 | ok = sh "ruby -c #{recipe} >/dev/null 2>&1" 15 | raise "Syntax error in #{recipe}" if not ok 16 | end 17 | 18 | Dir["**/*.json"].each do |json| 19 | begin 20 | require 'json' 21 | # parse without instantiating Chef classes 22 | JSON.parse File.read(json), :create_additions => false 23 | rescue => error 24 | raise "Syntax error in #{json}: #{error.message}" 25 | end 26 | end 27 | 28 | if @server =~ /^local$/i 29 | sh chef_cmd 30 | else 31 | sh "rsync -rlP --rsh=\"ssh #{ssh_opts}\" --delete --exclude '.*' ./ #@server:#{REMOTE_CHEF_PATH}" 32 | ssh "cd #{REMOTE_CHEF_PATH}; #{chef_cmd}" 33 | end 34 | end 35 | 36 | private 37 | def chef_cmd 38 | "sudo -H -E chef-solo -c config/solo.rb -j config/#@node.json -l #{ @log_level || 'info'}" 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /lib/spatula/prepare.rb: -------------------------------------------------------------------------------- 1 | # Prepare :server: for chef solo to run on it 2 | module Spatula 3 | class Prepare < SshCommand 4 | 5 | RUBYGEMS_VERSION = "1.6.2" 6 | DEFAULT_RUBY_VERSION = "1.9.2-p180" 7 | 8 | def run 9 | 10 | if @key_file and !@upload_key 11 | @upload_key = true 12 | end 13 | 14 | upload_ssh_key if @upload_key 15 | send "run_for_#{os}" 16 | end 17 | 18 | def os 19 | etc_issue = `#{ssh_command("cat /etc/issue")}` 20 | case etc_issue 21 | when /ubuntu/i 22 | "ubuntu" 23 | when /debian/i 24 | "debian" 25 | when /fedora/i 26 | "fedora" 27 | when /CentOS/i 28 | "centos" 29 | when "" 30 | raise "Couldn't get system info from /etc/issue. Please check your SSH credentials." 31 | else 32 | raise "Sorry, we currently only support prepare on ubuntu, debian & fedora. Please fork http://github.com/trotter/spatula and add support for your OS. I'm happy to incorporate pull requests." 33 | end 34 | end 35 | 36 | def run_for_ubuntu 37 | ssh "#{sudo} apt-get update" 38 | ssh "#{sudo} apt-get install -y ruby irb ri libopenssl-ruby1.8 libshadow-ruby1.8 ruby1.8-dev build-essential rsync curl" 39 | install_rubygems 40 | install_chef 41 | end 42 | 43 | def run_for_debian 44 | ssh "#{sudo} apt-get update" 45 | ssh "#{sudo} apt-get install -y build-essential zlib1g-dev libssl-dev libreadline5-dev curl rsync" 46 | install_rubygems 47 | install_chef 48 | end 49 | 50 | def run_for_fedora 51 | sudo = ssh('which sudo > /dev/null 2>&1') ? 'sudo' : '' 52 | ssh "#{sudo} yum install -y make gcc gcc-c++ rsync sudo openssl-devel rubygems ruby-devel ruby-shadow curl" 53 | end 54 | 55 | def run_for_centos 56 | ssh "#{sudo} yum install -y make gcc gcc-c++ rsync sudo openssl-devel curl" 57 | install_ruby 58 | install_chef 59 | end 60 | 61 | def ruby_version 62 | @ruby_version || DEFAULT_RUBY_VERSION 63 | end 64 | 65 | def ruby_path 66 | rev = ruby_version.match(/^(\d+\.\d+)/)[1] 67 | "#{rev}/ruby-#{ruby_version}.tar.gz" 68 | end 69 | 70 | def install_ruby 71 | ssh "curl -L 'ftp://ftp.ruby-lang.org/pub/ruby/#{ruby_path}' | tar xvzf -" 72 | ssh "cd ruby-#{ruby_version} && ./configure && make && #{sudo} make install" 73 | end 74 | 75 | def install_rubygems 76 | ssh "curl -L 'http://production.cf.rubygems.org/rubygems/rubygems-#{RUBYGEMS_VERSION}.tgz' | tar xvzf -" 77 | ssh "cd rubygems* && #{sudo} ruby setup.rb --no-ri --no-rdoc" 78 | ssh "#{sudo} ln -sfv /usr/bin/gem1.8 /usr/bin/gem" 79 | end 80 | 81 | def install_chef 82 | ssh "#{sudo} gem install rdoc chef ohai --no-ri --no-rdoc --source http://gems.opscode.com --source http://gems.rubyforge.org" 83 | end 84 | 85 | def sudo 86 | ssh('which sudo > /dev/null 2>&1') ? 'sudo' : '' 87 | end 88 | 89 | def upload_ssh_key 90 | authorized_file = "~/.ssh/authorized_keys" 91 | 92 | unless @key_file 93 | %w{rsa dsa}.each do |key_type| 94 | filename = "#{ENV['HOME']}/.ssh/id_#{key_type}.pub" 95 | if File.exists?(filename) 96 | @key_file = filename 97 | break 98 | end 99 | end 100 | end 101 | 102 | raise "Key file '#{@key_file}' not found: aborting." unless File.exists?(@key_file) 103 | 104 | key = File.open(@key_file).read.split(' ')[0..1].join(' ') 105 | 106 | ssh "mkdir -p .ssh && echo #{key} >> #{authorized_file}" 107 | ssh "cat #{authorized_file} | sort | uniq > #{authorized_file}.tmp && mv #{authorized_file}.tmp #{authorized_file}" 108 | ssh "chmod 0700 .ssh && chmod 0600 #{authorized_file}" 109 | end 110 | end 111 | end 112 | -------------------------------------------------------------------------------- /lib/spatula/search.rb: -------------------------------------------------------------------------------- 1 | # Search for cookbooks matching :query: 2 | module Spatula 3 | class Search 4 | def self.run(*args) 5 | new(*args).run 6 | end 7 | 8 | def initialize(query, start=0, count=10) 9 | @query = query 10 | @start = start 11 | @count = count 12 | end 13 | 14 | def run 15 | url = URI.parse("%s/search?q=%s&start=%s&items=%s" % [BASE_URL, @query, @start, @count]) 16 | response = Net::HTTP.get(url) 17 | items = JSON.parse(response)["items"] 18 | items.each do |item| 19 | puts [item["cookbook_name"], item["cookbook_description"], item["cookbook_maintainer"]].join("\t") 20 | end 21 | end 22 | end 23 | end 24 | 25 | -------------------------------------------------------------------------------- /lib/spatula/ssh_command.rb: -------------------------------------------------------------------------------- 1 | module Spatula 2 | class SshCommand 3 | def self.run(*args) 4 | new(*args).run 5 | end 6 | 7 | def initialize(server, port=nil, login=nil, identity=nil, upload_key=nil, key_file=nil, ruby_version=nil) 8 | @server = server 9 | @port = port 10 | @port_switch = port ? " -p #{port}" : '' 11 | @login_switch = login ? "-l #{login}" : '' 12 | @identity_switch = identity ? %Q|-i "#{identity}"| : '' 13 | @upload_key = upload_key 14 | @key_file = key_file 15 | @ruby_version = ruby_version 16 | end 17 | 18 | def ssh(command) 19 | sh ssh_command(command) 20 | end 21 | 22 | def ssh_command(command) 23 | %Q|ssh -t#{ssh_opts} #@server "#{command.gsub('"', '\\"')}"| 24 | end 25 | 26 | def ssh_opts 27 | "#@port_switch #@login_switch #@identity_switch" 28 | end 29 | 30 | private 31 | def sh(command) 32 | system command 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /scripts/forward_ports.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'rubygems' 4 | require 'virtualbox' 5 | 6 | module VirtualBox 7 | class VM 8 | def main_interface_name 9 | interface = nics.first.nictype 10 | case interface 11 | when /82540EM/ 12 | return 'e1000' 13 | else 14 | abort "Cannot reliably determine the network interface. Email trotter (cashion@gmail.com)" 15 | end 16 | end 17 | 18 | def set_interface_data service, key, value 19 | extra_data["VBoxInternal/Devices/#{main_interface_name}/0/LUN#0/Config/#{service}/#{key}"] = value 20 | end 21 | 22 | def forward_port service, from, to, protocol="TCP" 23 | set_interface_data service, "HostPort", from 24 | set_interface_data service, "GuestPort", to 25 | set_interface_data service, "Protocol", protocol 26 | end 27 | end 28 | end 29 | 30 | if __FILE__ == $0 31 | port = File.read(File.dirname(__FILE__) + "/ssh_port").chomp.to_i 32 | image = ARGV[0] || abort("Usage: #$0 ") 33 | 34 | vm = VirtualBox::VM.find(image) 35 | 36 | puts "Forwarding ports for ssh" 37 | vm.forward_port 'SSH', port, 22 38 | vm.save 39 | end 40 | -------------------------------------------------------------------------------- /scripts/ssh_port: -------------------------------------------------------------------------------- 1 | 3322 2 | -------------------------------------------------------------------------------- /scripts/ssh_to_virtualbox: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ssh -p $(cat $(dirname $0)/ssh_port) -l spatula $@ localhost 4 | -------------------------------------------------------------------------------- /spatula.gemspec: -------------------------------------------------------------------------------- 1 | PKG_VERSION = "0.0.12" 2 | PKG_FILES = Dir['README.textile', 3 | 'bin/*', 4 | 'lib/**/*.rb'] 5 | 6 | $spec = Gem::Specification.new do |s| 7 | s.name = 'spatula' 8 | s.version = PKG_VERSION 9 | s.summary = "Command line helper app for use with Chef" 10 | s.description = <= 0.13.4") 16 | s.add_dependency("json", ">= 1.2.4") 17 | s.files = PKG_FILES.to_a 18 | s.bindir = 'bin' 19 | s.executables = 'spatula' 20 | s.has_rdoc = false 21 | s.author = "Trotter Cashion" 22 | s.email = "cashion@gmail.com" 23 | s.homepage = "http://trottercashion.com" 24 | end 25 | -------------------------------------------------------------------------------- /test/integration/spatula_test.rb: -------------------------------------------------------------------------------- 1 | ## THIS TEST WON'T WORK ON YOUR MACHINE 2 | ## YOU NEED A VM THAT ONLY I HAVE RIGHT NOW 3 | ## Sorry 4 | 5 | require 'test/unit' 6 | 7 | SPATULA_ROOT = File.dirname(__FILE__) + '/../..' 8 | VM_PORT = 3322 9 | IDENTITY = SPATULA_ROOT + '/test/keys/spatula-integration' 10 | 11 | class SpatulaTest < Test::Unit::TestCase 12 | def setup 13 | start_vm("spatula-ubuntu-9.10-64bit") 14 | end 15 | 16 | def teardown 17 | stop_vm 18 | end 19 | 20 | def test_prepares_server 21 | sh "ruby #{SPATULA_ROOT}/lib/spatula.rb prepare localhost --port=#{VM_PORT} --login=spatula --identity=#{IDENTITY}" 22 | assert ssh("gem list | grep chef") 23 | end 24 | 25 | def start_vm(vm) 26 | sh "VBoxManage startvm #{vm}" 27 | sleep 2 until ssh "ls" 28 | end 29 | 30 | def stop_vm 31 | unless ssh "sudo shutdown -h now" 32 | raise "Cannot connect to VM, are you sure it is running?" 33 | end 34 | end 35 | 36 | def ssh(command) 37 | sh %Q|ssh -l spatula -p #{VM_PORT} -i #{IDENTITY} localhost "#{command.gsub('"', '\\"')}"| 38 | end 39 | 40 | def sh(command) 41 | puts "running: #{command}" 42 | system command 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /test/keys/spatula-integration: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEA2r8jdg1R3YYxpGnxWPGgDsd81kqmWR7dYArz7J57iASdscT8 3 | +waOKCLnPnvIZAWm4ZYI9XBsHpt4FGuXGiIYQ6eTWn2P6m+zY9CKPcWNrPrqOJul 4 | tXkv1VbH7c+DMmq9TFSQNGF0lsOpB5bX96C0igqr8mL5TyUATJv0ZuPbfPFHEwHD 5 | p7ugaCTdtktsvY/MI+LjPZH/Mpk5LPBbkUF44R1fTSoGHxveUNVY6qHCkf4TbeeF 6 | WRZa70NcbnCnx7SdocWQjpkWNi97DaX6+/490CMQAwRWr4BvJBG6Ms1CNKm0rjRT 7 | tPE83tfmpcnOyyDHn1qt60migE4nqWJDZyFYUQIBIwKCAQEAx/82XU4BtJfy33bO 8 | CC1fI3SPZNaJdg2XMz02ybV4QdhVqdisyECB+M90VmKLVCJssP40E5n8c8FX2Cfa 9 | m4zi/AbtH4i+GCucswfO2WQpwrmFsBlHDFGK0a5tpjoRjS5j7gQsEqI+tbo0JDIk 10 | iqGPHx+zJsDj8Jbbs8HJgqRw50FNfDedKGe4iIIgEbBwKb+OxrUC93N6mL0CTEfg 11 | pe44OT+dElO6Lvtcs7b1k7yhoMGK4Oc3H+CjgAngFJy3R1wuy4L4TMTpWpDMJTDW 12 | ka8Zuk0H4C5+lLkDktiTCzHg0e9dP510dNiwiyG4ZNGUPNV0BhSxqiKv3wpQyoOz 13 | CbKJiwKBgQD838xEEP2xCgYqYMVy+MjjRVoK4H5GI1lG0QeLf8ixanvjelyLgJit 14 | UrvQFi4ixx1WliioIvhgtS9g+JyobWvKSCeHlH4Ou8WYVFlpQi/a4GNR8+XhjpHz 15 | nm+/fTxoFk5lB0+Vo7DyxNThG3Sp0PpsBr2BtWlUmHHLqQKFddrjJQKBgQDdc1ir 16 | sox9iNBgQiz/Fx1ktTLdHm1q+DE32HoyW/w5+APoBsHm+yBDmYlsOt1PAw0M8cH4 17 | 60BHZgkuX0iW5DwAKwbJZiOoP1uDcJ8nCnbey/t9ceuarkQfnQUZ4VJMOL2BqVCG 18 | sXNJAdYj3A/q15zksfaJ48pdi+kTot+yHqsuvQKBgQCJRkpQ1gYPplseUcpFukEq 19 | 6yJAaz08BI+M19+GPg3cp4UVFooClkRA1SQggRG7G6I2UYPI/Qp9pC+pq4g+LMV8 20 | cE/5JLl1tmPzm4D+oEXdN/tnAL6fBECaMW/c+temN/6r32W3ogD40UBc8aW7RY9B 21 | 9QfKEgX6uSfU9Vkj4OSJ7wKBgAyngWjloaDF/UdUPRXkEE7lyGRoI4J0lRkiUCAi 22 | g3EG26bb0JDbJmpDSa5pw4DbmliC1+JWlfVzi37+IWe1RUHWkqxsPI1FcvGRaC4d 23 | 2ugo6cynbIx+/JQXmeQ4wt/Iul8uPx2jvXHi2QldCDlOJjj0OflAN3MPTyWxiSAf 24 | AnezAoGBAMlgf31IJrYllNGXiLXY1+yyLkODkuGoOim4NxGG2rRe2EBYIVzw/5bM 25 | VnLZE/vx6IBiIDFLXzdL9nqtvBzItCRR7aFIC3I66ZOMUWmHmjsO0sIfTE6BcVKp 26 | V5YDFaLd63TrKyFmy9Fti355xUEY+n9fzKwhxPU1Iy0Y9/YARSjZ 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /test/keys/spatula-integration.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA2r8jdg1R3YYxpGnxWPGgDsd81kqmWR7dYArz7J57iASdscT8+waOKCLnPnvIZAWm4ZYI9XBsHpt4FGuXGiIYQ6eTWn2P6m+zY9CKPcWNrPrqOJultXkv1VbH7c+DMmq9TFSQNGF0lsOpB5bX96C0igqr8mL5TyUATJv0ZuPbfPFHEwHDp7ugaCTdtktsvY/MI+LjPZH/Mpk5LPBbkUF44R1fTSoGHxveUNVY6qHCkf4TbeeFWRZa70NcbnCnx7SdocWQjpkWNi97DaX6+/490CMQAwRWr4BvJBG6Ms1CNKm0rjRTtPE83tfmpcnOyyDHn1qt60migE4nqWJDZyFYUQ== trotter@Trotter-Cashions-MacBook-Pro.local 2 | -------------------------------------------------------------------------------- /test/test-chef-repo/.gitignore: -------------------------------------------------------------------------------- 1 | .rake_test_cache 2 | 3 | -------------------------------------------------------------------------------- /test/test-chef-repo/README: -------------------------------------------------------------------------------- 1 | This is a blank repository you can use as a starting point for your 2 | local chef configuration. For full details on the parts aside from 3 | information contained in the README files, see the Chef wiki document 4 | 5 | http://wiki.opscode.com/display/chef/Chef+Repository 6 | -------------------------------------------------------------------------------- /test/test-chef-repo/Rakefile: -------------------------------------------------------------------------------- 1 | # 2 | # Rakefile for Chef Server Repository 3 | # 4 | # Author:: Adam Jacob () 5 | # Copyright:: Copyright (c) 2008 Opscode, Inc. 6 | # License:: Apache License, Version 2.0 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | require 'rubygems' 22 | require 'chef' 23 | require 'json' 24 | 25 | # Load constants from rake config file. 26 | require File.join(File.dirname(__FILE__), 'config', 'rake') 27 | 28 | # Detect the version control system and assign to $vcs. Used by the update 29 | # task in chef_repo.rake (below). The install task calls update, so this 30 | # is run whenever the repo is installed. 31 | # 32 | # Comment out these lines to skip the update. 33 | 34 | if File.directory?(File.join(TOPDIR, ".svn")) 35 | $vcs = :svn 36 | elsif File.directory?(File.join(TOPDIR, ".git")) 37 | $vcs = :git 38 | end 39 | 40 | # Load common, useful tasks from Chef. 41 | # rake -T to see the tasks this loads. 42 | 43 | load 'chef/tasks/chef_repo.rake' 44 | 45 | desc "Bundle a single cookbook for distribution" 46 | task :bundle_cookbook => [ :metadata ] 47 | task :bundle_cookbook, :cookbook do |t, args| 48 | tarball_name = "#{args.cookbook}.tar.gz" 49 | temp_dir = File.join(Dir.tmpdir, "chef-upload-cookbooks") 50 | temp_cookbook_dir = File.join(temp_dir, args.cookbook) 51 | tarball_dir = File.join(TOPDIR, "pkgs") 52 | FileUtils.mkdir_p(tarball_dir) 53 | FileUtils.mkdir(temp_dir) 54 | FileUtils.mkdir(temp_cookbook_dir) 55 | 56 | child_folders = [ "cookbooks/#{args.cookbook}", "site-cookbooks/#{args.cookbook}" ] 57 | child_folders.each do |folder| 58 | file_path = File.join(TOPDIR, folder, ".") 59 | FileUtils.cp_r(file_path, temp_cookbook_dir) if File.directory?(file_path) 60 | end 61 | 62 | system("tar", "-C", temp_dir, "-cvzf", File.join(tarball_dir, tarball_name), "./#{args.cookbook}") 63 | 64 | FileUtils.rm_rf temp_dir 65 | end 66 | 67 | -------------------------------------------------------------------------------- /test/test-chef-repo/certificates/README: -------------------------------------------------------------------------------- 1 | This directory contains certificates created by the Rakefile. 2 | -------------------------------------------------------------------------------- /test/test-chef-repo/config/client.rb.example: -------------------------------------------------------------------------------- 1 | # 2 | # Example Chef Client Config File 3 | # 4 | # We recommend using Opscode's chef cookbook for managing chef itself, 5 | # instead of using this file. It is provided as an example. 6 | 7 | log_level :info 8 | log_location STDOUT 9 | ssl_verify_mode :verify_none 10 | chef_server_url "http://chef.example.com:4000" 11 | 12 | validation_client_name "chef-validator" 13 | validation_key "/etc/chef/validation.pem" 14 | client_key "/etc/chef/client.pem" 15 | 16 | file_store_path "/srv/chef/file_store" 17 | file_cache_path "/srv/chef/cache" 18 | 19 | pid_file "/var/run/chef/chef-client.pid" 20 | 21 | Mixlib::Log::Formatter.show_time = true 22 | -------------------------------------------------------------------------------- /test/test-chef-repo/config/knife.rb.example: -------------------------------------------------------------------------------- 1 | log_level :info 2 | log_location STDOUT 3 | node_name 'chef_admin' 4 | client_key '/home/chef_admin/.chef/chef_admin.pem' 5 | validation_client_name 'chef-validator' 6 | validation_key '/home/chef_admin/.chef/chef-validator.pem' 7 | chef_server_url 'http://chef.example.com:4000' 8 | cache_type 'BasicFile' 9 | cache_options( :path => '/home/chef_admin/.chef/checksums' ) 10 | cookbook_path [ './cookbooks', './site-cookbooks' ] 11 | -------------------------------------------------------------------------------- /test/test-chef-repo/config/local.json: -------------------------------------------------------------------------------- 1 | { 2 | "recipes": ["test_cookbook"] 3 | } 4 | -------------------------------------------------------------------------------- /test/test-chef-repo/config/rake.rb: -------------------------------------------------------------------------------- 1 | ### 2 | # Company and SSL Details 3 | ### 4 | 5 | # The company name - used for SSL certificates, and in srvious other places 6 | COMPANY_NAME = "Example Com" 7 | 8 | # The Country Name to use for SSL Certificates 9 | SSL_COUNTRY_NAME = "US" 10 | 11 | # The State Name to use for SSL Certificates 12 | SSL_STATE_NAME = "Several" 13 | 14 | # The Locality Name for SSL - typically, the city 15 | SSL_LOCALITY_NAME = "Locality" 16 | 17 | # What department? 18 | SSL_ORGANIZATIONAL_UNIT_NAME = "Operations" 19 | 20 | # The SSL contact email address 21 | SSL_EMAIL_ADDRESS = "ops@example.com" 22 | 23 | # License for new Cookbooks 24 | # Can be :apachev2 or :none 25 | NEW_COOKBOOK_LICENSE = :apachev2 26 | 27 | ########################## 28 | # Chef Repository Layout # 29 | ########################## 30 | 31 | # Where to install upstream cookbooks for serving 32 | COOKBOOK_PATH = "/srv/chef/cookbooks" 33 | 34 | # Where to install site-local modifications to upstream cookbooks 35 | SITE_COOKBOOK_PATH = "/srv/chef/site-cookbooks" 36 | 37 | # Where to install roles 38 | ROLE_PATH = "/srv/chef/roles" 39 | 40 | # Chef Config Path 41 | CHEF_CONFIG_PATH = "/etc/chef" 42 | 43 | # The location of the Chef Server Config file (on the server) 44 | CHEF_SERVER_CONFIG = File.join(CHEF_CONFIG_PATH, "server.rb") 45 | 46 | # The location of the Chef Client Config file (on the client) 47 | CHEF_CLIENT_CONFIG = File.join(CHEF_CONFIG_PATH, "client.rb") 48 | 49 | ### 50 | # Useful Extras (which you probably don't need to change) 51 | ### 52 | 53 | # The top of the repository checkout 54 | TOPDIR = File.expand_path(File.join(File.dirname(__FILE__), "..")) 55 | 56 | # Where to store certificates generated with ssl_cert 57 | CADIR = File.expand_path(File.join(TOPDIR, "certificates")) 58 | 59 | # Where to store the mtime cache for the recipe/template syntax check 60 | TEST_CACHE = File.expand_path(File.join(TOPDIR, ".rake_test_cache")) -------------------------------------------------------------------------------- /test/test-chef-repo/config/server.rb.example: -------------------------------------------------------------------------------- 1 | # 2 | # Chef Server Config File 3 | # 4 | # We recommend using Opscode's chef cookbook for managing chef itself, 5 | # instead of using this file. It is provided as an example. 6 | 7 | log_level :info 8 | log_location STDOUT 9 | ssl_verify_mode :verify_none 10 | chef_server_url "http://chef.example.com:4000" 11 | 12 | signing_ca_path "/srv/chef/ca" 13 | couchdb_database 'chef' 14 | 15 | cookbook_path [ "/srv/chef/cookbooks", "/srv/chef/site-cookbooks" ] 16 | 17 | file_cache_path "/srv/chef/cache" 18 | node_path "/srv/chef/nodes" 19 | openid_store_path "/srv/chef/openid/store" 20 | openid_cstore_path "/srv/chef/openid/cstore" 21 | search_index_path "/srv/chef/search_index" 22 | role_path "/srv/chef/roles" 23 | 24 | validation_client_name "chef-validator" 25 | validation_key "/etc/chef/validation.pem" 26 | client_key "/etc/chef/client.pem" 27 | web_ui_client_name "chef-webui" 28 | web_ui_key "/etc/chef/webui.pem" 29 | 30 | # change this as required. 31 | #web_ui_admin_user_name "admin" 32 | #web_ui_admin_default_password "replace_with_something_secure" 33 | 34 | supportdir = "/srv/chef/support" 35 | solr_jetty_path File.join(supportdir, "solr", "jetty") 36 | solr_data_path File.join(supportdir, "solr", "data") 37 | solr_home_path File.join(supportdir, "solr", "home") 38 | solr_heap_size "256M" 39 | 40 | umask 0022 41 | 42 | Mixlib::Log::Formatter.show_time = false 43 | -------------------------------------------------------------------------------- /test/test-chef-repo/config/solo.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Chef Solo Config File 3 | # 4 | 5 | base_path = File.expand_path(File.dirname(__FILE__) + '/..') 6 | 7 | log_level :info 8 | log_location STDOUT 9 | file_cache_path "/var/chef/cookbooks" 10 | 11 | file_cache_path base_path 12 | cookbook_path ["#{base_path}/site-cookbooks", 13 | "#{base_path}/cookbooks"] 14 | 15 | # Optionally store your JSON data file and a tarball of cookbooks remotely. 16 | #json_attribs "http://chef.example.com/dna.json" 17 | #recipe_url "http://chef.example.com/cookbooks.tar.gz" 18 | 19 | Mixlib::Log::Formatter.show_time = true 20 | -------------------------------------------------------------------------------- /test/test-chef-repo/cookbooks/README: -------------------------------------------------------------------------------- 1 | This directory contains upstream or shared cookbooks. 2 | 3 | To replace this with a Git repository, remove this directory and 4 | clone the upstream repository. 5 | -------------------------------------------------------------------------------- /test/test-chef-repo/cookbooks/test_cookbook/README.rdoc: -------------------------------------------------------------------------------- 1 | = DESCRIPTION: 2 | 3 | = REQUIREMENTS: 4 | 5 | = ATTRIBUTES: 6 | 7 | = USAGE: 8 | 9 | -------------------------------------------------------------------------------- /test/test-chef-repo/cookbooks/test_cookbook/metadata.rb: -------------------------------------------------------------------------------- 1 | maintainer "Example Com" 2 | maintainer_email "ops@example.com" 3 | license "Apache 2.0" 4 | description "Installs/Configures test_cookbook" 5 | long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc')) 6 | version "0.1" 7 | -------------------------------------------------------------------------------- /test/test-chef-repo/cookbooks/test_cookbook/recipes/default.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Cookbook Name:: test_cookbook 3 | # Recipe:: default 4 | # 5 | # Copyright 2010, Example Com 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | directory "#{ENV['HOME']}/test_dir" do 21 | action :create 22 | end 23 | -------------------------------------------------------------------------------- /test/test-chef-repo/roles/README: -------------------------------------------------------------------------------- 1 | Create roles here, in either .rb or .json files. To install roles on the 2 | server, use knife. We provide an example role here. 3 | 4 | knife role from file roles/base_example.rb 5 | -------------------------------------------------------------------------------- /test/test-chef-repo/roles/base_example.rb: -------------------------------------------------------------------------------- 1 | name "base_example" 2 | description "Example base role applied to all nodes." 3 | # List of recipes and roles to apply. Requires Chef 0.8, earlier versions use 'recipes()'. 4 | #run_list() 5 | 6 | # Attributes applied if the node doesn't have it set already. 7 | #default_attributes() 8 | 9 | # Attributes applied no matter what the node has set already. 10 | #override_attributes() 11 | -------------------------------------------------------------------------------- /test/test-chef-repo/site-cookbooks/README: -------------------------------------------------------------------------------- 1 | This directory contains cookbooks that modify upstream ones, 2 | or that are specific to your site. 3 | --------------------------------------------------------------------------------