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.
Files changed (49) hide show
  1. data/.travis.yml +2 -0
  2. data/CHANGELOG.md +4 -0
  3. data/README.md +31 -30
  4. data/bin/gusteau +14 -13
  5. data/gusteau.gemspec +4 -1
  6. data/lib/gusteau.rb +1 -0
  7. data/lib/gusteau/bureau.rb +32 -20
  8. data/lib/gusteau/chef.rb +2 -2
  9. data/lib/gusteau/config.rb +39 -0
  10. data/lib/gusteau/node.rb +11 -43
  11. data/lib/gusteau/ssh_config.rb +8 -7
  12. data/lib/gusteau/vagrant.rb +7 -32
  13. data/lib/gusteau/version.rb +1 -1
  14. data/spec/config/gusteau.yml +60 -0
  15. data/spec/config/remi.yml +29 -0
  16. data/spec/lib/gusteau/bureau_spec.rb +52 -0
  17. data/spec/lib/gusteau/compressed_tar_stream_spec.rb +31 -0
  18. data/spec/lib/gusteau/config_spec.rb +31 -0
  19. data/spec/lib/gusteau/log_spec.rb +34 -0
  20. data/spec/lib/gusteau/node_spec.rb +40 -85
  21. data/spec/lib/gusteau/server_spec.rb +12 -0
  22. data/spec/lib/gusteau/ssh_config_spec.rb +16 -10
  23. data/spec/lib/gusteau/ssh_spec.rb +110 -0
  24. data/spec/lib/gusteau/vagrant_spec.rb +46 -17
  25. data/spec/spec_helper.rb +11 -0
  26. data/template/.gusteau.yml.erb +21 -0
  27. data/template/.kitchen.yml +20 -0
  28. data/template/Berksfile +3 -3
  29. data/template/Gemfile +6 -1
  30. data/template/README.md.erb +70 -0
  31. data/template/Vagrantfile +12 -4
  32. data/template/init.sh +27 -0
  33. data/template/site-cookbooks/cowsay/metadata.rb +10 -0
  34. data/template/site-cookbooks/cowsay/recipes/default.rb +1 -3
  35. data/template/site-cookbooks/platform/metadata.rb +14 -0
  36. data/template/site-cookbooks/platform/recipes/default.rb +3 -0
  37. data/template/test/integration/data_bags/users/remi.json +7 -0
  38. data/template/test/integration/default/serverspec/localhost/cowsay_spec.rb +5 -0
  39. data/template/test/integration/default/serverspec/localhost/platform_spec.rb +25 -0
  40. data/template/test/integration/default/serverspec/spec_helper.rb +9 -0
  41. metadata +81 -17
  42. data/bootstrap/centos.sh +0 -17
  43. data/bootstrap/redhat.sh +0 -17
  44. data/bootstrap/ubuntu.sh +0 -17
  45. data/spec/nodes/development.yml +0 -17
  46. data/spec/nodes/production.yml +0 -18
  47. data/spec/nodes/staging.yml +0 -12
  48. data/template/nodes/example.yml.erb +0 -19
  49. 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
- subject { Gusteau::SSHConfig.new('./spec') }
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 2222
13
- User developer
13
+ Port 22
14
+ User root
14
15
 
15
- Host production
16
- HostName www.example.com
16
+ Host staging-www
17
+ HostName staging.myapp.com
17
18
  Port 22
18
19
  User root
19
20
 
20
- Host staging
21
- HostName staging.example.com
22
- Port 2222
23
- User devops
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) { mock() }
7
- let(:vm) { mock() }
8
- let(:instance) { mock() }
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
- yield instance
14
- end
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.dir = './spec/nodes'
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.dir = './spec/nodes'
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(:node) { ::Gusteau::Node.new('./spec/nodes/development.yml') }
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 => 4,
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
@@ -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]
@@ -2,6 +2,6 @@
2
2
 
3
3
  site :opscode
4
4
 
5
- cookbook 'apt'
6
- cookbook 'build-essential'
7
- cookbook 'user'
5
+ %w{ cowsay platform }.each do |c|
6
+ cookbook c, :path => "./site-cookbooks/#{c}"
7
+ end
@@ -1,6 +1,11 @@
1
1
  # vi:ft=ruby:
2
2
 
3
- source 'http://rubygems.org'
3
+ source 'https://rubygems.org'
4
4
 
5
5
  gem 'berkshelf'
6
6
  gem 'gusteau'
7
+
8
+ group :integration do
9
+ gem 'test-kitchen', github: 'opscode/test-kitchen'
10
+ gem 'kitchen-vagrant', '~> 0.10.0'
11
+ end
@@ -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!*