stackfu 0.1.1 → 0.1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +4 -0
- data/Manifest +36 -4
- data/Rakefile +1 -1
- data/autotest/discover.rb +1 -0
- data/firewall/config/01-controls.yml +5 -0
- data/firewall/config/02-requirements.yml +4 -0
- data/firewall/config/03-executions.yml +6 -0
- data/firewall/config/03-scripts.yml +6 -0
- data/firewall/config/04-validations.yml +4 -0
- data/firewall/executables/configure_ufw.sh.erb +9 -0
- data/firewall/executables/install_ufw.sh.erb +7 -0
- data/firewall/script/configure_ufw.sh.erb +9 -0
- data/firewall/script/install_ufw.sh.erb +7 -0
- data/firewall/script.yml +8 -0
- data/lib/stackfu/api_hooks.rb +2 -2
- data/lib/stackfu/app.rb +5 -5
- data/lib/stackfu/commands/command.rb +7 -3
- data/lib/stackfu/commands/config_command.rb +1 -1
- data/lib/stackfu/commands/deploy_command.rb +53 -61
- data/lib/stackfu/commands/dump_command.rb +46 -40
- data/lib/stackfu/commands/generate_command.rb +10 -12
- data/lib/stackfu/commands/help_command.rb +1 -1
- data/lib/stackfu/commands/list_command.rb +76 -22
- data/lib/stackfu/commands/publish_command.rb +35 -18
- data/lib/stackfu/commands/server_command.rb +124 -124
- data/lib/stackfu/date_helper.rb +111 -0
- data/lib/stackfu.rb +4 -2
- data/spec/fixtures/scripts/all.json +11 -0
- data/spec/fixtures/scripts/create.json +10 -0
- data/spec/fixtures/scripts/delete.json +10 -0
- data/spec/fixtures/scripts/firewall.json +12 -0
- data/spec/fixtures/scripts/none.json +12 -0
- data/spec/fixtures/scripts/not_found.json +11 -0
- data/spec/fixtures/scripts/script_not_found.json +11 -0
- data/spec/fixtures/servers/all.json +12 -0
- data/spec/fixtures/servers/cannot_deploy.json +0 -0
- data/spec/fixtures/servers/deploy.json +290 -0
- data/spec/fixtures/servers/none.json +12 -0
- data/spec/fixtures/servers/not_found.json +11 -0
- data/spec/fixtures/servers/webbynode/deploy.json +12 -0
- data/spec/fixtures/servers/webbynode.json +12 -0
- data/spec/spec_helper.rb +191 -0
- data/spec/stackfu/api_hooks_spec.rb +7 -0
- data/spec/stackfu/commands/deploy_command_spec.rb +65 -0
- data/spec/stackfu/commands/dump_command_spec.rb +47 -0
- data/spec/stackfu/commands/generate_command_spec.rb +90 -0
- data/spec/stackfu/commands/list_command_spec.rb +53 -0
- data/spec/stackfu/commands/publish_command_spec.rb +67 -0
- data/stackfu.gemspec +4 -4
- data/templates/02-requirements.yml.erb +8 -10
- data/templates/{03-scripts.yml.erb → 03-executions.yml.erb} +3 -3
- data/templates/04-validations.yml.erb +1 -2
- data/templates/stack.yml.erb +4 -13
- data/test/support/fixtures.rb +1 -1
- data/test/unit/commands/test_server_command.rb +259 -259
- metadata +42 -7
- data/test/stack.yml +0 -26
- /data/stackfu-installer/config/{03-scripts.yml → 03-executions.yml} +0 -0
@@ -0,0 +1,12 @@
|
|
1
|
+
HTTP/1.1 200 OK
|
2
|
+
Etag: "d751713988987e9331980363e24189ce"
|
3
|
+
Connection: Keep-Alive
|
4
|
+
Content-Type: application/json; charset=utf-8
|
5
|
+
Date: Mon, 06 Sep 2010 03:09:00 GMT
|
6
|
+
Server: WEBrick/1.3.1 (Ruby/1.8.7/2009-12-24)
|
7
|
+
X-Runtime: 0.625119
|
8
|
+
Content-Length: 2
|
9
|
+
Cache-Control: max-age=0, private, must-revalidate
|
10
|
+
Set-Cookie: _stackfu_session=BAh7ByIPc2Vzc2lvbl9pZCIlMGRiYzFmZjlmNGFkNDBjNDlhYzE2ODEwM2E1NDYzM2QiGXdhcmRlbi51c2VyLnVzZXIua2V5WwciCVVzZXJvOhNCU09OOjpPYmplY3RJRAY6CkBkYXRhWxFpUWkBg2kB%2FmkkaQHUaQGJaQHoaQGTaQGPaQBpAGkJ--87aa1578a2f486481a5ccb365970fd9dcd4f1449; path=/; HttpOnly
|
11
|
+
|
12
|
+
[]
|
@@ -0,0 +1,11 @@
|
|
1
|
+
HTTP/1.1 404 Not Found
|
2
|
+
Connection: Keep-Alive
|
3
|
+
Content-Type: application/json; charset=utf-8
|
4
|
+
Date: Mon, 06 Sep 2010 15:07:35 GMT
|
5
|
+
Server: WEBrick/1.3.1 (Ruby/1.8.7/2009-12-24)
|
6
|
+
X-Runtime: 0.387455
|
7
|
+
Content-Length: 25
|
8
|
+
Cache-Control: no-cache
|
9
|
+
Set-Cookie: _stackfu_session=BAh7ByIPc2Vzc2lvbl9pZCIlZDI4YjQ5MGRlMTM0NTVkZjZmMTE1OTg2MjEwZGI0ZGIiGXdhcmRlbi51c2VyLnVzZXIua2V5WwciCVVzZXJvOhNCU09OOjpPYmplY3RJRAY6CkBkYXRhWxFpUWkBg2kB%2FmkkaQHUaQGJaQHoaQGTaQGPaQBpAGkJ--283c189facf98f987ce9dce345c20a91db7e03ae; path=/; HttpOnly
|
10
|
+
|
11
|
+
Server firewall not found
|
@@ -0,0 +1,12 @@
|
|
1
|
+
HTTP/1.1 200 OK
|
2
|
+
Etag: "b2d8ba4761967f030b2ea220620986b1"
|
3
|
+
Connection: Keep-Alive
|
4
|
+
Content-Type: application/json; charset=utf-8
|
5
|
+
Date: Sat, 04 Sep 2010 21:35:47 GMT
|
6
|
+
Server: WEBrick/1.3.1 (Ruby/1.8.7/2009-12-24)
|
7
|
+
X-Runtime: 0.313166
|
8
|
+
Content-Length: 1730
|
9
|
+
Cache-Control: max-age=0, private, must-revalidate
|
10
|
+
Set-Cookie: _stackfu_session=BAh7ByIPc2Vzc2lvbl9pZCIlYzZiMDZlNmJlZTgwZTU3ODA1NTgzMjk1YmI4N2FhN2EiGXdhcmRlbi51c2VyLnVzZXIua2V5WwciCVVzZXJvOhNCU09OOjpPYmplY3RJRAY6CkBkYXRhWxFpUWkBgml%2BaXNpAdRpAYlpAehpM2kBwWkAaQBpCA%3D%3D--b119069c65fff79fbc923dc31cc993334e278c79; path=/; HttpOnly
|
11
|
+
|
12
|
+
{"stack":{"slug":null,"_id":"4c82bbb3d489e856ce000005","scripts":[{"slug":"firewall","name":"firewall","controls":[{"name":"Ports","label":"Ports","_id":"4c82796ed489e82ec1000005","_type":"Textbox","type":"Textbox","hint":"separate by comma's"}],"created_at":"2010-09-04T13:53:02-03:00","updated_at":"2010-09-04T13:53:02-03:00","_id":"4c82796ed489e82ec1000008","validations":[{"body":"test -x ufw","_id":"4c82796ed489e82ec1000002","_type":"ExecutableExists","params":{"data":"ufw"},"description":"File ufw exists and is executable"}],"user_id":"4c82796ed489e82ec1000003","requirements":[{"body":"test -x apt-get","_id":"4c82796ed489e82ec1000001","_type":"ExecutableExists","params":{"data":"apt-get"},"description":"File apt-get exists and is executable"}],"executions":[{"body":" # \n # configure_ufw.sh\n # Tue Dec 01 15:06:48 -0200 2009\n #\n\n apt-get update\n apt-get install -y ufw\n","_id":"4c82796ed489e82ec1000006","description":"Install Ufw","watching_user_ids":[]},{"body":" # \n # install_ufw.sh\n # Tue Dec 01 15:06:48 -0200 2009\n #\n\n ufw default deny\n <% ports.split(\",\").each do |port| %>\n ufw allow <%= port %> \n <% end %>\n","_id":"4c82796ed489e82ec1000007","description":"Configure Ufw","watching_user_ids":[]}],"description":"Set up a firewall for your server to improve security.\n Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n Praesent eget erat libero, id malesuada tortor.\n Donec pharetra sapien et nulla ultricies ac pharetra neque vulputate.","watching_user_ids":[]}]},"provider_id":null,"server_id":"4c82796ed489e82ec1000017","_id":"4c82bbb3d489e856ce000006","params":{"ports":"80,23,22"},"status":"queued"}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
HTTP/1.1 200 OK
|
2
|
+
Etag: "41c3b7d21d2e41ec1838513f1e889bfa"
|
3
|
+
Connection: Keep-Alive
|
4
|
+
Content-Type: application/json; charset=utf-8
|
5
|
+
Date: Sat, 04 Sep 2010 20:33:27 GMT
|
6
|
+
Server: WEBrick/1.3.1 (Ruby/1.8.7/2009-12-24)
|
7
|
+
X-Runtime: 0.444424
|
8
|
+
Content-Length: 451
|
9
|
+
Cache-Control: max-age=0, private, must-revalidate
|
10
|
+
Set-Cookie: _stackfu_session=BAh7ByIPc2Vzc2lvbl9pZCIlNDZkMzg5M2MxOWFmNTFmY2U3YmZjODMzNTFjNDYwMjkiGXdhcmRlbi51c2VyLnVzZXIua2V5WwciCVVzZXJvOhNCU09OOjpPYmplY3RJRAY6CkBkYXRhWxFpUWkBgml%2BaXNpAdRpAYlpAehpM2kBwWkAaQBpCA%3D%3D--4d15caee746e09b3d7fd6c7a63937dbf32696736; path=/; HttpOnly
|
11
|
+
|
12
|
+
{"slug":"webbynode","name":"Webbynode","updated_at":"2010-09-04T17:32:56-03:00","_id":"4c82796ed489e82ec1000017","provider_name":"Linnode","user_id":"4c82796ed489e82ec1000003","ip":"123.45.678.90","description":"Nunc hendrerit blandit ultrices. Cras pellentesque turpis et dolo\n molestie vitae lacinia nisi iaculis. Pellentesque vitae quam enim. Vivamus dui quam,\n aliquet in condimentum vel, placerat sit amet quam. Aliquam ac sollicitudin dui."}
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,191 @@
|
|
1
|
+
# Require RSpec
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rspec'
|
4
|
+
require 'webmock/rspec'
|
5
|
+
require 'pp'
|
6
|
+
|
7
|
+
# Load Webbynode Class
|
8
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib', 'stackfu')
|
9
|
+
|
10
|
+
# Set Testing Environment
|
11
|
+
$testing = true
|
12
|
+
WebMock.disable_net_connect!
|
13
|
+
HighLine.track_eof = false
|
14
|
+
|
15
|
+
# Reads out a file from the fixtures directory
|
16
|
+
|
17
|
+
module StackFuHelpers
|
18
|
+
def read_fixture(file)
|
19
|
+
File.read(File.join(File.dirname(__FILE__), "fixtures", file))
|
20
|
+
end
|
21
|
+
|
22
|
+
def prepare_raise(method, uri, error)
|
23
|
+
request = stub_request(method,
|
24
|
+
"#{StackFu::API.gsub("http://", "http://abc123:X@")}#{uri}")
|
25
|
+
request.to_raise(error)
|
26
|
+
end
|
27
|
+
|
28
|
+
def prepare(method, uri, fixture=uri, options=nil)
|
29
|
+
request = stub_request(method,
|
30
|
+
"#{StackFu::API.gsub("http://", "http://abc123:X@")}#{uri}")
|
31
|
+
|
32
|
+
request = request.with(options) if options
|
33
|
+
|
34
|
+
request.to_return(read_fixture(fixture))
|
35
|
+
end
|
36
|
+
|
37
|
+
def when_asked_to_choose(what, options)
|
38
|
+
$actions << { :type => "choose", :action => options.merge(:prompt => what) }
|
39
|
+
end
|
40
|
+
|
41
|
+
def when_asked(what, options)
|
42
|
+
$actions << { :type => "ask", :action => [what, options[:answer]] }
|
43
|
+
end
|
44
|
+
|
45
|
+
def agree_with(what)
|
46
|
+
$actions << { :type => "agree", :action => what }
|
47
|
+
end
|
48
|
+
|
49
|
+
def disagree_of(what)
|
50
|
+
$actions << { :type => "disagree", :action => what }
|
51
|
+
end
|
52
|
+
|
53
|
+
def redirect_stdout
|
54
|
+
@orig_stdout = $stdout
|
55
|
+
$stdout = StringIO.new
|
56
|
+
end
|
57
|
+
|
58
|
+
def command(cmd, settings_present=true)
|
59
|
+
redirect_stdout
|
60
|
+
cmd ||= ""
|
61
|
+
StackFu::App.expects(:settings?).returns(settings_present)
|
62
|
+
if settings_present
|
63
|
+
StackFu::App.any_instance.expects(:load_config).returns({ :login => "flipper", :token => "abc123" })
|
64
|
+
end
|
65
|
+
StackFu::App.new(cmd.split(" ")).start
|
66
|
+
end
|
67
|
+
|
68
|
+
def stdout
|
69
|
+
if @orig_stdout
|
70
|
+
$stdout.rewind
|
71
|
+
@result = $stdout.read
|
72
|
+
$stdout = @orig_stdout
|
73
|
+
@orig_stdout = nil
|
74
|
+
end
|
75
|
+
|
76
|
+
@result
|
77
|
+
end
|
78
|
+
|
79
|
+
def debug(s)
|
80
|
+
@orig_stdout.puts s
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
Rspec.configure do |config|
|
85
|
+
config.mock_with :mocha
|
86
|
+
|
87
|
+
config.include WebMock
|
88
|
+
config.include StackFuHelpers
|
89
|
+
config.include Rspec::Matchers
|
90
|
+
|
91
|
+
config.before(:each) do
|
92
|
+
$actions = []
|
93
|
+
$asked = []
|
94
|
+
end
|
95
|
+
|
96
|
+
config.after(:each) do
|
97
|
+
stdout if @orig_stdout
|
98
|
+
asked = $asked.map { |s| " - #{s}" }.join("\n")
|
99
|
+
unless $actions.empty?
|
100
|
+
questions = $actions.map do |q|
|
101
|
+
info = case q[:type]
|
102
|
+
when "ask"
|
103
|
+
q[:action].first
|
104
|
+
|
105
|
+
when "choose"
|
106
|
+
txt = "'#{q[:action][:prompt]}'"
|
107
|
+
txt << " with options '#{q[:action][:with_options].join(", ")}'" if q[:action][:with_options]
|
108
|
+
else
|
109
|
+
q[:action]
|
110
|
+
end
|
111
|
+
|
112
|
+
" - #{q[:type]} #{info}"
|
113
|
+
end.join("\n")
|
114
|
+
fail "Expected questions not asked:\n#{questions}\nQuestions responded:\n#{asked}\n"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
module Kernel
|
120
|
+
def choose(*items, &details)
|
121
|
+
if (action = $actions.first)
|
122
|
+
if action[:type] == "choose"
|
123
|
+
item = OpenStruct.new
|
124
|
+
class << item
|
125
|
+
def choice(*args)
|
126
|
+
(self.choices||=[]) << args
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
details.call item
|
131
|
+
|
132
|
+
exp_action = $actions.shift[:action]
|
133
|
+
item.prompt.should == exp_action[:prompt]
|
134
|
+
|
135
|
+
exp_action[:with_options].try(:each) do |opt|
|
136
|
+
item.choices.flatten.include?(opt).should == true
|
137
|
+
end
|
138
|
+
|
139
|
+
if (answer = exp_action[:answer]).is_a?(Numeric)
|
140
|
+
item.choices[answer][0]
|
141
|
+
else
|
142
|
+
answer
|
143
|
+
end
|
144
|
+
end
|
145
|
+
else
|
146
|
+
fail "Unexpected choose"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def ask(question, answer_type = String, &details)
|
151
|
+
if (action = $actions.first)
|
152
|
+
matches = if (expected = action[:action].first).is_a?(Regexp)
|
153
|
+
question =~ expected
|
154
|
+
else
|
155
|
+
question == expected
|
156
|
+
end
|
157
|
+
|
158
|
+
if action[:type] == "ask" and matches
|
159
|
+
$asked << "responded to ask #{action[:action].first} with #{action[:action].last}"
|
160
|
+
exp_action = $actions.shift
|
161
|
+
result = exp_action[:action].last
|
162
|
+
return result
|
163
|
+
end
|
164
|
+
|
165
|
+
fail "Expected to #{action[:type]} #{action[:action].inspect} but asked #{question.inspect}"
|
166
|
+
else
|
167
|
+
fail "Unexpected ask #{question.inspect}"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def agree(yes_or_no_question, character = nil)
|
172
|
+
action = $actions.first
|
173
|
+
if action and action[:action] == yes_or_no_question
|
174
|
+
if action[:type] == "agree" or action[:type] == "disagree"
|
175
|
+
$asked << "#{action[:type]}d to #{action[:action]}"
|
176
|
+
result = $actions.shift[:type] == "agree"
|
177
|
+
# d "#{action[:type]} #{yes_or_no_question} => #{result}"
|
178
|
+
return result
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
if action
|
183
|
+
fail "Expected to #{action[:type]} #{action[:action].inspect} but asked to agree with #{yes_or_no_question.inspect}"
|
184
|
+
else
|
185
|
+
fail "Unexpected agreement #{yes_or_no_question.inspect}"
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def d(x); $stderr.puts x.pretty_inspect; end
|
191
|
+
def rd(x); $stderr.puts x; end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# Load Spec Helper
|
2
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), '../..', 'spec_helper')
|
3
|
+
|
4
|
+
describe StackFu::Commands::DeployCommand do
|
5
|
+
it "presents the options when none given" do
|
6
|
+
command "deploy"
|
7
|
+
stdout.should =~ /You have to tell which script you want to deploy and to which server./
|
8
|
+
end
|
9
|
+
|
10
|
+
it "deploys a server" do
|
11
|
+
prepare(:get, '/servers/webbynode.json')
|
12
|
+
prepare(:get, '/scripts/firewall.json')
|
13
|
+
prepare(:post, '/servers/webbynode/deploy.json')
|
14
|
+
|
15
|
+
when_asked " Ports: ", :answer => "80,23,22"
|
16
|
+
|
17
|
+
agree_with "Continue with script installation?\n"
|
18
|
+
|
19
|
+
command "deploy firewall webbynode"
|
20
|
+
|
21
|
+
stdout.should =~ /Preparing: firewall/
|
22
|
+
stdout.should =~ /Set up a firewall for your server to improve security./
|
23
|
+
end
|
24
|
+
|
25
|
+
it "shows an error when the script is not found" do
|
26
|
+
prepare(:get, '/scripts/my_script.json', '/scripts/not_found.json')
|
27
|
+
|
28
|
+
command "deploy my_script server"
|
29
|
+
stdout.should =~ /Script 'my_script' was not found/
|
30
|
+
end
|
31
|
+
|
32
|
+
it "shows an error when script found but server not found" do
|
33
|
+
prepare(:get, '/scripts/firewall.json', '/scripts/firewall.json')
|
34
|
+
prepare(:get, '/servers/slicey.json', '/servers/not_found.json')
|
35
|
+
|
36
|
+
command "deploy firewall slicey"
|
37
|
+
stdout.should =~ /Server 'slicey' was not found/
|
38
|
+
end
|
39
|
+
|
40
|
+
it "tells the user if there's a problem submitting the deployment" do
|
41
|
+
prepare(:get, '/scripts/firewall.json')
|
42
|
+
prepare(:get, '/servers/webbynode.json')
|
43
|
+
prepare_raise(:post, '/servers/webbynode/deploy.json', Errno::ECONNREFUSED)
|
44
|
+
|
45
|
+
when_asked " Ports: ", :answer => "20,21,22"
|
46
|
+
|
47
|
+
agree_with "Continue with script installation?\n"
|
48
|
+
|
49
|
+
command "deploy firewall webbynode"
|
50
|
+
stdout.should =~ /Could not connect to StackFu server./
|
51
|
+
end
|
52
|
+
|
53
|
+
it "stops deploying if user disagree of continue prompt" do
|
54
|
+
prepare(:get, '/scripts/firewall.json')
|
55
|
+
prepare(:get, '/servers/webbynode.json')
|
56
|
+
|
57
|
+
when_asked " Ports: ", :answer => "20,21,22"
|
58
|
+
|
59
|
+
disagree_of "Continue with script installation?\n"
|
60
|
+
|
61
|
+
command "deploy firewall webbynode"
|
62
|
+
stdout.should =~ /Aborted./
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# Load Spec Helper
|
2
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), '../..', 'spec_helper')
|
3
|
+
|
4
|
+
describe StackFu::Commands::DumpCommand do
|
5
|
+
it "requires a parameter" do
|
6
|
+
command "dump"
|
7
|
+
stdout.should =~ /You have to tell which script you want to dump/
|
8
|
+
end
|
9
|
+
|
10
|
+
it "displays an error when the stack is not found" do
|
11
|
+
prepare :get, "/scripts/my_script.json", "/scripts/not_found.json"
|
12
|
+
command "dump my_script"
|
13
|
+
stdout.should =~ /Script 'my_script' was not found/
|
14
|
+
end
|
15
|
+
|
16
|
+
it "asks before overwriting an existing folder" do
|
17
|
+
prepare :get, "/scripts/firewall.json", "/scripts/firewall.json"
|
18
|
+
|
19
|
+
StackFu::Commands::DumpCommand.any_instance.expects(:directory?).with("firewall").returns(true)
|
20
|
+
disagree_of("There is already a folder called 'firewall'. Do you want to overwrite its contents?")
|
21
|
+
|
22
|
+
command "dump firewall"
|
23
|
+
stdout.should =~ /Aborted./
|
24
|
+
end
|
25
|
+
|
26
|
+
context "valid script" do
|
27
|
+
it "creates a directory structure that describes the stack" do
|
28
|
+
prepare :get, "/scripts/firewall.json", "/scripts/firewall.json"
|
29
|
+
|
30
|
+
StackFu::Commands::DumpCommand.any_instance.expects(:directory?).with("firewall").returns(false)
|
31
|
+
|
32
|
+
command "dump firewall"
|
33
|
+
stdout.should =~ /^\tcreate firewall\//
|
34
|
+
stdout.should =~ /^\tcreate firewall\/script.yml/
|
35
|
+
stdout.should =~ /^\tcreate firewall\/config\//
|
36
|
+
stdout.should =~ /^\tcreate firewall\/config\/01-controls.yml/
|
37
|
+
stdout.should =~ /^\tcreate firewall\/config\/02-requirements.yml/
|
38
|
+
stdout.should =~ /^\tcreate firewall\/config\/03-executions.yml/
|
39
|
+
stdout.should =~ /^\tcreate firewall\/config\/04-validations.yml/
|
40
|
+
stdout.should =~ /^\tcreate firewall\/executables\//
|
41
|
+
stdout.should =~ /^\tcreate firewall\/executables\//
|
42
|
+
stdout.should =~ /^\tcreate firewall\/executables\/install_ufw.sh.erb/
|
43
|
+
stdout.should =~ /^\tcreate firewall\/executables\/configure_ufw.sh.erb/
|
44
|
+
stdout.should =~ /^Script firewall dumped successfully/
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# Load Spec Helper
|
2
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), '../..', 'spec_helper')
|
3
|
+
|
4
|
+
describe StackFu::Commands::GenerateCommand do
|
5
|
+
it "generates the script file and folder when no executables are given" do
|
6
|
+
expect_create :dir => "test", :file => "script.yml"
|
7
|
+
expect_create :dir => "test/executables"
|
8
|
+
expect_create :dir => "test/config", :file => "01-controls.yml"
|
9
|
+
expect_create :dir => "test/config", :file => "02-requirements.yml"
|
10
|
+
expect_create :dir => "test/config", :file => "03-executions.yml"
|
11
|
+
expect_create :dir => "test/config", :file => "04-validations.yml"
|
12
|
+
|
13
|
+
command "generate test"
|
14
|
+
stdout.should =~ /Script test created successfully/
|
15
|
+
end
|
16
|
+
|
17
|
+
it "generates proper tree with one executable passed" do
|
18
|
+
expect_create :dir => "other", :file => "script.yml"
|
19
|
+
expect_create :dir => "other/executables", :file => "install_counter_strike_server.sh.erb"
|
20
|
+
expect_create :dir => "other/config", :file => "01-controls.yml"
|
21
|
+
expect_create :dir => "other/config", :file => "02-requirements.yml"
|
22
|
+
expect_create :dir => "other/config", :file => "03-executions.yml",
|
23
|
+
:contents => [/install_counter_strike_server/, /Install Counter Strike Server/]
|
24
|
+
expect_create :dir => "other/config", :file => "04-validations.yml"
|
25
|
+
|
26
|
+
command "generate other install_counter_strike_server:script"
|
27
|
+
stdout.should =~ /Script other created successfully/
|
28
|
+
end
|
29
|
+
|
30
|
+
it "generates proper tree with scripts and controls" do
|
31
|
+
expect_create :dir => "test", :file => "script.yml"
|
32
|
+
expect_create :dir => "test/executables", :file => "install_counter_strike_server.sh.erb"
|
33
|
+
expect_create :dir => "test/executables", :file => "show_me_the_money.sh.erb"
|
34
|
+
expect_create :dir => "test/config", :file => "01-controls.yml",
|
35
|
+
:contents => [
|
36
|
+
/name: clan_name/, /label: Clan Name/, /type: Textbox/,
|
37
|
+
/name: clan_password/, /label: Clan Password/, /type: Password/
|
38
|
+
]
|
39
|
+
expect_create :dir => "test/config", :file => "02-requirements.yml"
|
40
|
+
expect_create :dir => "test/config", :file => "03-executions.yml",
|
41
|
+
:contents => [
|
42
|
+
/install_counter_strike_server/, /Install Counter Strike Server/,
|
43
|
+
/show_me_the_money/, /Show Me The Money/
|
44
|
+
]
|
45
|
+
expect_create :dir => "test/config", :file => "04-validations.yml"
|
46
|
+
|
47
|
+
command "generate test clan_name:textbox clan_password:password install_counter_strike_server:script show_me_the_money:script"
|
48
|
+
end
|
49
|
+
|
50
|
+
it "raises an error message if one of the params is unknown" do
|
51
|
+
command "generate test abcdef"
|
52
|
+
stdout.should =~ /Don't know how to generate a script with abcdef. Use 'stackfu help generate' for more information./
|
53
|
+
end
|
54
|
+
|
55
|
+
it "raises an error message if one of the params is of invalid type" do
|
56
|
+
command "generate test yogurt:food"
|
57
|
+
stdout.should =~ /Don't know how to generate a script with food yogurt. Use 'stackfu help generate' for more information./
|
58
|
+
end
|
59
|
+
|
60
|
+
it "raises a nice error when mkdir fails" do
|
61
|
+
expect_create :dir => "test", :file => "script.yml", :raise => [IOError, "Error description"]
|
62
|
+
command "generate test"
|
63
|
+
stdout.should =~ /There was an error creating your script: Error description/
|
64
|
+
end
|
65
|
+
|
66
|
+
it "raises a nice error when mkdir fails because there is a file with same name" do
|
67
|
+
expect_create :dir => "test", :file => "script.yml", :raise => [Errno::EEXIST, "Error description"]
|
68
|
+
command "generate test"
|
69
|
+
stdout.should =~ /There was an error creating your script: File exists - Error description/
|
70
|
+
end
|
71
|
+
|
72
|
+
def expect_create(opts={})
|
73
|
+
expect = StackFu::Commands::GenerateCommand.any_instance.expects(:create).with do |dir, file, contents|
|
74
|
+
dir_match = opts[:dir] ? dir == opts[:dir] : true
|
75
|
+
file_match = opts[:file] ? file == opts[:file] : true
|
76
|
+
contents_match = opts[:contents] ?
|
77
|
+
opts[:contents].each do |c|
|
78
|
+
break true if contents =~ c
|
79
|
+
false
|
80
|
+
end : true
|
81
|
+
block_match = block_given? ? yield(dir, file, contents) : true
|
82
|
+
|
83
|
+
its_a_match = dir_match and file_match and contents_match and block_match
|
84
|
+
end
|
85
|
+
|
86
|
+
if opts[:raise]
|
87
|
+
expect.raises(opts[:raise].first, opts[:raise].last)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# Load Spec Helper
|
2
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), '../..', 'spec_helper')
|
3
|
+
|
4
|
+
describe StackFu::Commands::ListCommand do
|
5
|
+
it "tells the user if no scripts were found" do
|
6
|
+
prepare(:get, '/scripts.json', 'scripts/none.json')
|
7
|
+
prepare(:get, '/servers.json', 'servers/none.json')
|
8
|
+
command "list"
|
9
|
+
|
10
|
+
stdout.should =~ /You have nothing to list yet. To generate a new script, use the 'stackfu generate' command/
|
11
|
+
end
|
12
|
+
|
13
|
+
it "lists scripts" do
|
14
|
+
prepare(:get, '/scripts.json', 'scripts/all.json')
|
15
|
+
prepare(:get, '/servers.json', 'servers/none.json')
|
16
|
+
command "list scripts"
|
17
|
+
|
18
|
+
stdout.should =~ /Listing 4 scripts/
|
19
|
+
stdout.should =~ /firewall/
|
20
|
+
stdout.should =~ /mongodb/
|
21
|
+
stdout.should =~ /memcached/
|
22
|
+
stdout.should =~ /mysql/
|
23
|
+
end
|
24
|
+
|
25
|
+
it "lists servers" do
|
26
|
+
prepare(:get, '/scripts.json', 'scripts/none.json')
|
27
|
+
prepare(:get, '/servers.json', 'servers/all.json')
|
28
|
+
command "list servers"
|
29
|
+
|
30
|
+
stdout.should =~ /Listing 2 servers/
|
31
|
+
stdout.should =~ /Webbynode/
|
32
|
+
stdout.should =~ /MyDog/
|
33
|
+
end
|
34
|
+
|
35
|
+
it "lists both" do
|
36
|
+
prepare(:get, '/servers.json', 'servers/all.json')
|
37
|
+
prepare(:get, '/scripts.json', 'scripts/all.json')
|
38
|
+
|
39
|
+
command "list"
|
40
|
+
|
41
|
+
stdout.should =~ /Listing 4 scripts/
|
42
|
+
stdout.should =~ /firewall/
|
43
|
+
stdout.should =~ /mongodb/
|
44
|
+
stdout.should =~ /memcached/
|
45
|
+
stdout.should =~ /mysql/
|
46
|
+
|
47
|
+
stdout.should =~ /Listing 2 servers/
|
48
|
+
stdout.should =~ /Webbynode/
|
49
|
+
stdout.should =~ /MyDog/
|
50
|
+
stdout.should =~ /123.45.678.90/
|
51
|
+
stdout.should =~ /123.45.678.91/
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# Load Spec Helper
|
2
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), '../..', 'spec_helper')
|
3
|
+
|
4
|
+
describe StackFu::Commands::PublishCommand do
|
5
|
+
|
6
|
+
it "checks if script exists before publishing" do
|
7
|
+
prepare(:get, '/scripts/firewall.json', '/scripts/firewall.json')
|
8
|
+
prepare(:delete, '/scripts/firewall.json', '/scripts/delete.json')
|
9
|
+
prepare(:post, '/scripts.json', '/scripts/create.json')
|
10
|
+
|
11
|
+
setup_script(:script_name => 'firewall')
|
12
|
+
|
13
|
+
agree_with("You already have a script named firewall. Do you want to update it?")
|
14
|
+
|
15
|
+
command "pub"
|
16
|
+
stdout.should =~ /Publishing script firewall/
|
17
|
+
stdout.should =~ /Success/
|
18
|
+
end
|
19
|
+
|
20
|
+
def setup_script(options={})
|
21
|
+
StackFu::Commands::PublishCommand.any_instance.expects(:read).with("script.yml").returns(<<-EOS)
|
22
|
+
---
|
23
|
+
type: stack
|
24
|
+
name: #{options[:"script_name"] || "my_script"}
|
25
|
+
description: "This will deploy my script"
|
26
|
+
EOS
|
27
|
+
StackFu::Commands::PublishCommand.any_instance.expects(:read).with("config/01-controls.yml").returns(<<-EOS)
|
28
|
+
controls:
|
29
|
+
- name: nome
|
30
|
+
label: Nome
|
31
|
+
type: Textbox
|
32
|
+
- name: idade
|
33
|
+
label: Idade
|
34
|
+
type: Numericbox
|
35
|
+
EOS
|
36
|
+
StackFu::Commands::PublishCommand.any_instance.expects(:read).with("config/02-requirements.yml").returns(<<-EOS)
|
37
|
+
requirements:
|
38
|
+
|
39
|
+
- type: directory
|
40
|
+
data: "/var"
|
41
|
+
error: "You need /var folder before installing"
|
42
|
+
EOS
|
43
|
+
StackFu::Commands::PublishCommand.any_instance.expects(:read).with("config/03-executions.yml").returns(options[:scripts] || <<-EOS)
|
44
|
+
executions:
|
45
|
+
|
46
|
+
- description: Echoer
|
47
|
+
file: echoer
|
48
|
+
EOS
|
49
|
+
StackFu::Commands::PublishCommand.any_instance.expects(:read).with("config/04-validations.yml").returns(<<-EOS)
|
50
|
+
validations:
|
51
|
+
- type: directory
|
52
|
+
data: "/etc/apache2"
|
53
|
+
error: Apache was not installed properly
|
54
|
+
EOS
|
55
|
+
|
56
|
+
unless options[:scripts]
|
57
|
+
StackFu::Commands::PublishCommand.any_instance.expects(:read).with("executables/echoer.sh.erb").returns(<<-EOS)
|
58
|
+
#
|
59
|
+
# echoe.sh
|
60
|
+
# Echoes a variable
|
61
|
+
#
|
62
|
+
|
63
|
+
echo "<%= nome %> is <%= age %> years old"
|
64
|
+
EOS
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/stackfu.gemspec
CHANGED
@@ -2,17 +2,17 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{stackfu}
|
5
|
-
s.version = "0.1.1"
|
5
|
+
s.version = "0.1.2.1"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Felipe Coury"]
|
9
|
-
s.date = %q{2010-
|
9
|
+
s.date = %q{2010-09-07}
|
10
10
|
s.default_executable = %q{stackfu}
|
11
11
|
s.description = %q{StackFu Backend}
|
12
12
|
s.email = %q{felipe@stackfu.com}
|
13
13
|
s.executables = ["stackfu"]
|
14
|
-
s.extra_rdoc_files = ["CHANGELOG", "README", "README.md", "bin/stackfu", "lib/stackfu.rb", "lib/stackfu/api_hooks.rb", "lib/stackfu/app.rb", "lib/stackfu/commands/command.rb", "lib/stackfu/commands/config_command.rb", "lib/stackfu/commands/deploy_command.rb", "lib/stackfu/commands/dump_command.rb", "lib/stackfu/commands/generate_command.rb", "lib/stackfu/commands/help_command.rb", "lib/stackfu/commands/list_command.rb", "lib/stackfu/commands/publish_command.rb", "lib/stackfu/commands/server_command.rb", "lib/stackfu/helpers/providers_credentials.rb", "lib/stackfu/helpers/rendering.rb", "lib/stackfu/operating_systems.rb"]
|
15
|
-
s.files = ["CHANGELOG", "Manifest", "README", "README.md", "Rakefile", "bin/stackfu", "lib/stackfu.rb", "lib/stackfu/api_hooks.rb", "lib/stackfu/app.rb", "lib/stackfu/commands/command.rb", "lib/stackfu/commands/config_command.rb", "lib/stackfu/commands/deploy_command.rb", "lib/stackfu/commands/dump_command.rb", "lib/stackfu/commands/generate_command.rb", "lib/stackfu/commands/help_command.rb", "lib/stackfu/commands/list_command.rb", "lib/stackfu/commands/publish_command.rb", "lib/stackfu/commands/server_command.rb", "lib/stackfu/helpers/providers_credentials.rb", "lib/stackfu/helpers/rendering.rb", "lib/stackfu/operating_systems.rb", "stackfu-installer/config/01-controls.yml", "stackfu-installer/config/02-requirements.yml", "stackfu-installer/config/03-
|
14
|
+
s.extra_rdoc_files = ["CHANGELOG", "README", "README.md", "bin/stackfu", "lib/stackfu.rb", "lib/stackfu/api_hooks.rb", "lib/stackfu/app.rb", "lib/stackfu/commands/command.rb", "lib/stackfu/commands/config_command.rb", "lib/stackfu/commands/deploy_command.rb", "lib/stackfu/commands/dump_command.rb", "lib/stackfu/commands/generate_command.rb", "lib/stackfu/commands/help_command.rb", "lib/stackfu/commands/list_command.rb", "lib/stackfu/commands/publish_command.rb", "lib/stackfu/commands/server_command.rb", "lib/stackfu/date_helper.rb", "lib/stackfu/helpers/providers_credentials.rb", "lib/stackfu/helpers/rendering.rb", "lib/stackfu/operating_systems.rb"]
|
15
|
+
s.files = ["CHANGELOG", "Gemfile", "Manifest", "README", "README.md", "Rakefile", "autotest/discover.rb", "bin/stackfu", "firewall/config/01-controls.yml", "firewall/config/02-requirements.yml", "firewall/config/03-executions.yml", "firewall/config/03-scripts.yml", "firewall/config/04-validations.yml", "firewall/executables/configure_ufw.sh.erb", "firewall/executables/install_ufw.sh.erb", "firewall/script.yml", "firewall/script/configure_ufw.sh.erb", "firewall/script/install_ufw.sh.erb", "lib/stackfu.rb", "lib/stackfu/api_hooks.rb", "lib/stackfu/app.rb", "lib/stackfu/commands/command.rb", "lib/stackfu/commands/config_command.rb", "lib/stackfu/commands/deploy_command.rb", "lib/stackfu/commands/dump_command.rb", "lib/stackfu/commands/generate_command.rb", "lib/stackfu/commands/help_command.rb", "lib/stackfu/commands/list_command.rb", "lib/stackfu/commands/publish_command.rb", "lib/stackfu/commands/server_command.rb", "lib/stackfu/date_helper.rb", "lib/stackfu/helpers/providers_credentials.rb", "lib/stackfu/helpers/rendering.rb", "lib/stackfu/operating_systems.rb", "spec/fixtures/scripts/all.json", "spec/fixtures/scripts/create.json", "spec/fixtures/scripts/delete.json", "spec/fixtures/scripts/firewall.json", "spec/fixtures/scripts/none.json", "spec/fixtures/scripts/not_found.json", "spec/fixtures/scripts/script_not_found.json", "spec/fixtures/servers/all.json", "spec/fixtures/servers/cannot_deploy.json", "spec/fixtures/servers/deploy.json", "spec/fixtures/servers/none.json", "spec/fixtures/servers/not_found.json", "spec/fixtures/servers/webbynode.json", "spec/fixtures/servers/webbynode/deploy.json", "spec/spec_helper.rb", "spec/stackfu/api_hooks_spec.rb", "spec/stackfu/commands/deploy_command_spec.rb", "spec/stackfu/commands/dump_command_spec.rb", "spec/stackfu/commands/generate_command_spec.rb", "spec/stackfu/commands/list_command_spec.rb", "spec/stackfu/commands/publish_command_spec.rb", "stackfu-installer/config/01-controls.yml", "stackfu-installer/config/02-requirements.yml", "stackfu-installer/config/03-executions.yml", "stackfu-installer/config/04-validations.yml", "stackfu-installer/script/dotfiles_installation.sh.erb", "stackfu-installer/script/github_credentials_setup.sh.erb", "stackfu-installer/script/nginx_and_passenger.sh.erb", "stackfu-installer/script/redis_installation.sh.erb", "stackfu-installer/script/resque_installation.sh.erb", "stackfu-installer/script/ruby_environment.sh.erb", "stackfu-installer/script/stackfu.sh.erb", "stackfu-installer/stack.yml", "templates/01-controls.yml.erb", "templates/02-requirements.yml.erb", "templates/03-executions.yml.erb", "templates/04-validations.yml.erb", "templates/script.sh.erb", "templates/stack.yml.erb", "test/fixtures/add_server_error", "test/fixtures/deployment_add", "test/fixtures/deployment_add_error", "test/fixtures/deployments", "test/fixtures/logs", "test/fixtures/logs_partial", "test/fixtures/plugin_add", "test/fixtures/plugin_add_error", "test/fixtures/plugin_deployment_add", "test/fixtures/plugin_not_found", "test/fixtures/plugin_unauthorized", "test/fixtures/plugins", "test/fixtures/plugins_by_name", "test/fixtures/plugins_by_name_other", "test/fixtures/plugins_empty", "test/fixtures/plugins_multiple", "test/fixtures/providers", "test/fixtures/providers_servers", "test/fixtures/server_add", "test/fixtures/server_add_dupe", "test/fixtures/server_add_error", "test/fixtures/server_delete", "test/fixtures/server_delete_error", "test/fixtures/servers", "test/fixtures/servers_by_name", "test/fixtures/servers_empty", "test/fixtures/servers_not_found", "test/fixtures/servers_unauthorized", "test/fixtures/servers_webbynode", "test/fixtures/stack/stackfu-installer/config/01-controls.yml", "test/fixtures/stack/stackfu-installer/config/02-requirements.yml", "test/fixtures/stack/stackfu-installer/config/03-scripts.yml", "test/fixtures/stack/stackfu-installer/config/04-validations.yml", "test/fixtures/stack/stackfu-installer/script/dotfiles_installation.sh.erb", "test/fixtures/stack/stackfu-installer/script/github_credentials_setup.sh.erb", "test/fixtures/stack/stackfu-installer/script/nginx_and_passenger.sh.erb", "test/fixtures/stack/stackfu-installer/script/redis_installation.sh.erb", "test/fixtures/stack/stackfu-installer/script/resque_installation.sh.erb", "test/fixtures/stack/stackfu-installer/script/ruby_environment.sh.erb", "test/fixtures/stack/stackfu-installer/script/stackfu.sh.erb", "test/fixtures/stack/stackfu-installer/stack.yml", "test/fixtures/stack_add", "test/fixtures/stack_add_error", "test/fixtures/stack_add_error_dupe", "test/fixtures/stack_adds_by_name", "test/fixtures/stack_delete_not_found", "test/fixtures/stacks", "test/fixtures/stacks_by_name", "test/fixtures/stacks_by_name_other", "test/fixtures/stacks_empty", "test/fixtures/stacks_multiple", "test/fixtures/stacks_not_found", "test/fixtures/stacks_realworld", "test/fixtures/stacks_stackfu-installer", "test/fixtures/stacks_unauthorized", "test/fixtures/stacks_with_controls", "test/fixtures/users", "test/fixtures/users_no_credentials", "test/fixtures/users_update", "test/support/custom_matchers.rb", "test/support/fixtures.rb", "test/support/io_stub.rb", "test/support/web_fixtures.rb", "test/test_helper.rb", "test/unit/commands/test_command.rb", "test/unit/commands/test_config_command.rb", "test/unit/commands/test_deploy_command.rb", "test/unit/commands/test_dump_command.rb", "test/unit/commands/test_generate_command.rb", "test/unit/commands/test_help_command.rb", "test/unit/commands/test_list_command.rb", "test/unit/commands/test_publish_command.rb", "test/unit/commands/test_server_command.rb", "test/unit/helpers/test_rendering.rb", "test/unit/test_array.rb", "test/unit/test_provider.rb", "test/unit/test_stackfu.rb", "stackfu.gemspec"]
|
16
16
|
s.homepage = %q{http://stackfu.com/cli}
|
17
17
|
s.post_install_message = %q{
|
18
18
|
--==-- StackFu - Server Deployment Engine --==--
|