gusteau 1.0.3.dev → 1.0.4.dev

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
+ ## 1.0.4.dev / 2013-07-08
2
+ * Bugfix: `after` hook was not taking effect
3
+ * Add a quick `show nodename` subcommand for printing out individual node configuration
4
+ * Add an ability to configure `cookbooks_path` and `roles_path` from within `.gusteau.yml`
5
+
1
6
  ## 1.0.3.dev / 2013-07-07
2
- * Implement 'before' and 'after' hooks (global and environment-based)
7
+ * Implement `before` and `after` hooks (global and environment-based)
3
8
 
4
9
  ## 1.0.2.dev / 2013-07-06
5
10
  * Fix Ruby 1.8.7 and Rubinius compatibility
data/bin/gusteau CHANGED
@@ -40,21 +40,31 @@ class Gusteau::CLI < Optitron::CLI
40
40
 
41
41
  desc 'Lists all known nodes'
42
42
  def list
43
- puts "Known nodes are:\n - #{nodes.keys.join("\n - ")}"
43
+ puts nodes_list
44
+ end
45
+
46
+ desc 'Show the configuration of a specific node'
47
+ def show(node_name)
48
+ puts node(node_name).config.to_yaml
44
49
  end
45
50
 
46
51
  private
47
52
 
48
53
  def node(node_name)
49
54
  unless node = nodes[node_name]
50
- abort "Node '#{node_name}' is unknown. Known nodes are #{nodes.keys.join(', ')}."
55
+ abort "Node '#{node_name}' is unknown. #{nodes_list}"
51
56
  else
52
57
  node
53
58
  end
54
59
  end
55
60
 
56
61
  def nodes
57
- @nodes ||= Gusteau::Config.nodes(".gusteau.yml")
62
+ Gusteau::Config.read('.gusteau.yml')
63
+ Gusteau::Config.nodes
64
+ end
65
+
66
+ def nodes_list
67
+ "Known nodes are:\n - #{nodes.keys.join("\n - ")}"
58
68
  end
59
69
 
60
70
  end
data/lib/gusteau/chef.rb CHANGED
@@ -26,14 +26,12 @@ module Gusteau
26
26
  private
27
27
 
28
28
  def src_files(dna_path)
29
- %W(
29
+ list = %W(
30
30
  #{dna_path}
31
31
  #{File.expand_path("../../../bootstrap", __FILE__)}
32
- ./cookbooks
33
- ./site-cookbooks
34
- ./roles
35
- ./data_bags
36
- ).select { |file| File.exists? file }
32
+ data_bags
33
+ ) + Gusteau::Config.settings['cookbooks_path'] + [ Gusteau::Config.settings['roles_path']]
34
+ list.select { |file| File.exists? file }
37
35
  end
38
36
  end
39
37
  end
@@ -2,42 +2,66 @@ require 'gusteau/erb'
2
2
  require 'hash_deep_merge'
3
3
 
4
4
  module Gusteau
5
- module Config
6
- extend self
7
- extend Gusteau::ERB
8
-
9
- def nodes(config_path)
10
- if File.exists?(config_path)
11
- config = read_erb_yaml(config_path)
12
- env_config = config['environments']
13
-
14
- env_config.inject({}) do |nodes, (env_name, env_hash)|
15
- if env_hash['nodes']
16
- env_hash['nodes'].each_pair do |node_name, node_hash|
17
- node_name = "#{env_name}-#{node_name}"
18
- nodes[node_name] = build_node(config, node_name, env_hash, node_hash)
19
- end
20
- end
21
- nodes
22
- end
5
+ class Config
6
+ include Gusteau::ERB
7
+
8
+ def self.read(config_path)
9
+ @instance = Gusteau::Config.new(config_path)
10
+ end
11
+
12
+ def self.nodes
13
+ @instance.send(:nodes)
14
+ end
15
+
16
+ def self.settings
17
+ @instance.send(:settings)
18
+ end
19
+
20
+ def initialize(config_path)
21
+ @config = if File.exists?(config_path)
22
+ read_erb_yaml(config_path)
23
23
  else
