gusteau 0.4.8 → 1.0.0.dev
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.travis.yml +2 -0
- data/CHANGELOG.md +4 -0
- data/README.md +31 -30
- data/bin/gusteau +14 -13
- data/gusteau.gemspec +4 -1
- data/lib/gusteau.rb +1 -0
- data/lib/gusteau/bureau.rb +32 -20
- data/lib/gusteau/chef.rb +2 -2
- data/lib/gusteau/config.rb +39 -0
- data/lib/gusteau/node.rb +11 -43
- data/lib/gusteau/ssh_config.rb +8 -7
- data/lib/gusteau/vagrant.rb +7 -32
- data/lib/gusteau/version.rb +1 -1
- data/spec/config/gusteau.yml +60 -0
- data/spec/config/remi.yml +29 -0
- data/spec/lib/gusteau/bureau_spec.rb +52 -0
- data/spec/lib/gusteau/compressed_tar_stream_spec.rb +31 -0
- data/spec/lib/gusteau/config_spec.rb +31 -0
- data/spec/lib/gusteau/log_spec.rb +34 -0
- data/spec/lib/gusteau/node_spec.rb +40 -85
- data/spec/lib/gusteau/server_spec.rb +12 -0
- data/spec/lib/gusteau/ssh_config_spec.rb +16 -10
- data/spec/lib/gusteau/ssh_spec.rb +110 -0
- data/spec/lib/gusteau/vagrant_spec.rb +46 -17
- data/spec/spec_helper.rb +11 -0
- data/template/.gusteau.yml.erb +21 -0
- data/template/.kitchen.yml +20 -0
- data/template/Berksfile +3 -3
- data/template/Gemfile +6 -1
- data/template/README.md.erb +70 -0
- data/template/Vagrantfile +12 -4
- data/template/init.sh +27 -0
- data/template/site-cookbooks/cowsay/metadata.rb +10 -0
- data/template/site-cookbooks/cowsay/recipes/default.rb +1 -3
- data/template/site-cookbooks/platform/metadata.rb +14 -0
- data/template/site-cookbooks/platform/recipes/default.rb +3 -0
- data/template/test/integration/data_bags/users/remi.json +7 -0
- data/template/test/integration/default/serverspec/localhost/cowsay_spec.rb +5 -0
- data/template/test/integration/default/serverspec/localhost/platform_spec.rb +25 -0
- data/template/test/integration/default/serverspec/spec_helper.rb +9 -0
- metadata +81 -17
- data/bootstrap/centos.sh +0 -17
- data/bootstrap/redhat.sh +0 -17
- data/bootstrap/ubuntu.sh +0 -17
- data/spec/nodes/development.yml +0 -17
- data/spec/nodes/production.yml +0 -18
- data/spec/nodes/staging.yml +0 -12
- data/template/nodes/example.yml.erb +0 -19
- data/template/roles/platform.rb +0 -8
@@ -54,6 +54,18 @@ describe Gusteau::Server do
|
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
+
describe "#upload" do
|
58
|
+
let(:pr) { "/tmp/gusteau-test" }
|
59
|
+
|
60
|
+
before { ["#{pr}/cookbooks", "#{pr}/.git"].each { |d| FileUtils.mkdir_p(d) } }
|
61
|
+
after { FileUtils.rm_rf(pr) }
|
62
|
+
|
63
|
+
it "skips the excluded files" do
|
64
|
+
server.expects(:send_files).with(["#{pr}/cookbooks"], "/etc/chef")
|
65
|
+
server.upload(["#{pr}/cookbooks", "#{pr}/.git"], "/etc/chef", { :exclude => "#{pr}/.git" })
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
57
69
|
describe "#prepared_cmd" do
|
58
70
|
subject { server.send(:prepared_cmd, 'cd /etc/chef && touch test') }
|
59
71
|
|
@@ -1,26 +1,32 @@
|
|
1
1
|
require './spec/spec_helper.rb'
|
2
2
|
|
3
3
|
describe Gusteau::SSHConfig do
|
4
|
-
|
4
|
+
let(:nodes) { Gusteau::Config.nodes("./spec/config/gusteau.yml") }
|
5
|
+
subject { Gusteau::SSHConfig.new(nodes) }
|
5
6
|
|
6
7
|
let(:config) do
|
7
8
|
<<-eos
|
8
9
|
# BEGIN GUSTEAU NODES
|
9
10
|
|
10
|
-
Host development
|
11
|
+
Host development-playground
|
11
12
|
HostName 192.168.100.21
|
12
|
-
Port
|
13
|
-
User
|
13
|
+
Port 22
|
14
|
+
User root
|
14
15
|
|
15
|
-
Host
|
16
|
-
HostName
|
16
|
+
Host staging-www
|
17
|
+
HostName staging.myapp.com
|
17
18
|
Port 22
|
18
19
|
User root
|
19
20
|
|
20
|
-
Host
|
21
|
-
HostName
|
22
|
-
Port
|
23
|
-
User
|
21
|
+
Host production-db
|
22
|
+
HostName db.myapp.com
|
23
|
+
Port 22
|
24
|
+
User billy
|
25
|
+
|
26
|
+
Host production-www
|
27
|
+
HostName www.myapp.com
|
28
|
+
Port 22
|
29
|
+
User billy
|
24
30
|
|
25
31
|
# END GUSTEAU NODES
|
26
32
|
eos
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require './spec/spec_helper'
|
2
|
+
|
3
|
+
describe Gusteau::SSH do
|
4
|
+
let(:connector_class) do
|
5
|
+
class Example
|
6
|
+
include Gusteau::SSH
|
7
|
+
attr_accessor :host, :port, :user, :password
|
8
|
+
end
|
9
|
+
Example
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:connector) { connector_class.new }
|
13
|
+
|
14
|
+
describe "#conn" do
|
15
|
+
before do
|
16
|
+
connector.host = 'microsoft.com'
|
17
|
+
connector.port = 2202
|
18
|
+
connector.user = 'ray'
|
19
|
+
end
|
20
|
+
|
21
|
+
context "password is present" do
|
22
|
+
it "should use SSH port and password when present" do
|
23
|
+
connector.password = 'qwerty123'
|
24
|
+
|
25
|
+
Net::SSH.expects(:start).with('microsoft.com', 'ray', {:port => 2202, :password => 'qwerty123'})
|
26
|
+
connector.conn
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "password is not present" do
|
31
|
+
it "should not use password" do
|
32
|
+
Net::SSH.expects(:start).with('microsoft.com', 'ray', {:port => 2202})
|
33
|
+
connector.conn
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "send methods" do
|
39
|
+
let(:conn) { stub_everything('conn') }
|
40
|
+
let(:channel) { stub_everything('channel') }
|
41
|
+
|
42
|
+
before do
|
43
|
+
connector.expects(:conn).at_least_once.returns(conn)
|
44
|
+
|
45
|
+
def conn.open_channel
|
46
|
+
yield channel
|
47
|
+
channel # is this the correct way to test it?
|
48
|
+
end
|
49
|
+
conn.expects(:channel).at_least_once.returns(channel)
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#send_command" do
|
53
|
+
context "user is root" do
|
54
|
+
before { connector.user = 'root' }
|
55
|
+
|
56
|
+
it "should execute the command as is" do
|
57
|
+
channel.expects(:exec).with('cowsay')
|
58
|
+
connector.send_command 'cowsay'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "user is not root" do
|
63
|
+
before { connector.user = 'vaskas' }
|
64
|
+
|
65
|
+
it "should execute the command with sudo" do
|
66
|
+
channel.expects(:exec).with("sudo -- sh -c 'cowsay'")
|
67
|
+
connector.send_command 'cowsay'
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "success status" do
|
72
|
+
let(:success) { true }
|
73
|
+
|
74
|
+
before do
|
75
|
+
def channel.exec(cmd); yield true, success; end
|
76
|
+
channel.expects(:success).returns(success)
|
77
|
+
end
|
78
|
+
|
79
|
+
context "command succeeded" do
|
80
|
+
it "should start receiving data" do
|
81
|
+
channel.expects(:on_data)
|
82
|
+
connector.send_command 'sl'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context "command failed" do
|
87
|
+
let(:success) { false }
|
88
|
+
|
89
|
+
it "should raise an exception" do
|
90
|
+
proc { connector.send_command 'sl' }.must_raise RuntimeError
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "#send_files" do
|
97
|
+
before do
|
98
|
+
connector.user = 'root'
|
99
|
+
connector.expects(:compressed_tar_stream).returns(mock())
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should execute the extraction command and send the data" do
|
103
|
+
channel.expects(:exec).with("tar zxf - -C /etc/chef")
|
104
|
+
channel.expects(:send_data)
|
105
|
+
|
106
|
+
connector.send_files(%w{ a b }, '/etc/chef')
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -1,31 +1,39 @@
|
|
1
1
|
require './spec/spec_helper.rb'
|
2
2
|
|
3
3
|
describe Gusteau::Vagrant do
|
4
|
+
let(:instance) { mock() }
|
5
|
+
let(:subvm) { stub_everything('subvm') }
|
4
6
|
|
5
7
|
describe "#detect" do
|
6
|
-
let(:config)
|
7
|
-
let(:vm)
|
8
|
-
let(:
|
9
|
-
let(:subvm) { stub_everything('subvm') }
|
8
|
+
let(:config) { mock() }
|
9
|
+
let(:vm) { mock() }
|
10
|
+
let(:virtualbox) { stub_everything('virtualbox') }
|
10
11
|
|
11
12
|
before do
|
12
|
-
def vm.define(name)
|
13
|
-
|
14
|
-
|
13
|
+
def vm.define(name); yield instance; end
|
14
|
+
vm.expects(:instance).at_least_once.returns(instance)
|
15
|
+
|
16
|
+
def subvm.provider(type); yield virtualbox; end
|
17
|
+
subvm.expects(:virtualbox).at_least_once.returns(virtualbox)
|
15
18
|
|
16
19
|
config.expects(:vm).at_least_once.returns(vm)
|
17
|
-
vm.expects(:instance).at_least_once.returns(instance)
|
18
20
|
instance.expects(:vm).at_least_once.returns(subvm)
|
19
21
|
end
|
20
22
|
|
21
23
|
it "should define vm instances with correct settings" do
|
22
|
-
subvm.expects('box='.to_sym).with('development')
|
24
|
+
subvm.expects('box='.to_sym).with('development-playground')
|
23
25
|
subvm.expects('box_url='.to_sym).with("http://a.com/b.box")
|
24
26
|
subvm.expects(:network).with(:private_network, { :ip => '192.168.100.21' })
|
25
27
|
subvm.expects(:provision).never
|
26
28
|
|
29
|
+
virtualbox.expects(:customize).with ['modifyvm', :id,
|
30
|
+
'--memory', 1024,
|
31
|
+
'--name', 'development-playground',
|
32
|
+
'--cpus', 2,
|
33
|
+
'--natdnsproxy1', 'on']
|
34
|
+
|
27
35
|
Gusteau::Vagrant.detect(config) do |setup|
|
28
|
-
setup.
|
36
|
+
setup.config_path = './spec/config/gusteau.yml'
|
29
37
|
setup.defaults.box_url = "http://a.com/b.box"
|
30
38
|
end
|
31
39
|
end
|
@@ -34,7 +42,7 @@ describe Gusteau::Vagrant do
|
|
34
42
|
subvm.expects(:provision).with('chef_solo')
|
35
43
|
|
36
44
|
Gusteau::Vagrant.detect(config) do |setup|
|
37
|
-
setup.
|
45
|
+
setup.config_path = './spec/config/gusteau.yml'
|
38
46
|
setup.defaults.box_url = "http://a.com/b.box"
|
39
47
|
setup.provision = true
|
40
48
|
end
|
@@ -42,6 +50,7 @@ describe Gusteau::Vagrant do
|
|
42
50
|
end
|
43
51
|
|
44
52
|
describe "#vm_config" do
|
53
|
+
let(:node) { Gusteau::Config.nodes("./spec/config/gusteau.yml")['development-playground'] }
|
45
54
|
subject { Gusteau::Vagrant.vm_config(node, options) }
|
46
55
|
|
47
56
|
let(:defaults) do
|
@@ -54,16 +63,14 @@ describe Gusteau::Vagrant do
|
|
54
63
|
let(:prefix) { 'hyper' }
|
55
64
|
let(:options) { { :defaults => defaults, :prefix => prefix } }
|
56
65
|
|
57
|
-
let(:
|
58
|
-
|
59
|
-
let(:expected_label) { 'hyper-development' }
|
66
|
+
let(:expected_label) { 'hyper-development-playground' }
|
60
67
|
let(:expected_config) do
|
61
68
|
{
|
62
|
-
:name => 'development',
|
69
|
+
:name => 'development-playground',
|
63
70
|
:label => expected_label,
|
64
71
|
:box_url => 'https://opscode.s3.amazonaws.com/centos-6.4.box',
|
65
72
|
:ip => '192.168.100.21',
|
66
|
-
:cpus =>
|
73
|
+
:cpus => 2,
|
67
74
|
:memory => 4096
|
68
75
|
}
|
69
76
|
end
|
@@ -74,7 +81,7 @@ describe Gusteau::Vagrant do
|
|
74
81
|
|
75
82
|
context "prefix not specified" do
|
76
83
|
let(:prefix) { nil }
|
77
|
-
let(:expected_label) { 'development' }
|
84
|
+
let(:expected_label) { 'development-playground' }
|
78
85
|
|
79
86
|
it "should omit the prefix" do
|
80
87
|
subject.must_equal(expected_config)
|
@@ -89,4 +96,26 @@ describe Gusteau::Vagrant do
|
|
89
96
|
end
|
90
97
|
end
|
91
98
|
end
|
99
|
+
|
100
|
+
describe "#define_provisioner" do
|
101
|
+
let(:node) { Gusteau::Config.nodes("./spec/config/gusteau.yml")['development-playground'] }
|
102
|
+
let(:chef) { stub_everything('chef') }
|
103
|
+
|
104
|
+
before do
|
105
|
+
def subvm.provision(provider); yield chef; end
|
106
|
+
subvm.expects(:chef).returns(chef)
|
107
|
+
|
108
|
+
instance.expects(:vm).at_least_once.returns(subvm)
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should set the correct Chef JSON" do
|
112
|
+
chef.expects('json='.to_sym).with({"mysql"=>{"server_root_password"=>"guesswhat"}})
|
113
|
+
Gusteau::Vagrant.define_provisioner(instance, node)
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should set the correct Chef run_list" do
|
117
|
+
chef.expects('run_list='.to_sym).with(["recipe[zsh]", "recipe[mysql::server]"])
|
118
|
+
Gusteau::Vagrant.define_provisioner(instance, node)
|
119
|
+
end
|
120
|
+
end
|
92
121
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
require 'coveralls'
|
2
|
+
require 'simplecov'
|
3
|
+
|
4
|
+
if ENV['COVERAGE'] == 'coveralls'
|
5
|
+
Coveralls.wear!
|
6
|
+
else
|
7
|
+
SimpleCov.start do
|
8
|
+
add_filter "/spec/"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
1
12
|
$LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
2
13
|
require 'lib/gusteau'
|
3
14
|
require 'minitest/autorun'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
environments:
|
2
|
+
example:
|
3
|
+
attributes:
|
4
|
+
users:
|
5
|
+
- <%= @login %>
|
6
|
+
cowsay:
|
7
|
+
greeting: "Good job, <%= @login %>!"
|
8
|
+
|
9
|
+
run_list:
|
10
|
+
- recipe[platform]
|
11
|
+
- recipe[cowsay]
|
12
|
+
|
13
|
+
nodes:
|
14
|
+
box:
|
15
|
+
host: 33.33.33.10
|
16
|
+
user: vagrant
|
17
|
+
password: vagrant
|
18
|
+
vagrant:
|
19
|
+
IP: 33.33.33.10
|
20
|
+
cpu: 1
|
21
|
+
memory: 256
|
@@ -0,0 +1,20 @@
|
|
1
|
+
---
|
2
|
+
driver_plugin: vagrant
|
3
|
+
|
4
|
+
platforms:
|
5
|
+
- name: ubuntu-13.04
|
6
|
+
driver_config:
|
7
|
+
box: opscode-ubuntu-13.04
|
8
|
+
box_url: https://opscode-vm.s3.amazonaws.com/vagrant/opscode_ubuntu-13.04_provisionerless.box
|
9
|
+
require_chef_omnibus: true
|
10
|
+
|
11
|
+
suites:
|
12
|
+
- name: default
|
13
|
+
attributes:
|
14
|
+
users:
|
15
|
+
- remi
|
16
|
+
cowsay:
|
17
|
+
greeting: "Hello test-kitchen"
|
18
|
+
run_list:
|
19
|
+
- recipe[platform]
|
20
|
+
- recipe[cowsay]
|
data/template/Berksfile
CHANGED
data/template/Gemfile
CHANGED
@@ -0,0 +1,70 @@
|
|
1
|
+
# chef-repo
|
2
|
+
|
3
|
+
Welcome to your example Chef-Repo, <%= @login %>.
|
4
|
+
|
5
|
+
Now that you've installed everything, let's have a look around.
|
6
|
+
|
7
|
+
## Structure
|
8
|
+
|
9
|
+
### .gusteau.yml
|
10
|
+
|
11
|
+
A configuration file for all your environments and nodes. This project features one environment, `example` which only includes one node, `box`.
|
12
|
+
|
13
|
+
### Vagrantfile
|
14
|
+
|
15
|
+
A configuration file for Vagrant which includes gusteau as a plugin. It detects all your `.gusteau.yml` nodes with `vagrant` keys in them and configures Vagrant instances for them. The `example-box` node is one such example.
|
16
|
+
|
17
|
+
### cookbooks
|
18
|
+
|
19
|
+
Gusteau uploads `site-cookbooks` and `cookbooks` directories when you converge a node. Between the two, `cookbooks` is a directory for your vendorized cookbooks. This example project uses Berkshelf, so in order to populate the directory run
|
20
|
+
|
21
|
+
```
|
22
|
+
berks install --path ./cookbooks
|
23
|
+
```
|
24
|
+
|
25
|
+
### site-cookbooks
|
26
|
+
|
27
|
+
Your repo-specific or work-in-progress cookbooks. A good place to store your [wrapper cookbooks](http://devopsanywhere.blogspot.com.au/2012/11/how-to-write-reusable-chef-cookbooks.html).
|
28
|
+
|
29
|
+
### data_bags
|
30
|
+
|
31
|
+
Chef Data bags. A way to store large pieces of domain-specifc configuration. See the included `users` data_bag for an example.
|
32
|
+
|
33
|
+
## Using gusteau
|
34
|
+
|
35
|
+
To try gusteau first with an example Vagrant node, bring it up:
|
36
|
+
|
37
|
+
```
|
38
|
+
vagrant up example-box
|
39
|
+
```
|
40
|
+
|
41
|
+
Then run `gusteau converge`:
|
42
|
+
|
43
|
+
```
|
44
|
+
gusteau converge example-box
|
45
|
+
```
|
46
|
+
|
47
|
+
## Testing your Chef-Repo
|
48
|
+
|
49
|
+
It is a very good practice to have tests for your Chef-driven infrastructure.
|
50
|
+
This project includes an example [test-kitchen](https://github.com/opscode/test-kitchen) setup to get you started.
|
51
|
+
|
52
|
+
The tests are implemented using the excellent [serverspec](http://serverspec.org/) framework.
|
53
|
+
|
54
|
+
There are two important bits to have a look at:
|
55
|
+
|
56
|
+
### test
|
57
|
+
|
58
|
+
The directory where integration tests are placed.
|
59
|
+
|
60
|
+
### .kitchen.yml
|
61
|
+
|
62
|
+
Test-kitchen configuration file where test platforms and suites are specified.
|
63
|
+
|
64
|
+
To run the tests:
|
65
|
+
|
66
|
+
```
|
67
|
+
bundle exec kitchen test
|
68
|
+
```
|
69
|
+
|
70
|
+
*Happy cooking with Chef and Gusteau!*
|