remy 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/remy/remy.rb ADDED
@@ -0,0 +1,140 @@
1
+ #--
2
+ # Copyright (c) 2011 Gregory S. Woodward
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ module Remy
25
+ class Configuration
26
+ attr_accessor :yml_files, :cookbook_path, :spec_path, :remote_chef_dir, :node_attributes, :roles_path
27
+
28
+ def initialize
29
+ @yml_files = []
30
+ @node_attributes = {}
31
+ end
32
+ end
33
+
34
+ class << self
35
+ include ::Remy::Shell
36
+ include FileUtils
37
+
38
+ def configure
39
+ @config_instance = Configuration.new
40
+ yield @config_instance
41
+ @configuration = Hashie::Mash.new({:yml_files => [@config_instance.yml_files].compact.flatten,
42
+ :remote_chef_dir => (@config_instance.remote_chef_dir || '/var/chef'),
43
+ :roles_path => [@config_instance.roles_path].compact.flatten,
44
+ :spec_path => [@config_instance.spec_path].compact.flatten,
45
+ :cookbook_path => [@config_instance.cookbook_path].compact.flatten}.merge!(@config_instance.node_attributes))
46
+
47
+ @config_instance.yml_files.each do |filename|
48
+ begin
49
+ configuration.deep_merge!(YAML.load(ERB.new(File.read(filename)).result) || {})
50
+ rescue SystemCallError, IOError
51
+ warn "WARN: #{filename} could not be found!"
52
+ end
53
+ end
54
+ end
55
+
56
+ def configuration
57
+ @configuration ? @configuration : Hashie::Mash.new
58
+ end
59
+
60
+ def to_json
61
+ configuration.to_json
62
+ end
63
+
64
+ def servers
65
+ configuration.servers
66
+ end
67
+
68
+ def find_servers(options = {})
69
+ return nil unless configuration.servers
70
+ Hashie::Mash.new(configuration.servers.inject({}) do |hash, (server_name, server_config)|
71
+ found = options.all? { |(key, value)| server_config[key] == value }
72
+ hash[server_name] = server_config if found
73
+ hash
74
+ end)
75
+ end
76
+
77
+ def find_server(options = {})
78
+ return nil unless configuration.servers
79
+ server_name, server_config = configuration.servers.detect do |(server_name, server_config)|
80
+ options.all? { |(key, value)| server_config[key] == value }
81
+ end
82
+ {server_name => server_config.nil? ? nil : server_config.dup}
83
+ end
84
+
85
+ def find_server_config(options = {})
86
+ find_server(options).try(:values).try(:first)
87
+ end
88
+
89
+ def find_server_config_by_name(name)
90
+ return nil unless configuration.servers
91
+ configuration.servers.find {|(server_name, _)| server_name == name}.try(:last)
92
+ end
93
+
94
+ def cloud_configuration
95
+ configuration && configuration.cloud_configuration
96
+ end
97
+
98
+ def bootstrap
99
+ configuration && configuration.bootstrap
100
+ end
101
+
102
+ def determine_ip_addresses_for_remy_run(rake_args)
103
+ ip_addresses = []
104
+ if options_hash = convert_properties_to_hash(rake_args)
105
+ servers = find_servers(options_hash)
106
+ if !servers.empty?
107
+ ip_addresses = servers.collect {|server_name, chef_option| chef_option.ip_address }
108
+ else
109
+ ip_addresses = [options_hash[:ip_address]]
110
+ end
111
+ else
112
+ names_or_ip_addresses = rake_args.split(' ').collect {|name| name.strip }
113
+ names_or_ip_addresses.each do |name_or_ip_address|
114
+ # From: http://www.regular-expressions.info/examples.html
115
+ ip_address_regex = '\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b'
116
+ if name_or_ip_address.match(ip_address_regex)
117
+ ip_addresses << name_or_ip_address
118
+ elsif server_config = find_server_config_by_name(name_or_ip_address)
119
+ ip_addresses << server_config.ip_address
120
+ end
121
+ end
122
+ ip_addresses << configuration.ip_address
123
+ end
124
+ ip_addresses.compact
125
+ end
126
+
127
+ # Converts "foo:bar baz:blech" to {:foo => 'bar', :baz => 'blech'}
128
+ def convert_properties_to_hash(properties)
129
+ if properties =~ /:/
130
+ properties.split(' ').inject({}) do |result, pair|
131
+ key, value = pair.split(':')
132
+ result[key] = value
133
+ result
134
+ end.symbolize_keys
135
+ else
136
+ nil
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,71 @@
1
+ class Remy::Server
2
+ attr_reader :server_name, :cloud_api_key, :cloud_username, :cloud_provider, :flavor_id, :image_id, :server
3
+
4
+ def initialize(options = {})
5
+ options = {
6
+ :flavor_id => 4, # 2GB
7
+ :image_id => 49, # Ubuntu 10.04 LTS (lucid)
8
+ :quiet => false
9
+ }.merge(Remy.cloud_configuration || {}).merge(options || {}).symbolize_keys
10
+
11
+ @server_name = options[:server_name]
12
+ @cloud_api_key = options[:cloud_api_key]
13
+ @cloud_username = options[:cloud_username]
14
+ @cloud_provider = options[:cloud_provider]
15
+ @flavor_id = options[:flavor_id]
16
+ @image_id = options[:image_id]
17
+ @quiet = options[:quiet]
18
+ @raise_exception = options[:raise_exception]
19
+ @server = nil
20
+ end
21
+
22
+ def create
23
+ compute = Fog::Compute.new(
24
+ :provider => cloud_provider,
25
+ :rackspace_api_key => cloud_api_key,
26
+ :rackspace_username => cloud_username
27
+ )
28
+
29
+ @server = compute.servers.create(:flavor_id => flavor_id.to_i, :image_id => image_id.to_i, :name => server_name)
30
+ server.wait_for do
31
+ print '.'
32
+ STDOUT.flush
33
+ ready?
34
+ end
35
+ print server_info
36
+ {:ip_address => server.public_ip_address, :password => server.password}
37
+ rescue Exception => e
38
+ puts 'Failed!'
39
+ p e
40
+ raise e if raise_exception?
41
+ {}
42
+ end
43
+
44
+ private
45
+ def server_info
46
+ <<-SERVER_INFO
47
+
48
+
49
+ Server name: #{server.name}
50
+ root password: #{server.password}
51
+ RAM: #{server.flavor.ram} MB
52
+ Image: #{server.image.name}
53
+ IP address: #{server.public_ip_address}
54
+ Private IP address: #{server.addresses['private'][0]}
55
+
56
+ SERVER_INFO
57
+
58
+ end
59
+
60
+ def print *args
61
+ Kernel.print(*args) unless quiet?
62
+ end
63
+
64
+ def quiet?
65
+ @quiet
66
+ end
67
+
68
+ def raise_exception?
69
+ @raise_exception
70
+ end
71
+ end
data/lib/remy/shell.rb ADDED
@@ -0,0 +1,26 @@
1
+ module Remy
2
+ module Shell
3
+ def execute(command)
4
+ if quiet?
5
+ `#{command} 2>&1`
6
+ $?.success?
7
+ else
8
+ puts "Running command: #{command}"
9
+ system command
10
+ end
11
+ end
12
+
13
+ def remote_execute(cmd)
14
+ raise ArgumentError.new unless ip_address
15
+ execute "ssh -T #{user}@#{ip_address} '#{cmd.strip}'"
16
+ end
17
+
18
+ def user
19
+ 'root'
20
+ end
21
+
22
+ def quiet?
23
+ false
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,3 @@
1
+ module Remy
2
+ VERSION = "0.0.1"
3
+ end
data/lib/remy.rb ADDED
@@ -0,0 +1,56 @@
1
+ #--
2
+ # Copyright (c) 2011 Gregory S. Woodward
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ begin
25
+ require 'active_support/core_ext/object/to_json'
26
+ rescue LoadError
27
+ require 'active_support/json/encoders/object'
28
+ end
29
+
30
+ begin
31
+ require 'active_support/core_ext/object/try'
32
+ rescue LoadError
33
+ require 'active_support/core_ext/try'
34
+ end
35
+
36
+ require 'active_support/core_ext/hash'
37
+ require 'fog'
38
+ require 'erb'
39
+ require 'json'
40
+ require 'hashie'
41
+ require 'tmpdir'
42
+ require 'remy/shell'
43
+ require 'yaml'
44
+ dir = File.dirname(__FILE__)
45
+ Dir[File.join(File.dirname(__FILE__), 'remy', '**', '*.rb')].each {|f| require f.gsub(dir, '')[1, f.length] }
46
+
47
+ module Remy
48
+ begin
49
+ class Railtie < ::Rails::Railtie
50
+ rake_tasks do
51
+ load 'tasks/remy.rake'
52
+ end
53
+ end
54
+ rescue LoadError, NameError
55
+ end
56
+ end
@@ -0,0 +1,51 @@
1
+ require 'remy'
2
+
3
+ namespace :remy do
4
+ task :environment do
5
+ begin
6
+ Rake::Task[:environment].invoke
7
+ rescue RuntimeError
8
+ end
9
+ end
10
+
11
+ desc 'ssh to a named box'
12
+ task :ssh, :rake_args do |task, options|
13
+ Rake::Task[:'remy:environment'].invoke
14
+ user = Remy.configuration.user || 'root'
15
+ if ip_address = Remy.determine_ip_addresses_for_remy_run(options[:rake_args]).try(:first)
16
+ exec "ssh #{user}@#{ip_address}"
17
+ end
18
+ end
19
+
20
+ namespace :chef do
21
+ desc 'run chef solo'
22
+ task :run, :rake_args do |task, options|
23
+ Rake::Task[:'remy:environment'].invoke
24
+ Remy::Chef.rake_run(options[:rake_args])
25
+ end
26
+ end
27
+
28
+ namespace :server do
29
+ desc 'create a server'
30
+ task :create, :server_name, :flavor_id, :cloud_api_key, :cloud_username, :cloud_provider, :image_id do |task, options|
31
+ Rake::Task[:'remy:environment'].invoke
32
+ Remy::Server.new(options).create
33
+ end
34
+
35
+ desc 'bootstrap chef'
36
+ task :bootstrap, :ip_address, :password do |task, options|
37
+ Rake::Task[:'remy:environment'].invoke
38
+ Remy::Bootstrap.new(options).run
39
+ end
40
+
41
+ desc 'create a server and bootstrap chef'
42
+ task :create_and_bootstrap, :server_name, :flavor_id, :cloud_api_key, :cloud_username, :cloud_provider, :image_id do |task, options|
43
+ Rake::Task[:'remy:environment'].invoke
44
+ begin
45
+ result = Remy::Server.new({:raise_exception => true}.merge(options)).create
46
+ Rake::Task[:'remy:server:bootstrap'].invoke(result[:ip_address], result[:password])
47
+ rescue Exception => e
48
+ end
49
+ end
50
+ end
51
+ end
data/remy.gemspec ADDED
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'remy/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'remy'
7
+ s.version = Remy::VERSION
8
+ s.authors = ['Greg Woodward & Ryan Dy']
9
+ s.email = ['pair+gwoodward+rdy@pivotallabs.com']
10
+ s.homepage = 'http://sharespost.com'
11
+ s.summary = %q{Remy gem}
12
+ s.description = %q{Easy chef deployment}
13
+
14
+ s.rubyforge_project = 'remy'
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ['lib']
20
+
21
+ # specify any dependencies here; for example:
22
+ s.add_development_dependency 'bourne'
23
+ s.add_development_dependency 'mocha'
24
+ s.add_development_dependency 'i18n'
25
+ s.add_development_dependency 'json'
26
+ s.add_development_dependency 'rspec', '~> 2.7.0'
27
+ s.add_runtime_dependency 'activesupport', '>= 2'
28
+ s.add_runtime_dependency 'chef'
29
+ s.add_runtime_dependency 'fog'
30
+ s.add_runtime_dependency 'hashie'
31
+ end
@@ -0,0 +1,7 @@
1
+ baz:
2
+ baz
3
+ another_node_attribute:
4
+ hot
5
+ colors:
6
+ blue: 'blue'
7
+ green: 'green'
@@ -0,0 +1,44 @@
1
+ app_server: &APP
2
+ recipes:
3
+ - recipe[hello_world]
4
+ database_server: &DB
5
+ adapter: mysql2
6
+ encoding: utf8
7
+
8
+ rails_env: bogus_and_should_be_overridden_by_value_in_servers_section
9
+
10
+ servers:
11
+ web.sharespost.com:
12
+ <<: *APP
13
+ ip_address: <%= IP_ADDRESS %>
14
+ rails_env: demo
15
+ color: blue
16
+
17
+ db.sharespost.com:
18
+ <<: *DB
19
+ ip_address: 51.51.51.51
20
+ rails_env: production
21
+ color: yellow
22
+
23
+ demo.sharespost.com:
24
+ <<: *DB
25
+ <<: *APP
26
+ ip_address: 52.52.52.52
27
+ rails_env: demo
28
+ color: green
29
+
30
+ cloud_configuration:
31
+ cloud_provider: Rackspace
32
+ cloud_username: sharespost
33
+ cloud_api_key: abcdefg12345
34
+ flavor_id: 4
35
+ image_id: 49
36
+ server_name: new-server.somedomain.com
37
+
38
+ bootstrap:
39
+ ruby_version: 1.9.2
40
+ gems:
41
+ bundler: 1.0.21
42
+ chef: 0.10.4
43
+ rspec: 2.7.0
44
+
@@ -0,0 +1,5 @@
1
+ blah:
2
+ bar
3
+ colors:
4
+ red: 'red'
5
+ green: 'green'
@@ -0,0 +1,8 @@
1
+ ip_address: <%= IP_ADDRESS %>
2
+ color: blue
3
+ recipes:
4
+ - recipe[hello_world]
5
+ other_data:
6
+ - red
7
+ - yellow
8
+ - blue
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe Remy::Bootstrap do
4
+ def ruby_version(bootstrap)
5
+ bootstrap.instance_variable_get(:@ruby_version)
6
+ end
7
+
8
+ def gem(bootstrap)
9
+ bootstrap.instance_variable_get(:@gems)
10
+ end
11
+
12
+ def ip_address(bootstrap)
13
+ bootstrap.instance_variable_get(:@ip_address)
14
+ end
15
+
16
+ describe "ruby_version" do
17
+ it 'should default to 1.8.7 if there is no Ruby version specified in the yml files' do
18
+ Remy.configure { |config| config.yml_files = File.join(File.dirname(__FILE__), '../fixtures/hello_world_chef.yml') }
19
+ bootstrap = Remy::Bootstrap.new
20
+ ruby_version(bootstrap).should == '1.8.7'
21
+ end
22
+
23
+ it 'should get the Ruby version if specified in the yml files' do
24
+ Remy.configure { |config| config.yml_files = File.join(File.dirname(__FILE__), '../fixtures/chef.yml') }
25
+ bootstrap = Remy::Bootstrap.new
26
+ ruby_version(bootstrap).should == '1.9.2'
27
+ end
28
+
29
+ it 'should use the version passed in as an option, even if it exists in the yml files' do
30
+ Remy.configure { |config| config.yml_files = File.join(File.dirname(__FILE__), '../fixtures/chef.yml') }
31
+ bootstrap = Remy::Bootstrap.new(:ruby_version => '1.9.1')
32
+ ruby_version(bootstrap).should == '1.9.1'
33
+ end
34
+ end
35
+
36
+ describe "gems" do
37
+ it 'should default to nil if not specified in the yml files' do
38
+ Remy.configure { |config| config.yml_files = File.join(File.dirname(__FILE__), '../fixtures/hello_world_chef.yml') }
39
+ bootstrap = Remy::Bootstrap.new
40
+ gem(bootstrap)[:chef].should be_nil
41
+ gem(bootstrap)[:bundler].should be_nil
42
+ gem(bootstrap)[:rspec].should be_nil
43
+ end
44
+
45
+ it 'should get gem version if it has been specified in the yml files' do
46
+ Remy.configure { |config| config.yml_files = File.join(File.dirname(__FILE__), '../fixtures/chef.yml') }
47
+ bootstrap = Remy::Bootstrap.new
48
+ gem(bootstrap)[:chef].should == '0.10.4'
49
+ gem(bootstrap)[:bundler].should == '1.0.21'
50
+ gem(bootstrap)[:rspec].should == '2.7.0'
51
+ end
52
+ end
53
+
54
+ describe "ip_address" do
55
+ it 'should use the value from the options' do
56
+ Remy.configure { |config| config.yml_files = File.join(File.dirname(__FILE__), '../fixtures/hello_world_chef.yml') }
57
+ bootstrap = Remy::Bootstrap.new(:ip_address => '1.2.3.4', :password => 'abcdef')
58
+ ip_address(bootstrap).should == '1.2.3.4'
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+
3
+ describe Remy::Chef do
4
+ def node_configuration(chef)
5
+ chef.instance_variable_get(:@node_configuration)
6
+ end
7
+
8
+ describe "#initialize and the node configuration" do
9
+ it 'should use the top-level IP address in the yml files, if one is present, and an ip address is not passed in as an argument' do
10
+ Remy.configure { |config| config.yml_files = File.join(File.dirname(__FILE__), '../fixtures/hello_world_chef.yml') }
11
+ chef = Remy::Chef.new
12
+ node_configuration(chef).ip_address.should == IP_ADDRESS
13
+ node_configuration(chef).color.should == 'blue'
14
+ node_configuration(chef).recipes.should == ['recipe[hello_world]']
15
+ end
16
+
17
+ it 'should allow the top-level values in the yml files (including the ip address) to be overridden' do
18
+ Remy.configure { |config| config.yml_files = File.join(File.dirname(__FILE__), '../fixtures/hello_world_chef.yml') }
19
+ chef = Remy::Chef.new(:ip_address => '1.2.3.4', :color => 'green')
20
+ node_configuration(chef).ip_address.should == '1.2.3.4'
21
+ node_configuration(chef).color.should == 'green'
22
+ node_configuration(chef).recipes.should == ['recipe[hello_world]']
23
+ end
24
+
25
+ it 'should return properties from the :servers section of the yml file if the ip address is found in there' do
26
+ Remy.configure { |config| config.yml_files = File.join(File.dirname(__FILE__), '../fixtures/chef.yml') }
27
+ chef = Remy::Chef.new(:ip_address => '51.51.51.51')
28
+ node_configuration(chef).ip_address.should == '51.51.51.51'
29
+ node_configuration(chef).rails_env.should == 'production'
30
+ node_configuration(chef).color.should == 'yellow'
31
+ node_configuration(chef).adapter.should == 'mysql2'
32
+ node_configuration(chef).encoding.should == 'utf8'
33
+ end
34
+
35
+ it 'should allow properties from the servers section of the yml file to be overridden plus additional options added' do
36
+ Remy.configure { |config| config.yml_files = File.join(File.dirname(__FILE__), '../fixtures/chef.yml') }
37
+ chef = Remy::Chef.new(:ip_address => '51.51.51.51', :color => 'purple', :temperature => 'warm')
38
+ node_configuration(chef).color.should == 'purple' # Overrides 'yellow' from the yml files
39
+ node_configuration(chef).temperature.should == 'warm' # A new node attribute which is not present in the yml files
40
+ end
41
+
42
+ it 'should allow the chef args to be specified (and not merge this chef_args value into the node configuration)' do
43
+ Remy.configure { |config| config.yml_files = File.join(File.dirname(__FILE__), '../fixtures/chef.yml') }
44
+ chef = Remy::Chef.new(:chef_args => '-l debug')
45
+ node_configuration(chef).chef_args.should be_nil
46
+ chef.instance_variable_get(:@chef_args).should == '-l debug'
47
+ end
48
+
49
+ it 'should allow the quiet option to be specified (and not merge this option into the node configuration)' do
50
+ Remy.configure { |config| config.yml_files = File.join(File.dirname(__FILE__), '../fixtures/chef.yml') }
51
+ chef = Remy::Chef.new(:quiet => true)
52
+ node_configuration(chef).quiet.should be_nil
53
+ chef.instance_variable_get(:@quiet).should be_true
54
+ end
55
+
56
+ it 'should not modify the global Remy configuration, but rather only the node configuration for this particular Chef node' do
57
+ Remy.configure { |config| config.yml_files = File.join(File.dirname(__FILE__), '../fixtures/bar.yml') }
58
+ Remy.configuration.another_node_attribute.should == 'hot'
59
+ chef = Remy::Chef.new(:another_node_attribute => 'cold')
60
+ node_configuration(chef).another_node_attribute.should == 'cold'
61
+ Remy.configuration.another_node_attribute.should == 'hot' # Unchanged from its original value # do some checks
62
+ end
63
+ end
64
+
65
+ describe '#run' do
66
+ before do
67
+ Remy.configure { |config| config.yml_files = File.join(File.dirname(__FILE__), '../fixtures/chef.yml') }
68
+ end
69
+
70
+ it 'should work with a hash as its argument' do
71
+ chef = Remy::Chef.new(:ip_address => IP_ADDRESS)
72
+ node_configuration(chef).ip_address.should == IP_ADDRESS
73
+ node_configuration(chef).recipes.should == ['recipe[hello_world]']
74
+ end
75
+
76
+ it 'should work with JSON as its argument' do
77
+ chef = Remy::Chef.new("{\"ip_address\":\"#{IP_ADDRESS}\"}")
78
+ node_configuration(chef).ip_address.should == IP_ADDRESS
79
+ node_configuration(chef).recipes.should == ['recipe[hello_world]']
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe Remy::Chef do
4
+ before do
5
+ Remy.configure do |config|
6
+ config.yml_files = ['../../fixtures/foo.yml', '../../fixtures/bar.yml', '../../fixtures/chef.yml'].map { |f| File.join(File.dirname(__FILE__), f) }
7
+ config.cookbook_path = ["../../../chef/cookbooks"].map { |f| File.join(File.dirname(__FILE__), f) }
8
+ config.spec_path = ["../../../chef/spec"].map { |f| File.join(File.dirname(__FILE__), f) }
9
+ end
10
+ end
11
+
12
+ describe '#run' do
13
+ def clean_up_remote_chef_test_files(chef)
14
+ chef.remote_execute "rm -rf /tmp/hello_world.txt #{Remy.configuration.remote_chef_dir}" if Remy.configuration.remote_chef_dir && Remy.configuration.remote_chef_dir.size > 2
15
+ end
16
+
17
+ def verify_contents_of_hello_world(chef)
18
+ chef.remote_execute(%Q{cat /tmp/hello_world.txt | grep "I am feeling blue"}).should be_true
19
+ end
20
+
21
+ def run_chef(options = {})
22
+ chef = Remy::Chef.new(options)
23
+ clean_up_remote_chef_test_files(chef)
24
+ chef.run
25
+ yield chef
26
+ clean_up_remote_chef_test_files(chef)
27
+ end
28
+
29
+ it 'should work with a hash as its argument' do
30
+ run_chef(:ip_address => IP_ADDRESS) do |chef|
31
+ verify_contents_of_hello_world(chef)
32
+ end
33
+ end
34
+
35
+ it 'should work with JSON as its argument' do
36
+ run_chef("{\"ip_address\":\"#{IP_ADDRESS}\"}") do |chef|
37
+ verify_contents_of_hello_world(chef)
38
+ end
39
+ end
40
+ end
41
+ end