24
24
  abort ".gusteau.yml not found"
25
25
  end
26
26
  end
27
27
 
28
+ private
29
+
30
+ def nodes
31
+ env_config = @config['environments']
32
+
33
+ @nodes ||= env_config.inject({}) do |nodes, (env_name, env_hash)|
34
+ if env_hash['nodes']
35
+ env_hash['nodes'].each_pair do |node_name, node_hash|
36
+ node_name = "#{env_name}-#{node_name}"
37
+ nodes[node_name] = build_node(node_name, env_hash, node_hash)
38
+ end
39
+ end
40
+ nodes
41
+ end
42
+ end
43
+
44
+ def settings
45
+ {
46
+ 'cookbooks_path' => @config['cookbooks_path'] || ['cookbooks', 'site-cookbooks'],
47
+ 'roles_path' => @config['roles_path'] || 'roles'
48
+ }
49
+ end
50
+
28
51
  #
29
52
  # Node attributes get deep-merged with the environment ones
30
53
  # Node run_list overrides the environment one
31
54
  # Environment before hooks override global ones
32
55
  #
33
- def build_node(config, node_name, env_hash, node_hash)
34
- config = {
56
+ def build_node(node_name, env_hash, node_hash)
57
+ node_config = {
35
58
  'server' => node_hash,
36
59
  'attributes' => (env_hash['attributes'] || {}).deep_merge(node_hash['attributes'] || {}),
37
- 'run_list' => node_hash['run_list'] || env_hash['run_list'],
38
- 'before' => env_hash['before'] || config['before']
60
+ 'run_list' => node_hash['run_list'] || env_hash['run_list'],
61
+ 'before' => env_hash['before'] || @config['before'],
62
+ 'after' => env_hash['after'] || @config['after']
39
63
  }
40
- Gusteau::Node.new(node_name, config)
64
+ Gusteau::Node.new(node_name, node_config)
41
65
  end
42
66
  end
43
67
  end
data/lib/gusteau/node.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'gusteau/server'
2
- require 'gusteau/chef'
3
2
 
4
3
  module Gusteau
5
4
  class Node
@@ -7,11 +6,11 @@ module Gusteau
7
6
 
8
7
  attr_reader :name, :config, :server
9
8
 
10
- def initialize(name, config)
11
- @name = name
12
- @config = config
9
+ def initialize(node_name, node_config)
10
+ @name = node_name
11
+ @config = node_config
13
12
 
14
- @server = Server.new(@config['server']) if @config['server']
13
+ @server = Server.new(@config['server'])
15
14
  @dna_path = '/tmp/dna.json'
16
15
  end
17
16
 
@@ -1,5 +1,6 @@
1
- require 'gusteau/log'
1
+ require 'gusteau/chef'
2
2
  require 'gusteau/ssh'
3
+ require 'gusteau/log'
3
4
 
4
5
  module Gusteau
5
6
  class Server
@@ -8,12 +9,12 @@ module Gusteau
8
9
 
9
10
  attr_reader :host, :port, :user, :password, :chef
10
11
 
11
- def initialize(config, opts={})
12
+ def initialize(config)
12
13
  @host = config['host']
13
14
  @port = config['port'] || 22
14
15
  @user = config['user'] || 'root'
15
16
  @password = config['password']
16
- @chef = Gusteau::Chef.new(self, config['platform'])
17
+ @chef = Gusteau::Chef.new(self, config['platform'])
17
18
  end
18
19
 
19
20
  def upload(files_and_dirs, dest_dir, opts={})
@@ -9,7 +9,7 @@ module Gusteau
9
9
  extend Gusteau::Log
10
10
 
11
11
  def detect(config)
12
- options = Hashie::Mash.new
12
+ options = Hashie::Mash.new
13
13
  options.defaults = Hashie::Mash.new
14
14
 
15
15
  yield options if block_given?
@@ -17,7 +17,9 @@ module Gusteau
17
17
  end
18
18
 
19
19
  def define_nodes(config, options, prefix = nil)
20
- Gusteau::Config.nodes(options[:config_path] || ".gusteau.yml").each_pair do |name, node|
20
+ Gusteau::Config.read(options[:config_path] || ".gusteau.yml")
21
+
22
+ Gusteau::Config.nodes.each_pair do |name, node|
21
23
  if node.config['server']['vagrant']
22
24
  define_vm config, node, options
23
25
  end
@@ -75,10 +77,10 @@ module Gusteau
75
77
  def define_provisioner(instance, node)
76
78
  instance.vm.provision 'chef_solo' do |chef|
77
79
  chef.data_bags_path = 'data_bags'
78
- chef.cookbooks_path = ['cookbooks', 'site-cookbooks']
79
- chef.roles_path = 'roles'
80
- chef.json = node.config['attributes'] || {}
81
- chef.run_list = node.config['run_list'] || []
80
+ chef.cookbooks_path = Gusteau::Config.settings['cookbooks_path']
81
+ chef.roles_path = Gusteau::Config.settings['roles_path']
82
+ chef.json = node.config['attributes'] || {}
83
+ chef.run_list = node.config['run_list'] || []
82
84
  end
83
85
  end
84
86
  end
@@ -1,3 +1,3 @@
1
1
  module Gusteau
2
- VERSION = "1.0.3.dev"
2
+ VERSION = "1.0.4.dev"
3
3
  end
@@ -0,0 +1,5 @@
1
+ cookbooks_path:
2
+ - private-cookbooks
3
+ - /home/user/.cookbooks
4
+
5
+ roles_path: basic-roles
@@ -1,6 +1,8 @@
1
1
  require './spec/spec_helper.rb'
2
2
 
3
3
  describe Gusteau::Chef do
4
+ before { Gusteau::Config.read('./spec/config/emile.yml') }
5
+
4
6
  let(:platform) { 'centos' }
5
7
  let(:server) { Gusteau::Server.new('host' => 'example.com', 'platform' => platform) }
6
8
  let(:chef) { Gusteau::Chef.new(server, platform) }
@@ -2,7 +2,7 @@ require './spec/spec_helper'
2
2
 
3
3
  describe Gusteau::Config do
4
4
  context "config not found" do
5
- subject { Gusteau::Config.nodes("/tmp/nonexistent/nonsence111") }
5
+ subject { Gusteau::Config.read("/tmp/nonexistent/nonsence111") }
6
6
 
7
7
  it "should exit with an error" do
8
8
  proc { subject }.must_raise SystemExit
@@ -10,27 +10,49 @@ describe Gusteau::Config do
10
10
  end
11
11
 
12
12
  context "config is found" do
13
- let(:nodes) { Gusteau::Config.nodes("./spec/config/remi.yml") }
13
+ before { Gusteau::Config.read("./spec/config/remi.yml") }
14
14
 
15
- it "should name nodes as per environment-node" do
16
- nodes.keys.sort.must_equal ["production-db", "production-www", "staging-vm"]
17
- end
15
+ describe "#nodes" do
16
+ let(:nodes) { Gusteau::Config.nodes }
18
17
 
19
- it "should override run_list if defined for a node" do
20
- nodes['production-db'].config['run_list'].must_equal(["recipe[git]", "recipe[postgresql::server]"])
21
- nodes['production-www'].config['run_list'].must_equal(["recipe[varnish]", "recipe[nginx]"])
22
- end
18
+ it "should name nodes as per environment-node" do
19
+ nodes.keys.sort.must_equal ["production-db", "production-www", "staging-vm"]
20
+ end
21
+
22
+ it "should override run_list if defined for a node" do
23
+ nodes['production-db'].config['run_list'].must_equal(["recipe[git]", "recipe[postgresql::server]"])
24
+ nodes['production-www'].config['run_list'].must_equal(["recipe[varnish]", "recipe[nginx]"])
25
+ end
26
+
27
+ it "should deeply merge the attributes" do
28
+ nodes['production-db'].config['attributes'].must_equal({
29
+ 'users' => ['alex', 'simon'],
30
+ 'mysql' => {'server_port' => 3307, 'server_root_password' => 'prodsecret' }
31
+ })
32
+ end
23
33
 
24
- it "should deeply merge the attributes" do
25
- nodes['production-db'].config['attributes'].must_equal({
26
- 'users' => ['alex', 'simon'],
27
- 'mysql' => {'server_port' => 3307, 'server_root_password' => 'prodsecret' }
28
- })
34
+ it "should override the global before hook with an environment one" do
35
+ nodes['production-www'].config['before'].must_equal(['bundle exec berks install'])
36
+ nodes['staging-vm'].config['before'].must_equal(['echo "Hello World!"'])
37
+ end
29
38
  end
30
39
 
31
- it "should override the global before hook with an environment one" do
32
- nodes['production-www'].config['before'].must_equal(['bundle exec berks install'])
33
- nodes['staging-vm'].config['before'].must_equal(['echo "Hello World!"'])
40
+ describe "#settings" do
41
+ let(:settings) { Gusteau::Config.settings }
42
+
43
+ it "should have defaults for cookbooks_path, roles_path" do
44
+ settings['cookbooks_path'].must_equal ['cookbooks', 'site-cookbooks']
45
+ settings['roles_path'].must_equal 'roles'
46
+ end
47
+
48
+ context "settings defined in the config yml" do
49
+ before { Gusteau::Config.read("./spec/config/emile.yml") }
50
+
51
+ it "should have defaults for cookbooks_path, roles_path" do
52
+ settings['cookbooks_path'].must_equal ['private-cookbooks', '/home/user/.cookbooks']
53
+ settings['roles_path'].must_equal 'basic-roles'
54
+ end
55
+ end
34
56
  end
35
57
  end
36
58
  end
@@ -1,8 +1,9 @@
1
1
  require './spec/spec_helper.rb'
2
2
 
3
3
  describe Gusteau::SSHConfig do
4
- let(:nodes) { Gusteau::Config.nodes("./spec/config/gusteau.yml") }
5
- subject { Gusteau::SSHConfig.new(nodes) }
4
+ before { Gusteau::Config.read("./spec/config/gusteau.yml") }
5
+
6
+ subject { Gusteau::SSHConfig.new(Gusteau::Config.nodes) }
6
7
 
7
8
  let(:config) do
8
9
  <<-eos
@@ -49,73 +49,76 @@ describe Gusteau::Vagrant do
49
49
  end
50
50
  end
51
51
 
52
- describe "#vm_config" do
53
- let(:node) { Gusteau::Config.nodes("./spec/config/gusteau.yml")['development-playground'] }
54
- subject { Gusteau::Vagrant.vm_config(node, options) }
55
-
56
- let(:defaults) do
57
- {
58
- :box_url => 'https://opscode.s3.amazonaws.com/centos-6.4.box',
59
- :cpus => 64,
60
- :memory => 4096,
61
- }
62
- end
63
- let(:prefix) { 'hyper' }
64
- let(:options) { { :defaults => defaults, :prefix => prefix } }
65
-
66
- let(:expected_label) { 'hyper-development-playground' }
67
- let(:expected_config) do
68
- {
69
- :name => 'development-playground',
70
- :label => expected_label,
71
- :box_url => 'https://opscode.s3.amazonaws.com/centos-6.4.box',
72
- :ip => '192.168.100.21',
73
- :cpus => 2,
74
- :memory => 4096
75
- }
76
- end
52
+ describe "internal methods" do
53
+ before { Gusteau::Config.read("./spec/config/gusteau.yml") }
54
+ let(:node) { Gusteau::Config.nodes['development-playground'] }
55
+
56
+ describe "#vm_config" do
57
+ subject { Gusteau::Vagrant.vm_config(node, options) }
58
+
59
+ let(:defaults) do
60
+ {
61
+ :box_url => 'https://opscode.s3.amazonaws.com/centos-6.4.box',
62
+ :cpus => 64,
63
+ :memory => 4096,
64
+ }
65
+ end
66
+ let(:prefix) { 'hyper' }
67
+ let(:options) { { :defaults => defaults, :prefix => prefix } }
68
+
69
+ let(:expected_label) { 'hyper-development-playground' }
70
+ let(:expected_config) do
71
+ {
72
+ :name => 'development-playground',
73
+ :label => expected_label,
74
+ :box_url => 'https://opscode.s3.amazonaws.com/centos-6.4.box',
75
+ :ip => '192.168.100.21',
76
+ :cpus => 2,
77
+ :memory => 4096
78
+ }
79
+ end
77
80
 
78
- it "should merge in defaults" do
79
- subject.must_equal(expected_config)
80
- end
81
+ it "should merge in defaults" do
82
+ subject.must_equal(expected_config)
83
+ end
81
84
 
82
- context "prefix not specified" do
83
- let(:prefix) { nil }
84
- let(:expected_label) { 'development-playground' }
85
+ context "prefix not specified" do
86
+ let(:prefix) { nil }
87
+ let(:expected_label) { 'development-playground' }
85
88
 
86
- it "should omit the prefix" do
87
- subject.must_equal(expected_config)
89
+ it "should omit the prefix" do
90
+ subject.must_equal(expected_config)
91
+ end
88
92
  end
89
- end
90
93
 
91
- context "box_url not specified" do
92
- let(:defaults) { {} }
94
+ context "box_url not specified" do
95
+ let(:defaults) { {} }
93
96
 
94
- it "should raise an exception" do
95
- proc { subject }.must_raise RuntimeError
97
+ it "should raise an exception" do
98
+ proc { subject }.must_raise RuntimeError
99
+ end
96
100
  end
97
101
  end
98
- end
99
102
 
100
- describe "#define_provisioner" do
101
- let(:node) { Gusteau::Config.nodes("./spec/config/gusteau.yml")['development-playground'] }
102
- let(:chef) { stub_everything('chef') }
103
+ describe "#define_provisioner" do
104
+ let(:chef) { stub_everything('chef') }
103
105
 
104
- before do
105
- def subvm.provision(provider); yield chef; end
106
- subvm.expects(:chef).returns(chef)
106
+ before do
107
+ def subvm.provision(provider); yield chef; end
108
+ subvm.expects(:chef).returns(chef)
107
109
 
108
- instance.expects(:vm).at_least_once.returns(subvm)
109
- end
110
+ instance.expects(:vm).at_least_once.returns(subvm)
111
+ end
110
112
 
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
113
+ it "should set the correct Chef JSON" do
114
+ chef.expects('json='.to_sym).with({"mysql"=>{"server_root_password"=>"guesswhat"}})
115
+ Gusteau::Vagrant.define_provisioner(instance, node)
116
+ end
115
117
 
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)
118
+ it "should set the correct Chef run_list" do
119
+ chef.expects('run_list='.to_sym).with(["recipe[zsh]", "recipe[mysql::server]"])
120
+ Gusteau::Vagrant.define_provisioner(instance, node)
121
+ end
119
122
  end
120
123
  end
121
124
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gusteau
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3.dev
4
+ version: 1.0.4.dev
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -240,6 +240,7 @@ files:
240
240
  - lib/gusteau/ssh_config.rb
241
241
  - lib/gusteau/vagrant.rb
242
242
  - lib/gusteau/version.rb
243
+ - spec/config/emile.yml
243
244
  - spec/config/gusteau.yml
244
245
  - spec/config/remi.yml
245
246
  - spec/lib/gusteau/bureau_spec.rb
@@ -285,7 +286,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
285
286
  version: '0'
286
287
  segments:
287
288
  - 0
288
- hash: -1682856364526822878
289
+ hash: 201267403645685756
289
290
  required_rubygems_version: !ruby/object:Gem::Requirement
290
291
  none: false
291
292
  requirements:
@@ -299,6 +300,7 @@ signing_key:
299
300
  specification_version: 3
300
301
  summary: Making servers provisioning enjoyable since 2013.
301
302
  test_files:
303
+ - spec/config/emile.yml
302
304
  - spec/config/gusteau.yml
303
305
  - spec/config/remi.yml
304
306
  - spec/lib/gusteau/bureau_spec.rb