engineyard-recipes 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/Gemfile +4 -0
- data/README.md +11 -0
- data/Rakefile +1 -0
- data/bin/ey-recipes +17 -0
- data/engineyard-recipes.gemspec +33 -0
- data/features/init-new-cookbook.feature +18 -0
- data/features/step_definitions/api_steps.rb +10 -0
- data/features/step_definitions/common_steps.rb +211 -0
- data/features/step_definitions/fixture_project_steps.rb +14 -0
- data/features/step_definitions/jenkins_steps.rb +21 -0
- data/features/support/common.rb +51 -0
- data/features/support/env.rb +18 -0
- data/features/support/matchers.rb +10 -0
- data/fixtures/bin/README.md +4 -0
- data/fixtures/bin/scp +6 -0
- data/fixtures/cookbooks/main/recipes/default.rb +1 -0
- data/fixtures/cookbooks/redis/recipes/default.rb +0 -0
- data/fixtures/jenkins_boot_sequence/jenkins_booting.html +1 -0
- data/fixtures/jenkins_boot_sequence/jenkins_ready.html +1 -0
- data/fixtures/jenkins_boot_sequence/pre_jenkins_booting.html +1 -0
- data/fixtures/projects/rails/Gemfile +3 -0
- data/fixtures/projects/rails/Rakefile +4 -0
- data/lib/engineyard-recipes/cli.rb +86 -0
- data/lib/engineyard-recipes/generators/init_generator/templates/cookbooks/main/attributes/recipe.rb +3 -0
- data/lib/engineyard-recipes/generators/init_generator/templates/cookbooks/main/definitions/ey_cloud_report.rb +6 -0
- data/lib/engineyard-recipes/generators/init_generator/templates/cookbooks/main/libraries/ruby_block.rb +40 -0
- data/lib/engineyard-recipes/generators/init_generator/templates/cookbooks/main/libraries/run_for_app.rb +12 -0
- data/lib/engineyard-recipes/generators/init_generator/templates/cookbooks/main/recipes/default.rb +0 -0
- data/lib/engineyard-recipes/generators/init_generator.rb +38 -0
- data/lib/engineyard-recipes/thor-ext/actions/directory.rb +33 -0
- data/lib/engineyard-recipes/version.rb +5 -0
- data/lib/engineyard-recipes.rb +7 -0
- metadata +149 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/ey-recipes
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
|
4
|
+
require 'engineyard-recipes'
|
5
|
+
require 'engineyard-recipes/cli'
|
6
|
+
|
7
|
+
begin
|
8
|
+
Engineyard::Recipes::CLI.start
|
9
|
+
rescue EY::Error => e
|
10
|
+
EY.ui.print_exception(e)
|
11
|
+
exit(1)
|
12
|
+
rescue Interrupt => e
|
13
|
+
puts
|
14
|
+
EY.ui.print_exception(e)
|
15
|
+
EY.ui.say("Quitting...")
|
16
|
+
exit(1)
|
17
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "engineyard-recipes/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "engineyard-recipes"
|
7
|
+
s.version = Engineyard::Recipes::VERSION
|
8
|
+
s.authors = ["Dr Nic Williams"]
|
9
|
+
s.email = ["drnicwilliams@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Tools to generate, upload, test and apply chef recipes for Engine Yard Cloud.}
|
12
|
+
s.description = %q{Tools to generate, upload, test and apply chef recipes for Engine Yard Cloud.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "engineyard-recipes"
|
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
|
+
s.add_dependency("thor", ["~> 0.14.6"])
|
22
|
+
s.add_dependency("engineyard", ["~> 1.4.6"])
|
23
|
+
|
24
|
+
s.add_development_dependency("rake", ["~> 0.9.2"])
|
25
|
+
s.add_development_dependency("cucumber", ["~> 1.1.2"])
|
26
|
+
s.add_development_dependency("rspec", ["~> 2.7.0"])
|
27
|
+
# s.add_development_dependency("json")
|
28
|
+
# s.add_development_dependency("awesome_print")
|
29
|
+
# s.add_development_dependency("realweb", '~>0.1.6')
|
30
|
+
# s.add_development_dependency("open4")
|
31
|
+
# s.add_development_dependency("sinatra")
|
32
|
+
# s.add_development_dependency("fakeweb", "~>1.3.0")
|
33
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Feature: Generate a new custom cookbook for your EY Cloud environments
|
2
|
+
|
3
|
+
Scenario: Generate basic cookbook scaffold
|
4
|
+
Given I am in the "rails" project folder
|
5
|
+
When I run local executable "ey-recipes" with arguments "init"
|
6
|
+
And file "cookbooks/main/recipes/default.rb" is created
|
7
|
+
And file "cookbooks/main/libraries/ruby_block.rb" is created
|
8
|
+
And I should see exactly
|
9
|
+
"""
|
10
|
+
create cookbooks
|
11
|
+
create cookbooks/main/attributes/recipe.rb
|
12
|
+
create cookbooks/main/definitions/ey_cloud_report.rb
|
13
|
+
create cookbooks/main/libraries/ruby_block.rb
|
14
|
+
create cookbooks/main/libraries/run_for_app.rb
|
15
|
+
create cookbooks/main/recipes/default.rb
|
16
|
+
|
17
|
+
Lovely.
|
18
|
+
"""
|
@@ -0,0 +1,10 @@
|
|
1
|
+
Given /^I have setup my engineyard email\/password for API access$/ do
|
2
|
+
ENV['EYRC'] = File.join(@home_path, ".eyrc")
|
3
|
+
token = { ENV['CLOUD_URL'] => {
|
4
|
+
"api_token" => "f81a1706ddaeb148cfb6235ddecfc1cf"} }
|
5
|
+
File.open(ENV['EYRC'], "w"){|f| YAML.dump(token, f) }
|
6
|
+
end
|
7
|
+
|
8
|
+
When /^I have "two accounts, two apps, two environments, ambiguous"$/ do
|
9
|
+
api_scenario "two accounts, two apps, two environments, ambiguous"
|
10
|
+
end
|
@@ -0,0 +1,211 @@
|
|
1
|
+
Given /^this project is active project folder/ do
|
2
|
+
@active_project_folder = File.expand_path(File.dirname(__FILE__) + "/../..")
|
3
|
+
end
|
4
|
+
|
5
|
+
Given /^env variable \$([\w_]+) set to( project path|) "(.*)"/ do |env_var, path, value|
|
6
|
+
in_project_folder {
|
7
|
+
value = File.expand_path(value)
|
8
|
+
} unless path.empty?
|
9
|
+
ENV[env_var] = value
|
10
|
+
end
|
11
|
+
|
12
|
+
Given /"(.*)" folder is deleted/ do |folder|
|
13
|
+
in_project_folder { FileUtils.rm_rf folder }
|
14
|
+
end
|
15
|
+
|
16
|
+
When /^I invoke "(.*)" generator with arguments "(.*)"$/ do |generator, arguments|
|
17
|
+
@stdout = StringIO.new
|
18
|
+
in_project_folder do
|
19
|
+
if Object.const_defined?("APP_ROOT")
|
20
|
+
APP_ROOT.replace(FileUtils.pwd)
|
21
|
+
else
|
22
|
+
APP_ROOT = FileUtils.pwd
|
23
|
+
end
|
24
|
+
run_generator(generator, arguments.split(' '), SOURCES, :stdout => @stdout)
|
25
|
+
end
|
26
|
+
File.open(File.join(@tmp_root, "generator.out"), "w") do |f|
|
27
|
+
@stdout.rewind
|
28
|
+
f << @stdout.read
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
When /^I run executable "(.*)" with arguments "(.*)"/ do |executable, arguments|
|
33
|
+
@stdout = File.expand_path(File.join(@tmp_root, "executable.out"))
|
34
|
+
in_project_folder do
|
35
|
+
system "#{executable.inspect} #{arguments} > #{@stdout.inspect} 2> #{@stdout.inspect}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
When /^I run project executable "(.*)" with arguments "(.*)"/ do |executable, arguments|
|
40
|
+
@stdout = File.expand_path(File.join(@tmp_root, "executable.out"))
|
41
|
+
in_project_folder do
|
42
|
+
system "ruby -rubygems #{executable.inspect} #{arguments} > #{@stdout.inspect} 2> #{@stdout.inspect}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
When /^I run local executable "(.*)" with arguments "(.*)"/ do |executable, arguments|
|
47
|
+
if executable == "ey-recipes"
|
48
|
+
require 'engineyard-recipes'
|
49
|
+
require 'engineyard-recipes/cli'
|
50
|
+
in_project_folder do
|
51
|
+
stdout, stderr = capture_stdios do
|
52
|
+
Engineyard::Recipes::CLI.start(arguments.split(/ /))
|
53
|
+
end
|
54
|
+
@stdout = File.expand_path(File.join(@tmp_root, "executable.out"))
|
55
|
+
File.open(@stdout, "w") {|f| f << stdout; f << stderr}
|
56
|
+
end
|
57
|
+
else
|
58
|
+
@stdout = File.expand_path(File.join(@tmp_root, "executable.out"))
|
59
|
+
executable = File.expand_path(File.join(File.dirname(__FILE__), "/../../bin", executable))
|
60
|
+
in_project_folder do
|
61
|
+
system "ruby -rubygems #{executable.inspect} #{arguments} > #{@stdout.inspect} 2> #{@stdout.inspect}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
When /^I invoke task "rake (.*)"/ do |task|
|
67
|
+
@stdout = File.expand_path(File.join(@tmp_root, "tests.out"))
|
68
|
+
in_project_folder do
|
69
|
+
system "bundle exec rake #{task} --trace > #{@stdout.inspect} 2> #{@stdout.inspect}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
Then /^folder "(.*)" (is|is not) created/ do |folder, is|
|
74
|
+
in_project_folder do
|
75
|
+
File.exists?(folder).should(is == 'is' ? be_true : be_false)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
Then /^file "(.*)" (is|is not) created/ do |file, is|
|
80
|
+
in_project_folder do
|
81
|
+
File.exists?(file).should(is == 'is' ? be_true : be_false)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
Then /^file with name matching "(.*)" is created/ do |pattern|
|
86
|
+
in_project_folder do
|
87
|
+
Dir[pattern].should_not be_empty
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
Then /^file "(.*)" contents (does|does not) match \/(.*)\// do |file, does, regex|
|
92
|
+
in_project_folder do
|
93
|
+
actual_output = File.read(file)
|
94
|
+
(does == 'does') ?
|
95
|
+
actual_output.should(match(/#{regex}/)) :
|
96
|
+
actual_output.should_not(match(/#{regex}/))
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
Then /^file "([^"]*)" contains "([^"]*)"$/ do |file, text|
|
101
|
+
in_project_folder do
|
102
|
+
actual_output = File.read(file)
|
103
|
+
actual_output.should contain(text)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
Then /gem file "(.*)" and generated file "(.*)" should be the same/ do |gem_file, project_file|
|
109
|
+
File.exists?(gem_file).should be_true
|
110
|
+
File.exists?(project_file).should be_true
|
111
|
+
gem_file_contents = File.read(File.dirname(__FILE__) + "/../../#{gem_file}")
|
112
|
+
project_file_contents = File.read(File.join(@active_project_folder, project_file))
|
113
|
+
project_file_contents.should == gem_file_contents
|
114
|
+
end
|
115
|
+
|
116
|
+
Then /^(does|does not) invoke generator "(.*)"$/ do |does_invoke, generator|
|
117
|
+
actual_output = get_command_output
|
118
|
+
does_invoke == "does" ?
|
119
|
+
actual_output.should(match(/dependency\s+#{generator}/)) :
|
120
|
+
actual_output.should_not(match(/dependency\s+#{generator}/))
|
121
|
+
end
|
122
|
+
|
123
|
+
Then /help options "(.*)" and "(.*)" are displayed/ do |opt1, opt2|
|
124
|
+
actual_output = get_command_output
|
125
|
+
actual_output.should match(/#{opt1}/)
|
126
|
+
actual_output.should match(/#{opt2}/)
|
127
|
+
end
|
128
|
+
|
129
|
+
Then /^I should see "([^\"]*)"$/ do |text|
|
130
|
+
actual_output = get_command_output
|
131
|
+
actual_output.should contain(text)
|
132
|
+
end
|
133
|
+
|
134
|
+
Then /^I should not see "([^\"]*)"$/ do |text|
|
135
|
+
actual_output =
|
136
|
+
actual_output.should_not contain(text)
|
137
|
+
end
|
138
|
+
|
139
|
+
Then /^I should see$/ do |text|
|
140
|
+
actual_output = get_command_output
|
141
|
+
actual_output.should contain(text)
|
142
|
+
end
|
143
|
+
|
144
|
+
Then /^I should not see$/ do |text|
|
145
|
+
actual_output = get_command_output
|
146
|
+
actual_output.should_not contain(text)
|
147
|
+
end
|
148
|
+
|
149
|
+
Then /^I should see exactly$/ do |text|
|
150
|
+
actual_output = get_command_output
|
151
|
+
actual_output.should == text
|
152
|
+
end
|
153
|
+
|
154
|
+
Then /^I should see all (\d+) tests pass/ do |expected_test_count|
|
155
|
+
expected = %r{^#{expected_test_count} tests, \d+ assertions, 0 failures, 0 errors}
|
156
|
+
actual_output = get_command_output
|
157
|
+
actual_output.should match(expected)
|
158
|
+
end
|
159
|
+
|
160
|
+
Then /^I should see all (\d+) examples pass/ do |expected_test_count|
|
161
|
+
expected = %r{^#{expected_test_count} examples?, 0 failures}
|
162
|
+
actual_output = get_command_output
|
163
|
+
actual_output.should match(expected)
|
164
|
+
end
|
165
|
+
|
166
|
+
Then /^yaml file "(.*)" contains (\{.*\})/ do |file, yaml|
|
167
|
+
in_project_folder do
|
168
|
+
yaml = eval yaml
|
169
|
+
YAML.load(File.read(file)).should == yaml
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
Then /^Rakefile can display tasks successfully/ do
|
174
|
+
@stdout = File.expand_path(File.join(@tmp_root, "rakefile.out"))
|
175
|
+
in_project_folder do
|
176
|
+
system "rake -T > #{@stdout.inspect} 2> #{@stdout.inspect}"
|
177
|
+
end
|
178
|
+
actual_output = get_command_output
|
179
|
+
actual_output.should match(/^rake\s+\w+\s+#\s.*/)
|
180
|
+
end
|
181
|
+
|
182
|
+
Then /^task "rake (.*)" is executed successfully/ do |task|
|
183
|
+
@stdout.should_not be_nil
|
184
|
+
actual_output = get_command_output
|
185
|
+
actual_output.should_not match(/^Don't know how to build task '#{task}'/)
|
186
|
+
actual_output.should_not match(/Error/i)
|
187
|
+
end
|
188
|
+
|
189
|
+
Then /^gem spec key "(.*)" contains \/(.*)\// do |key, regex|
|
190
|
+
in_project_folder do
|
191
|
+
gem_file = Dir["pkg/*.gem"].first
|
192
|
+
gem_spec = Gem::Specification.from_yaml(`gem spec #{gem_file}`)
|
193
|
+
spec_value = gem_spec.send(key.to_sym)
|
194
|
+
spec_value.to_s.should match(/#{regex}/)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
Then /^the file "([^\"]*)" is a valid gemspec$/ do |filename|
|
199
|
+
spec = eval(File.read(filename))
|
200
|
+
spec.validate
|
201
|
+
end
|
202
|
+
|
203
|
+
When /^I create a new node with the following options on "http:\/\/(.+?):(\d+)":$/ do |host, port, table|
|
204
|
+
options = table.raw.inject({}) do |options, (key, value)|
|
205
|
+
options[(key.to_sym rescue key) || key] = value
|
206
|
+
options
|
207
|
+
end
|
208
|
+
|
209
|
+
Recipes::Api.setup_base_url(:host => host, :port => port.to_i)
|
210
|
+
Recipes::Api.add_node(options)
|
211
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
Given /^I am in the "([^\"]*)" project folder$/ do |project|
|
2
|
+
project_folder = File.expand_path(File.join(@fixtures_path, "projects", project))
|
3
|
+
in_tmp_folder do
|
4
|
+
FileUtils.cp_r(project_folder, project)
|
5
|
+
setup_active_project_folder(project)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
Given /^I already have cookbooks installed$/ do
|
10
|
+
cookbooks_folder = File.expand_path(File.join(@fixtures_path, "cookbooks"))
|
11
|
+
in_project_folder do
|
12
|
+
FileUtils.cp_r(cookbooks_folder, ".")
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
Given /^I want to fake out the boot sequence of Recipes$/ do
|
2
|
+
base_path = File.join(File.dirname(__FILE__) + "/../../fixtures/Recipes_boot_sequence/")
|
3
|
+
FakeWeb.register_uri(:get, "http://app-master-hostname.compute-1.amazonaws.com/", [
|
4
|
+
{:body => File.read(base_path + "pre_Recipes_booting.html")},
|
5
|
+
{:body => File.read(base_path + "Recipes_booting.html")},
|
6
|
+
{:body => File.read(base_path + "Recipes_ready.html")}
|
7
|
+
])
|
8
|
+
end
|
9
|
+
|
10
|
+
Given /^I have public key "([^"]*)" on host "([^"]*)"$/ do |public_key_value, host|
|
11
|
+
mock_target = File.expand_path("../../../tmp/scp_mock", __FILE__)
|
12
|
+
File.open(mock_target, "w") { |file| file << public_key_value }
|
13
|
+
end
|
14
|
+
|
15
|
+
Given /^I set "([^"]*)" as the default Recipes server$/ do |host|
|
16
|
+
require "Recipes"
|
17
|
+
require "Recipes/config"
|
18
|
+
Recipes::Api.setup_base_url(:host => host, :port => 80)
|
19
|
+
Recipes::Api.send(:cache_base_uri)
|
20
|
+
end
|
21
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module CommonHelpers
|
2
|
+
def get_command_output
|
3
|
+
strip_color_codes(File.read(@stdout)).chomp
|
4
|
+
end
|
5
|
+
|
6
|
+
def strip_color_codes(text)
|
7
|
+
text.gsub(/\e\[\d+m/, '')
|
8
|
+
end
|
9
|
+
|
10
|
+
def in_tmp_folder(&block)
|
11
|
+
FileUtils.chdir(@tmp_root, &block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def in_project_folder(&block)
|
15
|
+
project_folder = @active_project_folder || @tmp_root
|
16
|
+
FileUtils.chdir(project_folder, &block)
|
17
|
+
end
|
18
|
+
|
19
|
+
def in_home_folder(&block)
|
20
|
+
FileUtils.chdir(@home_path, &block)
|
21
|
+
end
|
22
|
+
|
23
|
+
def force_local_lib_override(project_name = @project_name)
|
24
|
+
rakefile = File.read(File.join(project_name, 'Rakefile'))
|
25
|
+
File.open(File.join(project_name, 'Rakefile'), "w+") do |f|
|
26
|
+
f << "$:.unshift('#{@lib_path}')\n"
|
27
|
+
f << rakefile
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def setup_active_project_folder project_name
|
32
|
+
@active_project_folder = File.join(@tmp_root, project_name)
|
33
|
+
@project_name = project_name
|
34
|
+
end
|
35
|
+
|
36
|
+
# capture both [stdout, stderr] as well as stdin
|
37
|
+
def capture_stdios(input = nil, &block)
|
38
|
+
require 'stringio'
|
39
|
+
org_stdin, $stdin = $stdin, StringIO.new(input) if input
|
40
|
+
org_stdout, $stdout = $stdout, StringIO.new
|
41
|
+
org_stderr, $stderr = $stdout, StringIO.new
|
42
|
+
yield
|
43
|
+
return [$stdout.string, $stderr.string]
|
44
|
+
ensure
|
45
|
+
$stderr = org_stderr
|
46
|
+
$stdout = org_stdout
|
47
|
+
$stdin = org_stdin
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
World(CommonHelpers)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
$:.unshift(File.expand_path(File.dirname(__FILE__) + '/../../lib'))
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'engineyard-recipes'
|
4
|
+
|
5
|
+
path = ENV['PATH']
|
6
|
+
|
7
|
+
Before do
|
8
|
+
@tmp_root = File.dirname(__FILE__) + "/../../tmp"
|
9
|
+
@active_project_folder = @tmp_root
|
10
|
+
@home_path = File.expand_path(File.join(@tmp_root, "home"))
|
11
|
+
@lib_path = File.expand_path(File.dirname(__FILE__) + "/../../lib")
|
12
|
+
@fixtures_path = File.expand_path(File.dirname(__FILE__) + "/../../fixtures")
|
13
|
+
FileUtils.rm_rf @tmp_root
|
14
|
+
FileUtils.mkdir_p @home_path
|
15
|
+
ENV['HOME'] = @home_path
|
16
|
+
fixture_bin_path = File.expand_path('../../../fixtures/bin', __FILE__)
|
17
|
+
ENV['PATH'] = fixture_bin_path + ":" + path
|
18
|
+
end
|
data/fixtures/bin/scp
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require_recipe 'redis'
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
Please wait while Recipes is getting ready to work
|
@@ -0,0 +1 @@
|
|
1
|
+
Recipes is up!
|
@@ -0,0 +1 @@
|
|
1
|
+
This is some page before the instance is launched.
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'engineyard-recipes/thor-ext/actions/directory'
|
3
|
+
|
4
|
+
module Engineyard
|
5
|
+
module Recipes
|
6
|
+
class CLI < Thor
|
7
|
+
|
8
|
+
desc "init", "Creates cookbooks scaffolding for your recipes"
|
9
|
+
def init
|
10
|
+
require 'engineyard-recipes/generators/init_generator'
|
11
|
+
Engineyard::Recipes::Generators::InitGenerator.start
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "version", "show version information"
|
15
|
+
def version
|
16
|
+
require 'engineyard-recipes/version'
|
17
|
+
shell.say Engineyard::Recipes::VERSION
|
18
|
+
end
|
19
|
+
|
20
|
+
map "-v" => :version, "--version" => :version, "-h" => :help, "--help" => :help
|
21
|
+
|
22
|
+
private
|
23
|
+
def say(msg, color = nil)
|
24
|
+
color ? shell.say(msg, color) : shell.say(msg)
|
25
|
+
end
|
26
|
+
|
27
|
+
def display(text)
|
28
|
+
shell.say text
|
29
|
+
exit
|
30
|
+
end
|
31
|
+
|
32
|
+
def error(text)
|
33
|
+
shell.say "ERROR: #{text}", :red
|
34
|
+
exit
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns the [host, port] for the target Recipes CI server
|
38
|
+
def host_port(options)
|
39
|
+
require "recipes"
|
40
|
+
require "recipes/config"
|
41
|
+
if base_uri = ::Recipes::Config.config['base_uri']
|
42
|
+
uri = URI.parse(::Recipes::Config.config['base_uri'])
|
43
|
+
host = uri.host
|
44
|
+
port = uri.port
|
45
|
+
end
|
46
|
+
host = options["host"] if options["host"]
|
47
|
+
port = options["port"] || port || '80'
|
48
|
+
[host, port]
|
49
|
+
end
|
50
|
+
|
51
|
+
def no_environments_discovered
|
52
|
+
say "No environments with name recipes, recipes_server, recipes_production, recipes_server_production.", :red
|
53
|
+
say "Either:"
|
54
|
+
say " * Create an Engine Yard Cloud environment called recipes, recipes_server, recipes_production, recipes_server_production"
|
55
|
+
say " * Use --environment/--account flags to select Engine Yard Cloud environment"
|
56
|
+
end
|
57
|
+
|
58
|
+
def too_many_environments_discovered(environments)
|
59
|
+
say "Multiple environments possible, please be more specific:", :red
|
60
|
+
say ""
|
61
|
+
environments.each do |env_name, account_name, environment|
|
62
|
+
say " ey-recipes install_server --environment "; say "'#{env_name}' ", :yellow;
|
63
|
+
say "--account "; say "'#{account_name}'", :yellow
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def watch_page_while(host, port, path)
|
68
|
+
waiting = true
|
69
|
+
while waiting
|
70
|
+
begin
|
71
|
+
Net::HTTP.start(host, port) do |http|
|
72
|
+
req = http.get(path)
|
73
|
+
waiting = yield req
|
74
|
+
end
|
75
|
+
sleep 1; print '.'; $stdout.flush
|
76
|
+
rescue SocketError => e
|
77
|
+
sleep 1; print 'x'; $stdout.flush
|
78
|
+
rescue Exception => e
|
79
|
+
puts e.message
|
80
|
+
sleep 1; print '.'; $stdout.flush
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
|
2
|
+
class Chef
|
3
|
+
class Resource
|
4
|
+
class RubyBlock < Chef::Resource
|
5
|
+
def initialize(name, collection=nil, node=nil)
|
6
|
+
super(name, collection, node)
|
7
|
+
@resource_name = :ruby_block
|
8
|
+
@action = :create
|
9
|
+
@allowed_actions.push(:create)
|
10
|
+
end
|
11
|
+
|
12
|
+
def block(&block)
|
13
|
+
if block
|
14
|
+
@block = block
|
15
|
+
else
|
16
|
+
@block
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
class Chef
|
25
|
+
class Provider
|
26
|
+
class RubyBlock < Chef::Provider
|
27
|
+
def load_current_resource
|
28
|
+
Chef::Log.debug(@new_resource.inspect)
|
29
|
+
true
|
30
|
+
end
|
31
|
+
|
32
|
+
def action_create
|
33
|
+
@new_resource.block.call
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
Chef::Platform.platforms[:default].merge! :ruby_block => Chef::Provider::RubyBlock
|
40
|
+
|
data/lib/engineyard-recipes/generators/init_generator/templates/cookbooks/main/recipes/default.rb
ADDED
File without changes
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'thor/group'
|
2
|
+
|
3
|
+
module Engineyard::Recipes
|
4
|
+
module Generators
|
5
|
+
class InitGenerator < Thor::Group
|
6
|
+
include Thor::Actions
|
7
|
+
|
8
|
+
def self.source_root
|
9
|
+
File.join(File.dirname(__FILE__), "init_generator", "templates")
|
10
|
+
end
|
11
|
+
|
12
|
+
def install_cookbooks
|
13
|
+
file = "cookbooks/main/recipes/default.rb"
|
14
|
+
unless File.exists?(File.join(destination_root, "cookbooks/main/recipes/default.rb"))
|
15
|
+
directory "cookbooks"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# def attributes
|
20
|
+
# template "attributes.rb.tt", "cookbooks/recipes_slave/attributes/default.rb"
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# def recipe
|
24
|
+
# copy_file "recipes.rb", "cookbooks/recipes_slave/recipes/default.rb"
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
def readme
|
28
|
+
say ""
|
29
|
+
say "Lovely.", :green
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
def say(msg, color = nil)
|
34
|
+
color ? shell.say(msg, color) : shell.say(msg)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Extension: Sorts the Dir[lookup] to ensure deterministic ordering of actions
|
2
|
+
# to allow test assertions
|
3
|
+
|
4
|
+
class Thor
|
5
|
+
module Actions
|
6
|
+
class Directory < EmptyDirectory #:nodoc:
|
7
|
+
protected
|
8
|
+
|
9
|
+
def execute!
|
10
|
+
lookup = config[:recursive] ? File.join(source, '**') : source
|
11
|
+
lookup = File.join(lookup, '{*,.[a-z]*}')
|
12
|
+
|
13
|
+
Dir[lookup].sort.each do |file_source|
|
14
|
+
next if File.directory?(file_source)
|
15
|
+
file_destination = File.join(given_destination, file_source.gsub(source, '.'))
|
16
|
+
file_destination.gsub!('/./', '/')
|
17
|
+
|
18
|
+
case file_source
|
19
|
+
when /\.empty_directory$/
|
20
|
+
dirname = File.dirname(file_destination).gsub(/\/\.$/, '')
|
21
|
+
next if dirname == given_destination
|
22
|
+
base.empty_directory(dirname, config)
|
23
|
+
when /\.tt$/
|
24
|
+
destination = base.template(file_source, file_destination[0..-4], config, &@block)
|
25
|
+
else
|
26
|
+
destination = base.copy_file(file_source, file_destination, config, &@block)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: engineyard-recipes
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Dr Nic Williams
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-11-13 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: thor
|
16
|
+
requirement: &70345820762760 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.14.6
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70345820762760
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: engineyard
|
27
|
+
requirement: &70345820762200 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.4.6
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70345820762200
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rake
|
38
|
+
requirement: &70345820761680 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.9.2
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70345820761680
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: cucumber
|
49
|
+
requirement: &70345820761180 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.1.2
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70345820761180
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: rspec
|
60
|
+
requirement: &70345820760660 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ~>
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 2.7.0
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70345820760660
|
69
|
+
description: Tools to generate, upload, test and apply chef recipes for Engine Yard
|
70
|
+
Cloud.
|
71
|
+
email:
|
72
|
+
- drnicwilliams@gmail.com
|
73
|
+
executables:
|
74
|
+
- ey-recipes
|
75
|
+
extensions: []
|
76
|
+
extra_rdoc_files: []
|
77
|
+
files:
|
78
|
+
- .gitignore
|
79
|
+
- Gemfile
|
80
|
+
- README.md
|
81
|
+
- Rakefile
|
82
|
+
- bin/ey-recipes
|
83
|
+
- engineyard-recipes.gemspec
|
84
|
+
- features/init-new-cookbook.feature
|
85
|
+
- features/step_definitions/api_steps.rb
|
86
|
+
- features/step_definitions/common_steps.rb
|
87
|
+
- features/step_definitions/fixture_project_steps.rb
|
88
|
+
- features/step_definitions/jenkins_steps.rb
|
89
|
+
- features/support/common.rb
|
90
|
+
- features/support/env.rb
|
91
|
+
- features/support/matchers.rb
|
92
|
+
- fixtures/bin/README.md
|
93
|
+
- fixtures/bin/scp
|
94
|
+
- fixtures/cookbooks/main/recipes/default.rb
|
95
|
+
- fixtures/cookbooks/redis/recipes/default.rb
|
96
|
+
- fixtures/jenkins_boot_sequence/jenkins_booting.html
|
97
|
+
- fixtures/jenkins_boot_sequence/jenkins_ready.html
|
98
|
+
- fixtures/jenkins_boot_sequence/pre_jenkins_booting.html
|
99
|
+
- fixtures/projects/rails/Gemfile
|
100
|
+
- fixtures/projects/rails/Rakefile
|
101
|
+
- lib/engineyard-recipes.rb
|
102
|
+
- lib/engineyard-recipes/cli.rb
|
103
|
+
- lib/engineyard-recipes/generators/init_generator.rb
|
104
|
+
- lib/engineyard-recipes/generators/init_generator/templates/cookbooks/main/attributes/recipe.rb
|
105
|
+
- lib/engineyard-recipes/generators/init_generator/templates/cookbooks/main/definitions/ey_cloud_report.rb
|
106
|
+
- lib/engineyard-recipes/generators/init_generator/templates/cookbooks/main/libraries/ruby_block.rb
|
107
|
+
- lib/engineyard-recipes/generators/init_generator/templates/cookbooks/main/libraries/run_for_app.rb
|
108
|
+
- lib/engineyard-recipes/generators/init_generator/templates/cookbooks/main/recipes/default.rb
|
109
|
+
- lib/engineyard-recipes/thor-ext/actions/directory.rb
|
110
|
+
- lib/engineyard-recipes/version.rb
|
111
|
+
homepage: ''
|
112
|
+
licenses: []
|
113
|
+
post_install_message:
|
114
|
+
rdoc_options: []
|
115
|
+
require_paths:
|
116
|
+
- lib
|
117
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
118
|
+
none: false
|
119
|
+
requirements:
|
120
|
+
- - ! '>='
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
segments:
|
124
|
+
- 0
|
125
|
+
hash: -3089194490767720342
|
126
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
|
+
none: false
|
128
|
+
requirements:
|
129
|
+
- - ! '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
segments:
|
133
|
+
- 0
|
134
|
+
hash: -3089194490767720342
|
135
|
+
requirements: []
|
136
|
+
rubyforge_project: engineyard-recipes
|
137
|
+
rubygems_version: 1.8.6
|
138
|
+
signing_key:
|
139
|
+
specification_version: 3
|
140
|
+
summary: Tools to generate, upload, test and apply chef recipes for Engine Yard Cloud.
|
141
|
+
test_files:
|
142
|
+
- features/init-new-cookbook.feature
|
143
|
+
- features/step_definitions/api_steps.rb
|
144
|
+
- features/step_definitions/common_steps.rb
|
145
|
+
- features/step_definitions/fixture_project_steps.rb
|
146
|
+
- features/step_definitions/jenkins_steps.rb
|
147
|
+
- features/support/common.rb
|
148
|
+
- features/support/env.rb
|
149
|
+
- features/support/matchers.rb
|