toque 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/.travis.yml +4 -0
- data/Capfile +3 -0
- data/Gemfile +12 -0
- data/LICENSE.txt +22 -0
- data/README.md +109 -0
- data/Rakefile +6 -0
- data/Vagrantfile +99 -0
- data/lib/toque.rb +18 -0
- data/lib/toque/chef.rb +145 -0
- data/lib/toque/helpers.rb +69 -0
- data/lib/toque/tasks.rb +20 -0
- data/lib/toque/version.rb +12 -0
- data/spec/config/cookbooks/awesomeium/recipes/default.rb +8 -0
- data/spec/config/cookbooks/awesomeium/recipes/second.rb +7 -0
- data/spec/config/deploy.rb +35 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/spec_toque.rb +54 -0
- data/spec/toque/chef_spec.rb +129 -0
- data/spec/toque/helpers_spec.rb +39 -0
- data/toque.gemspec +22 -0
- metadata +86 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 728adde958810a994d9d16b9d51d2f8cd31ef9dd
|
4
|
+
data.tar.gz: f56fb4afebd0bfc9defe5a9e995a4f26a4466f17
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2c689a0d5f297ed1cbd9c4fba502ecf4ab918770afe4eef89c936d1a207dc3593d85e476c5ce127a2e384d1d23d50cb036d4c46c905b0fc938c02cd16ada185f
|
7
|
+
data.tar.gz: d13815fc714a02a45cb16a4fb3a783e970b3761910b5387078a3aa8464cf0401104fcc7de1b1b21b5b39716174ad1ca826e4af7b6b9269b9e2a4561ee1c297cd
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Capfile
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in toque.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
group :development, :test do
|
7
|
+
gem 'rake'
|
8
|
+
gem 'rspec'
|
9
|
+
gem 'vagrant', '>= 1.0.7'
|
10
|
+
gem 'bundler', '~> 1.3'
|
11
|
+
gem 'capistrano-spec', github: 'jgraichen/capistrano-spec'
|
12
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Jan Graichen
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
# Toque - The cap of a Chef
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/jgraichen/toque.png?branch=master)](https://travis-ci.org/jgraichen/toque)
|
4
|
+
|
5
|
+
**Toque** combines the power of *chef-solo* and *capistrano*. It allows you to
|
6
|
+
run chef cookbooks with chef-solo as part of your capistrano deploy process.
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
gem 'toque'
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install toque
|
21
|
+
|
22
|
+
After capifying your project add to your `Capfile`:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
require 'toque'
|
26
|
+
```
|
27
|
+
|
28
|
+
You can install chef by running `cap toque:chef:install` otherwise it will be
|
29
|
+
installed on first `run_list` call. **Toque** uses chef omnibus installer to
|
30
|
+
install a complete self-contained embedded chef environment.
|
31
|
+
|
32
|
+
You can specify a specific chef version by setting `:chef_version` to
|
33
|
+
something different to `:latest` or `nil`. An already installed version of
|
34
|
+
chef will not be upgraded.
|
35
|
+
|
36
|
+
See `cap toque:config` for more options.
|
37
|
+
|
38
|
+
## Usage
|
39
|
+
|
40
|
+
**Toque** assumes your cookbooks to be in `config/cookbooks` or
|
41
|
+
`vendor/cookbooks`. One way is to use `config/cookbooks` for your own
|
42
|
+
application cookbook(s) and `vendor/cookbooks` for community cookbooks managed
|
43
|
+
by [librarian-chef](https://github.com/applicationsonline/librarian-chef).
|
44
|
+
|
45
|
+
You can configure *librarian-chef* to use `vendor/cookbooks` as cookbook path:
|
46
|
+
|
47
|
+
```bash
|
48
|
+
$ librarian-chef config path ./vendor/cookbooks --local
|
49
|
+
```
|
50
|
+
|
51
|
+
In your deploy configuration you can now run `toque.run_list` with a list of
|
52
|
+
recipes you want to execute. You can run chef more then once with different
|
53
|
+
list.
|
54
|
+
|
55
|
+
For example if you want to setup the server before deploying your app run
|
56
|
+
your setup recipe right at the start:
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
before "deploy:update_code" do
|
60
|
+
toque.run_list 'recipe[awesome::setup]'
|
61
|
+
end
|
62
|
+
```
|
63
|
+
|
64
|
+
After deploying your app you may need to create a config for your application
|
65
|
+
like `database.yml` or redis configuration:
|
66
|
+
|
67
|
+
after "deploy:create_symlink" do
|
68
|
+
toque.run_list 'recipe[awesome::configure]'
|
69
|
+
end
|
70
|
+
|
71
|
+
## Configuration
|
72
|
+
|
73
|
+
By default all capistrano options are available in your node configuration:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
# config/deploy.rb
|
77
|
+
|
78
|
+
set :application, 'awesomeium'
|
79
|
+
set :deploy_to, "/var/www/#{application}"
|
80
|
+
set :user, 'awesomeix'
|
81
|
+
|
82
|
+
# config/cookbooks/awesome/recipes/configure.rb
|
83
|
+
|
84
|
+
template File.join(node[:deploy_to], 'config', 'database.yml') do
|
85
|
+
source 'database.yml.erb'
|
86
|
+
owner node[:user]
|
87
|
+
recursive true
|
88
|
+
end
|
89
|
+
```
|
90
|
+
|
91
|
+
## Thanks
|
92
|
+
|
93
|
+
Thanks to [roundsman](https://github.com/iain/roundsman) doing even some more
|
94
|
+
tasks like installing ruby and chef via rubygems. I've decided to make up
|
95
|
+
something new to use omnibus installer right from the start.
|
96
|
+
|
97
|
+
Also take a look at
|
98
|
+
[capistrano-spec](https://github.com/technicalpickles/capistrano-spec) allowing
|
99
|
+
some really great capistrano testing.
|
100
|
+
|
101
|
+
## Contributing
|
102
|
+
|
103
|
+
1. Fork it
|
104
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
105
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
106
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
107
|
+
5. Create new Pull Request
|
108
|
+
|
109
|
+
You can run a simple vagrant based test by running `bundle exec rspec spec/spec_toque.rb`.
|
data/Rakefile
ADDED
data/Vagrantfile
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
# -*- mode: ruby -*-
|
2
|
+
# vi: set ft=ruby :
|
3
|
+
|
4
|
+
Vagrant::Config.run do |config|
|
5
|
+
# All Vagrant configuration is done here. The most common configuration
|
6
|
+
# options are documented and commented below. For a complete reference,
|
7
|
+
# please see the online documentation at vagrantup.com.
|
8
|
+
|
9
|
+
# Every Vagrant virtual environment requires a box to build off of.
|
10
|
+
config.vm.box = 'precise32'
|
11
|
+
|
12
|
+
# The url from where the 'config.vm.box' box will be fetched if it
|
13
|
+
# doesn't already exist on the user's system.
|
14
|
+
config.vm.box_url = 'http://files.vagrantup.com/precise32.box'
|
15
|
+
|
16
|
+
# Boot with a GUI so you can see the screen. (Default is headless)
|
17
|
+
# config.vm.boot_mode = :gui
|
18
|
+
|
19
|
+
# Assign this VM to a host-only network IP, allowing you to access it
|
20
|
+
# via the IP. Host-only networks can talk to the host machine as well as
|
21
|
+
# any other machines on the same network, but cannot be accessed (through this
|
22
|
+
# network interface) by any external networks.
|
23
|
+
config.vm.network :hostonly, "192.168.33.10"
|
24
|
+
|
25
|
+
# Assign this VM to a bridged network, allowing you to connect directly to a
|
26
|
+
# network using the host's network device. This makes the VM appear as another
|
27
|
+
# physical device on your network.
|
28
|
+
# config.vm.network :bridged
|
29
|
+
|
30
|
+
# Forward a port from the guest to the host, which allows for outside
|
31
|
+
# computers to access the VM, whereas host only networking does not.
|
32
|
+
# config.vm.forward_port 80, 8080
|
33
|
+
|
34
|
+
# Share an additional folder to the guest VM. The first argument is
|
35
|
+
# an identifier, the second is the path on the guest to mount the
|
36
|
+
# folder, and the third is the path on the host to the actual folder.
|
37
|
+
# config.vm.share_folder "v-data", "/vagrant_data", "../data"
|
38
|
+
|
39
|
+
# Enable provisioning with Puppet stand alone. Puppet manifests
|
40
|
+
# are contained in a directory path relative to this Vagrantfile.
|
41
|
+
# You will need to create the manifests directory and a manifest in
|
42
|
+
# the file base.pp in the manifests_path directory.
|
43
|
+
#
|
44
|
+
# An example Puppet manifest to provision the message of the day:
|
45
|
+
#
|
46
|
+
# # group { "puppet":
|
47
|
+
# # ensure => "present",
|
48
|
+
# # }
|
49
|
+
# #
|
50
|
+
# # File { owner => 0, group => 0, mode => 0644 }
|
51
|
+
# #
|
52
|
+
# # file { '/etc/motd':
|
53
|
+
# # content => "Welcome to your Vagrant-built virtual machine!
|
54
|
+
# # Managed by Puppet.\n"
|
55
|
+
# # }
|
56
|
+
#
|
57
|
+
# config.vm.provision :puppet do |puppet|
|
58
|
+
# puppet.manifests_path = "manifests"
|
59
|
+
# puppet.manifest_file = "base.pp"
|
60
|
+
# end
|
61
|
+
|
62
|
+
# Enable provisioning with chef solo, specifying a cookbooks path, roles
|
63
|
+
# path, and data_bags path (all relative to this Vagrantfile), and adding
|
64
|
+
# some recipes and/or roles.
|
65
|
+
#
|
66
|
+
# config.vm.provision :chef_solo do |chef|
|
67
|
+
# chef.cookbooks_path = "../my-recipes/cookbooks"
|
68
|
+
# chef.roles_path = "../my-recipes/roles"
|
69
|
+
# chef.data_bags_path = "../my-recipes/data_bags"
|
70
|
+
# chef.add_recipe "mysql"
|
71
|
+
# chef.add_role "web"
|
72
|
+
#
|
73
|
+
# # You may also specify custom JSON attributes:
|
74
|
+
# chef.json = { :mysql_password => "foo" }
|
75
|
+
# end
|
76
|
+
|
77
|
+
# Enable provisioning with chef server, specifying the chef server URL,
|
78
|
+
# and the path to the validation key (relative to this Vagrantfile).
|
79
|
+
#
|
80
|
+
# The Opscode Platform uses HTTPS. Substitute your organization for
|
81
|
+
# ORGNAME in the URL and validation key.
|
82
|
+
#
|
83
|
+
# If you have your own Chef Server, use the appropriate URL, which may be
|
84
|
+
# HTTP instead of HTTPS depending on your configuration. Also change the
|
85
|
+
# validation key to validation.pem.
|
86
|
+
#
|
87
|
+
# config.vm.provision :chef_client do |chef|
|
88
|
+
# chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME"
|
89
|
+
# chef.validation_key_path = "ORGNAME-validator.pem"
|
90
|
+
# end
|
91
|
+
#
|
92
|
+
# If you're using the Opscode platform, your validator client is
|
93
|
+
# ORGNAME-validator, replacing ORGNAME with your organization name.
|
94
|
+
#
|
95
|
+
# IF you have your own Chef Server, the default validation client name is
|
96
|
+
# chef-validator, unless you changed the configuration.
|
97
|
+
#
|
98
|
+
# chef.validation_client_name = "ORGNAME-validator"
|
99
|
+
end
|
data/lib/toque.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'capistrano'
|
2
|
+
|
3
|
+
require 'toque/version'
|
4
|
+
require 'toque/helpers'
|
5
|
+
require 'toque/tasks'
|
6
|
+
require 'toque/chef'
|
7
|
+
|
8
|
+
module Toque
|
9
|
+
def self.load_into(configuration)
|
10
|
+
Toque::Helpers.load_into configuration
|
11
|
+
Toque::Tasks.load_into configuration
|
12
|
+
Toque::Chef.load_into configuration
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
if Capistrano::Configuration.instance
|
17
|
+
Toque.load_into Capistrano::Configuration.instance
|
18
|
+
end
|
data/lib/toque/chef.rb
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
module Toque
|
4
|
+
|
5
|
+
# Tasks and method to interact with chef.
|
6
|
+
#
|
7
|
+
module Chef
|
8
|
+
def self.load_into(configuration)
|
9
|
+
configuration.load do
|
10
|
+
|
11
|
+
namespace :toque do
|
12
|
+
namespace :chef do
|
13
|
+
|
14
|
+
set_default :chef_omnibus_installer_url, 'http://www.opscode.com/chef/install.sh'
|
15
|
+
set_default :cookbooks_paths, %w(config/cookbooks vendor/cookbooks)
|
16
|
+
set_default :databags_path, 'config/databags'
|
17
|
+
set_default :chef_version, :latest
|
18
|
+
set_default :chef_debug, false
|
19
|
+
set_default :chef_solo, '/opt/chef/bin/chef-solo'
|
20
|
+
|
21
|
+
# Check if chef-solo installed on remote machine.
|
22
|
+
#
|
23
|
+
def installed?
|
24
|
+
!installed_version.nil?
|
25
|
+
end
|
26
|
+
|
27
|
+
# Return installed chef-solo version.
|
28
|
+
#
|
29
|
+
def installed_version
|
30
|
+
capture("#{chef_solo} -v || true") =~ /Chef: (\d+\.\d+\.\d+)/ ? $1 : nil
|
31
|
+
end
|
32
|
+
|
33
|
+
# Return path to chef solo executable.
|
34
|
+
#
|
35
|
+
def chef_solo
|
36
|
+
fetch(:chef_solo).to_s || 'chef-solo'
|
37
|
+
end
|
38
|
+
|
39
|
+
# Return list of current recipes in run_list.
|
40
|
+
#
|
41
|
+
def recipes
|
42
|
+
Array fetch(:run_list)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Return list of existing cookbook paths.
|
46
|
+
#
|
47
|
+
def cookbooks_paths
|
48
|
+
fetch(:cookbooks_paths).to_a.select { |path| File.exists? path }
|
49
|
+
end
|
50
|
+
|
51
|
+
# Abort if no existing cookbook paths are setted.
|
52
|
+
#
|
53
|
+
def ensure_cookbooks!
|
54
|
+
raise 'No existing cookbook paths found.' if cookbooks_paths.empty?
|
55
|
+
end
|
56
|
+
|
57
|
+
# Return existing databag path or nil if path does not exist.
|
58
|
+
#
|
59
|
+
def databags_path
|
60
|
+
File.exists?((path = fetch(:databags_path))) ? path : nil
|
61
|
+
end
|
62
|
+
|
63
|
+
# Create and return omnibus installer command
|
64
|
+
#
|
65
|
+
def install_command
|
66
|
+
cmd = "#{top.sudo} bash"
|
67
|
+
cmd += " -s -- -v #{fetch :chef_version}" unless fetch(:chef_version) == :latest or fetch(:chef_version).nil?
|
68
|
+
cmd
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
# Tasks
|
73
|
+
#
|
74
|
+
|
75
|
+
desc 'Install chef via omnibus installed if not preset.'
|
76
|
+
task :check do
|
77
|
+
install unless installed?
|
78
|
+
end
|
79
|
+
|
80
|
+
desc 'Installs chef using omnibus installer.'
|
81
|
+
task :install do
|
82
|
+
require_curl
|
83
|
+
run "#{top.sudo} true && curl -L #{fetch :chef_omnibus_installer_url} | #{install_command}"
|
84
|
+
end
|
85
|
+
|
86
|
+
namespace :setup do
|
87
|
+
desc 'Upload local cookbook to remote server.'
|
88
|
+
task :cookbooks do
|
89
|
+
pwd!
|
90
|
+
|
91
|
+
tar = ::Tempfile.new("cookbooks.tar")
|
92
|
+
begin
|
93
|
+
tar.close
|
94
|
+
system "tar -cjf #{tar.path} #{cookbooks_paths.join(' ')} #{databags_path.to_s}"
|
95
|
+
upload tar.path, toque.pwd("cookbooks.tar"), :via => :scp
|
96
|
+
run "cd #{toque.pwd} && tar -xjf cookbooks.tar"
|
97
|
+
ensure
|
98
|
+
tar.unlink
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
desc 'Generate and upload chef solo script.'
|
103
|
+
task :script do
|
104
|
+
pwd!
|
105
|
+
|
106
|
+
cookbooks = cookbooks_paths.map { |p| %("#{pwd p}") }.join(', ')
|
107
|
+
solo = <<-HEREDOC
|
108
|
+
file_cache_path "#{pwd! 'cache'}"
|
109
|
+
cookbook_path [ #{cookbooks} ]
|
110
|
+
data_bag_path "#{pwd databags_path}"
|
111
|
+
HEREDOC
|
112
|
+
put solo, pwd("node.rb"), :via => :scp
|
113
|
+
end
|
114
|
+
|
115
|
+
desc 'Generate and upload node json configuration.'
|
116
|
+
task :configuration do
|
117
|
+
pwd!
|
118
|
+
|
119
|
+
attrs = variables.dup
|
120
|
+
attrs[:run_list] = recipes
|
121
|
+
put attrs.to_json, pwd("node.json"), :via => :scp
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
desc 'Run list of recipes from `:run_list` option.'
|
126
|
+
task :run_list do
|
127
|
+
ensure_cookbooks!
|
128
|
+
|
129
|
+
check
|
130
|
+
setup.cookbooks
|
131
|
+
setup.script
|
132
|
+
setup.configuration
|
133
|
+
|
134
|
+
logger.info "Now running #{recipes.join(', ')}"
|
135
|
+
|
136
|
+
sudo "#{chef_solo} -c #{pwd "node.rb"} -j #{pwd "node.json"}#{' -l debug' if fetch(:chef_debug)}"
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Toque
|
2
|
+
|
3
|
+
# Toque helpers
|
4
|
+
#
|
5
|
+
module Helpers
|
6
|
+
def self.load_into(configuration)
|
7
|
+
configuration.load do
|
8
|
+
|
9
|
+
namespace :toque do
|
10
|
+
|
11
|
+
# Set toque default variable.
|
12
|
+
#
|
13
|
+
def set_default(variable, *args, &block)
|
14
|
+
@_toque_variables ||= []
|
15
|
+
@_toque_overridden ||= []
|
16
|
+
@_toque_variables << variable
|
17
|
+
if exists? variable
|
18
|
+
@_toque_overridden << variable
|
19
|
+
else
|
20
|
+
set variable, *args, &block
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Return toque remote working directory.
|
25
|
+
#
|
26
|
+
def pwd(*path)
|
27
|
+
File.join(fetch(:toque_pwd).to_s, *path.map(&:to_s))
|
28
|
+
end
|
29
|
+
set_default :toque_pwd, '/tmp/toque'
|
30
|
+
|
31
|
+
# Return toque remote working directory. Will be created remotely if not existing.
|
32
|
+
#
|
33
|
+
def pwd!(*path)
|
34
|
+
run "mkdir -p #{pwd = pwd(*path)}"
|
35
|
+
pwd
|
36
|
+
end
|
37
|
+
|
38
|
+
# Search if curl is present
|
39
|
+
#
|
40
|
+
def curl?
|
41
|
+
!(capture('curl || true') =~ /not found/)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Install curl if not present
|
45
|
+
#
|
46
|
+
def require_curl
|
47
|
+
sudo 'apt-get install --no-install-recommends -yq curl' unless curl?
|
48
|
+
end
|
49
|
+
|
50
|
+
desc 'List current toque configuration'
|
51
|
+
task :config do
|
52
|
+
@_toque_variables.sort_by(&:to_s).each do |name|
|
53
|
+
display_name = ":#{name},".ljust(30)
|
54
|
+
if variables[name].is_a?(Proc)
|
55
|
+
value = "<block>"
|
56
|
+
else
|
57
|
+
value = fetch(name).inspect
|
58
|
+
value = "#{value[0..40]}... (truncated)" if value.length > 40
|
59
|
+
end
|
60
|
+
overridden = @_toque_overridden.include?(name) ? " (overridden)" : ""
|
61
|
+
puts "set #{display_name} #{value}#{overridden}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/toque/tasks.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Toque
|
2
|
+
module Tasks
|
3
|
+
def self.load_into(configuration)
|
4
|
+
configuration.load do
|
5
|
+
|
6
|
+
namespace :toque do
|
7
|
+
|
8
|
+
# Run list of recipes. Install chef if not already preset.
|
9
|
+
#
|
10
|
+
def run_list(*recipes)
|
11
|
+
set :run_list, recipes
|
12
|
+
chef.run_list
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'vagrant'
|
2
|
+
|
3
|
+
set :application, 'awesomeium'
|
4
|
+
|
5
|
+
set :repository, '.'
|
6
|
+
set :scm, :none # not recommended in production
|
7
|
+
set :deploy_via, :copy
|
8
|
+
|
9
|
+
server '192.168.33.10', :web, :app, :db, :primary => true
|
10
|
+
|
11
|
+
set :user, 'vagrant'
|
12
|
+
set :password, 'vagrant' # not recommended in production
|
13
|
+
|
14
|
+
set :deploy_to, "/home/#{user}/#{application}"
|
15
|
+
|
16
|
+
set :use_sudo, false
|
17
|
+
default_run_options[:pty] = true
|
18
|
+
|
19
|
+
# Toque options
|
20
|
+
set :cookbooks_paths, %w(spec/config/cookbooks)
|
21
|
+
|
22
|
+
namespace :vagrant do
|
23
|
+
task :up do
|
24
|
+
Vagrant::Environment.new.cli 'up'
|
25
|
+
end
|
26
|
+
|
27
|
+
task :destroy do
|
28
|
+
Vagrant::Environment.new.cli 'destroy'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
task :spec do
|
33
|
+
toque.run_list "recipe[awesomeium]"
|
34
|
+
end
|
35
|
+
before 'spec', 'vagrant:up'
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'capistrano-spec'
|
2
|
+
require 'toque'
|
3
|
+
|
4
|
+
Dir[File.expand_path('spec/support/**/*.rb')].each {|f| require f}
|
5
|
+
|
6
|
+
RSpec.configure do |config|
|
7
|
+
config.include Capistrano::Spec::Matchers
|
8
|
+
config.include Capistrano::Spec::Helpers
|
9
|
+
|
10
|
+
config.order = "random"
|
11
|
+
|
12
|
+
config.expect_with :rspec do |c|
|
13
|
+
# Only allow expect syntax
|
14
|
+
c.syntax = :expect
|
15
|
+
end
|
16
|
+
end
|
data/spec/spec_toque.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'vagrant'
|
3
|
+
|
4
|
+
describe Toque do
|
5
|
+
|
6
|
+
before do
|
7
|
+
@vagrant = Vagrant::Environment.new
|
8
|
+
@vagrant.cli 'up'
|
9
|
+
|
10
|
+
@configuration = Capistrano::Configuration.new
|
11
|
+
Toque.load_into(@configuration)
|
12
|
+
|
13
|
+
@configuration.load do
|
14
|
+
|
15
|
+
server '192.168.33.10', :web, :app, :db, :primary => true
|
16
|
+
set :user, 'vagrant'
|
17
|
+
set :password, 'vagrant'
|
18
|
+
|
19
|
+
set :use_sudo, false
|
20
|
+
default_run_options[:pty] = true
|
21
|
+
|
22
|
+
# Toque options
|
23
|
+
set :cookbooks_paths, %w(spec/config/cookbooks)
|
24
|
+
set :chef_version, '10.24.0'
|
25
|
+
|
26
|
+
task :awesome! do
|
27
|
+
toque.run_list 'recipe[awesomeium]'
|
28
|
+
end
|
29
|
+
|
30
|
+
task :awesome_the_second! do
|
31
|
+
toque.run_list 'recipe[awesomeium::second]'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
@configuration.sudo 'apt-get remove -yq curl'
|
36
|
+
@configuration.sudo 'apt-get autoremove -yq'
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should write an awesome file' do
|
40
|
+
@configuration.awesome!
|
41
|
+
|
42
|
+
# should have installed chef version
|
43
|
+
expect(@configuration.capture('/opt/chef/bin/chef-solo -v').strip).to be == 'Chef: 10.24.0'
|
44
|
+
|
45
|
+
# should have executed cookbook and created an awesome file
|
46
|
+
file_exists = @vagrant.primary_vm.channel.sudo 'ls /tmp/toque/awesome'
|
47
|
+
expect(file_exists).to be == 0
|
48
|
+
|
49
|
+
@configuration.awesome_the_second!
|
50
|
+
|
51
|
+
file_exists = @vagrant.primary_vm.channel.sudo 'ls /tmp/toque/awesome', :error_check => false
|
52
|
+
expect(file_exists).to_not be == 0
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Toque::Chef, 'loaded into capistrano' do
|
4
|
+
before do
|
5
|
+
@configuration = Capistrano::Configuration.new
|
6
|
+
@configuration.extend Capistrano::Spec::ConfigurationExtension
|
7
|
+
Toque.load_into(@configuration)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should define default omnibus installer URL' do
|
11
|
+
expect(@configuration.fetch :chef_omnibus_installer_url).to be == 'http://www.opscode.com/chef/install.sh'
|
12
|
+
end
|
13
|
+
|
14
|
+
it "defines toque:chef:install task" do
|
15
|
+
expect(@configuration.find_task 'toque:chef:install').to_not be_nil
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#installed?' do
|
19
|
+
it 'detect if chef-solo is not installed' do
|
20
|
+
expect(@configuration.toque.chef.installed?).to be_false
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'detect if chef-solo is installed' do
|
24
|
+
@configuration.stub_command '/opt/chef/bin/chef-solo -v || true', data: 'Chef: 11.4.0'
|
25
|
+
expect(@configuration.toque.chef.installed?).to be_true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#installed_version' do
|
30
|
+
it 'should fetch installed chef version' do
|
31
|
+
@configuration.stub_command '/opt/chef/bin/chef-solo -v || true', data: 'Chef: 11.4.0'
|
32
|
+
expect(@configuration.toque.chef.installed_version).to be == '11.4.0'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#cookbooks_paths' do
|
37
|
+
it 'should return existing cookbook paths' do
|
38
|
+
File.stub(:exists?).with('config/cookbooks').and_return true
|
39
|
+
File.stub(:exists?).with('vendor/cookbooks').and_return false
|
40
|
+
|
41
|
+
expect(@configuration.toque.chef.cookbooks_paths).to be == %w(config/cookbooks)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#ensure_cookbooks!' do
|
46
|
+
it 'should abort if no cookbook path exist' do
|
47
|
+
File.stub(:exists?).with('config/cookbooks').and_return false
|
48
|
+
File.stub(:exists?).with('vendor/cookbooks').and_return false
|
49
|
+
|
50
|
+
expect{ @configuration.toque.chef.ensure_cookbooks! }.to raise_error
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#databags_path' do
|
55
|
+
it 'should return path if exists' do
|
56
|
+
File.stub(:exists?).with('config/databags').and_return true
|
57
|
+
|
58
|
+
expect(@configuration.toque.chef.databags_path).to be == 'config/databags'
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should return nit if path does not exists' do
|
62
|
+
File.stub(:exists?).with('config/databags').and_return false
|
63
|
+
|
64
|
+
expect(@configuration.toque.chef.databags_path).to be_nil
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe '#chef_solo' do
|
69
|
+
it 'should return path to chef solo executable' do
|
70
|
+
expect(@configuration.toque.chef.chef_solo).to be == '/opt/chef/bin/chef-solo'
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should return path to custom chef solo executable' do
|
74
|
+
@configuration.set :chef_solo, 'chef-solo'
|
75
|
+
expect(@configuration.toque.chef.chef_solo).to be == 'chef-solo'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '#upload_cookbooks' do
|
80
|
+
before do
|
81
|
+
File.stub(:exists?).and_return false
|
82
|
+
File.stub(:exists?).with('config/cookbooks').and_return true
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'should create working dir' do
|
86
|
+
@configuration.toque.chef.setup.cookbooks
|
87
|
+
|
88
|
+
expect(@configuration).to have_run 'mkdir -p /tmp/toque'
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should upload cookbooks' do
|
92
|
+
@configuration.toque.chef.setup.cookbooks
|
93
|
+
|
94
|
+
expect(@configuration).to have_uploaded.to('/tmp/toque/cookbooks.tar')
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should extract cookbooks on server' do
|
98
|
+
@configuration.toque.chef.setup.cookbooks
|
99
|
+
|
100
|
+
expect(@configuration).to have_run 'cd /tmp/toque && tar -xjf cookbooks.tar'
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe 'toque:chef:install' do
|
105
|
+
|
106
|
+
it 'should install chef using omnibus installer' do
|
107
|
+
@configuration.toque.chef.install
|
108
|
+
expect(@configuration).to have_run("sudo -p 'sudo password: ' true && curl -L http://www.opscode.com/chef/install.sh | sudo -p 'sudo password: ' bash")
|
109
|
+
end
|
110
|
+
|
111
|
+
context 'with custom installer URL' do
|
112
|
+
before { @configuration.set :chef_omnibus_installer_url, 'http://mysrv.tld/inst.sh' }
|
113
|
+
|
114
|
+
it 'should install chef using custom omnibus installer' do
|
115
|
+
@configuration.toque.chef.install
|
116
|
+
expect(@configuration).to have_run("sudo -p 'sudo password: ' true && curl -L http://mysrv.tld/inst.sh | sudo -p 'sudo password: ' bash")
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context 'with specific chef version' do
|
121
|
+
before { @configuration.set :chef_version, '10.24.0' }
|
122
|
+
|
123
|
+
it 'should install chef using custom omnibus installer' do
|
124
|
+
@configuration.toque.chef.install
|
125
|
+
expect(@configuration).to have_run("sudo -p 'sudo password: ' true && curl -L http://www.opscode.com/chef/install.sh | sudo -p 'sudo password: ' bash -s -- -v 10.24.0")
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Toque::Helpers, 'loaded into capistrano' do
|
4
|
+
before do
|
5
|
+
@configuration = Capistrano::Configuration.new
|
6
|
+
@configuration.extend Capistrano::Spec::ConfigurationExtension
|
7
|
+
Toque.load_into(@configuration)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#pwd' do
|
11
|
+
it 'return toque working dir' do
|
12
|
+
expect(@configuration.toque.pwd).to be == '/tmp/toque'
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'return custom path if set' do
|
16
|
+
@configuration.set :toque_pwd, '/tmp/custom_path'
|
17
|
+
expect(@configuration.toque.pwd).to be == '/tmp/custom_path'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#pwd!' do
|
22
|
+
it 'return create remote working dir' do
|
23
|
+
@configuration.toque.pwd!
|
24
|
+
expect(@configuration).to have_run 'mkdir -p /tmp/toque'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#curl?' do
|
29
|
+
it 'return true if curl exists' do
|
30
|
+
@configuration.stub_command 'curl || true', data: "curl: try 'curl --help' or 'curl --manual' for more information"
|
31
|
+
expect(@configuration.toque.curl?).to be_true
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'return false if curl is missing' do
|
35
|
+
@configuration.stub_command 'curl || true', data: "sh: command not found"
|
36
|
+
expect(@configuration.toque.curl?).to be_false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/toque.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'toque/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'toque'
|
8
|
+
spec.version = Toque::VERSION
|
9
|
+
spec.authors = ['Jan Graichen']
|
10
|
+
spec.email = %w(jg@altimos.de)
|
11
|
+
spec.description = %q{Toque: Cap of a Chef. Integrate Chef into Capistrano.}
|
12
|
+
spec.summary = %q{Toque: Cap of a Chef. Integrate Chef into Capistrano.}
|
13
|
+
spec.homepage = 'https://github.com/jgraichen/toque'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = %w(lib)
|
20
|
+
|
21
|
+
spec.add_dependency 'capistrano'
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: toque
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jan Graichen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-04-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: capistrano
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: 'Toque: Cap of a Chef. Integrate Chef into Capistrano.'
|
28
|
+
email:
|
29
|
+
- jg@altimos.de
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- .gitignore
|
35
|
+
- .travis.yml
|
36
|
+
- Capfile
|
37
|
+
- Gemfile
|
38
|
+
- LICENSE.txt
|
39
|
+
- README.md
|
40
|
+
- Rakefile
|
41
|
+
- Vagrantfile
|
42
|
+
- lib/toque.rb
|
43
|
+
- lib/toque/chef.rb
|
44
|
+
- lib/toque/helpers.rb
|
45
|
+
- lib/toque/tasks.rb
|
46
|
+
- lib/toque/version.rb
|
47
|
+
- spec/config/cookbooks/awesomeium/recipes/default.rb
|
48
|
+
- spec/config/cookbooks/awesomeium/recipes/second.rb
|
49
|
+
- spec/config/deploy.rb
|
50
|
+
- spec/spec_helper.rb
|
51
|
+
- spec/spec_toque.rb
|
52
|
+
- spec/toque/chef_spec.rb
|
53
|
+
- spec/toque/helpers_spec.rb
|
54
|
+
- toque.gemspec
|
55
|
+
homepage: https://github.com/jgraichen/toque
|
56
|
+
licenses:
|
57
|
+
- MIT
|
58
|
+
metadata: {}
|
59
|
+
post_install_message:
|
60
|
+
rdoc_options: []
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - '>='
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - '>='
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
requirements: []
|
74
|
+
rubyforge_project:
|
75
|
+
rubygems_version: 2.0.3
|
76
|
+
signing_key:
|
77
|
+
specification_version: 4
|
78
|
+
summary: 'Toque: Cap of a Chef. Integrate Chef into Capistrano.'
|
79
|
+
test_files:
|
80
|
+
- spec/config/cookbooks/awesomeium/recipes/default.rb
|
81
|
+
- spec/config/cookbooks/awesomeium/recipes/second.rb
|
82
|
+
- spec/config/deploy.rb
|
83
|
+
- spec/spec_helper.rb
|
84
|
+
- spec/spec_toque.rb
|
85
|
+
- spec/toque/chef_spec.rb
|
86
|
+
- spec/toque/helpers_spec.rb
|