sunshine 1.0.0.pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +237 -0
- data/Manifest.txt +70 -0
- data/README.txt +277 -0
- data/Rakefile +46 -0
- data/bin/sunshine +5 -0
- data/examples/deploy.rb +61 -0
- data/examples/deploy_tasks.rake +112 -0
- data/examples/standalone_deploy.rb +31 -0
- data/lib/commands/add.rb +96 -0
- data/lib/commands/default.rb +169 -0
- data/lib/commands/list.rb +322 -0
- data/lib/commands/restart.rb +62 -0
- data/lib/commands/rm.rb +83 -0
- data/lib/commands/run.rb +151 -0
- data/lib/commands/start.rb +72 -0
- data/lib/commands/stop.rb +61 -0
- data/lib/sunshine/app.rb +876 -0
- data/lib/sunshine/binder.rb +70 -0
- data/lib/sunshine/crontab.rb +143 -0
- data/lib/sunshine/daemon.rb +380 -0
- data/lib/sunshine/daemons/ar_sendmail.rb +28 -0
- data/lib/sunshine/daemons/delayed_job.rb +30 -0
- data/lib/sunshine/daemons/nginx.rb +104 -0
- data/lib/sunshine/daemons/rainbows.rb +35 -0
- data/lib/sunshine/daemons/server.rb +66 -0
- data/lib/sunshine/daemons/unicorn.rb +26 -0
- data/lib/sunshine/dependencies.rb +103 -0
- data/lib/sunshine/dependency_lib.rb +200 -0
- data/lib/sunshine/exceptions.rb +54 -0
- data/lib/sunshine/healthcheck.rb +83 -0
- data/lib/sunshine/output.rb +131 -0
- data/lib/sunshine/package_managers/apt.rb +48 -0
- data/lib/sunshine/package_managers/dependency.rb +349 -0
- data/lib/sunshine/package_managers/gem.rb +54 -0
- data/lib/sunshine/package_managers/yum.rb +62 -0
- data/lib/sunshine/remote_shell.rb +241 -0
- data/lib/sunshine/repo.rb +128 -0
- data/lib/sunshine/repos/git_repo.rb +122 -0
- data/lib/sunshine/repos/rsync_repo.rb +29 -0
- data/lib/sunshine/repos/svn_repo.rb +78 -0
- data/lib/sunshine/server_app.rb +554 -0
- data/lib/sunshine/shell.rb +384 -0
- data/lib/sunshine.rb +391 -0
- data/templates/logrotate/logrotate.conf.erb +11 -0
- data/templates/nginx/nginx.conf.erb +109 -0
- data/templates/nginx/nginx_optimize.conf +23 -0
- data/templates/nginx/nginx_proxy.conf +13 -0
- data/templates/rainbows/rainbows.conf.erb +18 -0
- data/templates/tasks/sunshine.rake +114 -0
- data/templates/unicorn/unicorn.conf.erb +6 -0
- data/test/fixtures/app_configs/test_app.yml +11 -0
- data/test/fixtures/sunshine_test/test_upload +0 -0
- data/test/mocks/mock_object.rb +179 -0
- data/test/mocks/mock_open4.rb +117 -0
- data/test/test_helper.rb +188 -0
- data/test/unit/test_app.rb +489 -0
- data/test/unit/test_binder.rb +20 -0
- data/test/unit/test_crontab.rb +128 -0
- data/test/unit/test_git_repo.rb +26 -0
- data/test/unit/test_healthcheck.rb +70 -0
- data/test/unit/test_nginx.rb +107 -0
- data/test/unit/test_rainbows.rb +26 -0
- data/test/unit/test_remote_shell.rb +102 -0
- data/test/unit/test_repo.rb +42 -0
- data/test/unit/test_server.rb +324 -0
- data/test/unit/test_server_app.rb +425 -0
- data/test/unit/test_shell.rb +97 -0
- data/test/unit/test_sunshine.rb +157 -0
- data/test/unit/test_svn_repo.rb +55 -0
- data/test/unit/test_unicorn.rb +22 -0
- metadata +217 -0
@@ -0,0 +1,322 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Sunshine
|
4
|
+
|
5
|
+
##
|
6
|
+
# List and perform simple state actions on lists of sunshine apps.
|
7
|
+
#
|
8
|
+
# Usage: sunshine list app_name [more names...] [options]
|
9
|
+
#
|
10
|
+
# Arguments:
|
11
|
+
# app_name Name of an application to list.
|
12
|
+
#
|
13
|
+
# Options:
|
14
|
+
# -s, --status Check if an app is running.
|
15
|
+
# -d, --details Get details about the deployed apps.
|
16
|
+
# -h, --health [STATUS] Set or get the healthcheck status.
|
17
|
+
# (enable, disable, remove)
|
18
|
+
# -f, --format FORMAT Set the output format (txt, yml, json)
|
19
|
+
# -u, --user USER User to use for remote login. Use with -r
|
20
|
+
# -r, --remote svr1,svr2 Run on one or more remote servers.
|
21
|
+
# -v, --verbose Run in verbose mode.
|
22
|
+
|
23
|
+
class ListCommand < DefaultCommand
|
24
|
+
|
25
|
+
##
|
26
|
+
# Takes an array and a hash, runs the command and returns:
|
27
|
+
# true: success
|
28
|
+
# false: failed
|
29
|
+
# exitcode:
|
30
|
+
# code == 0: success
|
31
|
+
# code != 0: failed
|
32
|
+
# and optionally an accompanying message.
|
33
|
+
|
34
|
+
def self.exec names, config
|
35
|
+
action = config['return'] || :exist?
|
36
|
+
|
37
|
+
args = config[action.to_s] || []
|
38
|
+
args = [args, names].flatten
|
39
|
+
|
40
|
+
output = exec_each_server config do |shell|
|
41
|
+
new(shell).send(action, *args)
|
42
|
+
end
|
43
|
+
|
44
|
+
return output
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
##
|
49
|
+
# Executes common list functionality for each deploy server.
|
50
|
+
|
51
|
+
def self.exec_each_server config
|
52
|
+
shells = config['servers']
|
53
|
+
format = config['format']
|
54
|
+
|
55
|
+
responses = {}
|
56
|
+
success = true
|
57
|
+
|
58
|
+
shells.each do |shell|
|
59
|
+
shell.connect
|
60
|
+
|
61
|
+
begin
|
62
|
+
state, response = yield(shell)
|
63
|
+
rescue => e
|
64
|
+
state = false
|
65
|
+
response = "#{e.class}: #{e.message}\n#{e.backtrace.join("\n")}"
|
66
|
+
end
|
67
|
+
|
68
|
+
host = shell.host
|
69
|
+
success = state if success
|
70
|
+
responses[host] = build_response state, response
|
71
|
+
|
72
|
+
shell.disconnect
|
73
|
+
end
|
74
|
+
|
75
|
+
output = format ? self.send(format, responses) : responses
|
76
|
+
return success, output
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
##
|
81
|
+
# Formats response as text output:
|
82
|
+
# ------------------
|
83
|
+
# subdomain.host.com
|
84
|
+
# ------------------
|
85
|
+
# app_name: running
|
86
|
+
|
87
|
+
def self.txt_format res_hash
|
88
|
+
str_out = ""
|
89
|
+
|
90
|
+
res_hash.each do |host, response|
|
91
|
+
separator = "-" * host.length
|
92
|
+
|
93
|
+
host_status = if Hash === response[:data]
|
94
|
+
apps_status = response[:data].map do |app_name, status|
|
95
|
+
"#{app_name}: #{status[:data]}\n"
|
96
|
+
end
|
97
|
+
apps_status.join("\n")
|
98
|
+
|
99
|
+
else
|
100
|
+
response[:data]
|
101
|
+
end
|
102
|
+
|
103
|
+
str_out << "\n"
|
104
|
+
str_out << [separator, host, separator].join("\n")
|
105
|
+
str_out << "\n"
|
106
|
+
str_out << host_status
|
107
|
+
str_out << "\n"
|
108
|
+
end
|
109
|
+
|
110
|
+
str_out
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
##
|
115
|
+
# Formats response as yaml:
|
116
|
+
|
117
|
+
def self.yml_format res_hash
|
118
|
+
res_hash.to_yaml
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
##
|
123
|
+
# Formats response as json:
|
124
|
+
|
125
|
+
def self.json_format res_hash
|
126
|
+
res_hash.to_json
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
|
131
|
+
attr_accessor :app_list, :shell
|
132
|
+
|
133
|
+
def initialize shell
|
134
|
+
@shell = shell
|
135
|
+
@app_list = self.class.load_list @shell
|
136
|
+
end
|
137
|
+
|
138
|
+
|
139
|
+
##
|
140
|
+
# Reads and returns the specified apps' info file.
|
141
|
+
# Returns a response hash (see ListCommand#each_app).
|
142
|
+
|
143
|
+
def details(*app_names)
|
144
|
+
each_app(*app_names) do |server_app|
|
145
|
+
"\n#{server_app.deploy_details.to_yaml}"
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
##
|
151
|
+
# Returns the path of specified apps.
|
152
|
+
# Returns a response hash (see ListCommand#each_app).
|
153
|
+
|
154
|
+
def exist?(*app_names)
|
155
|
+
each_app(*app_names) do |server_app|
|
156
|
+
server_app.root_path
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
##
|
162
|
+
# Get or set the healthcheck state.
|
163
|
+
# Returns a response hash (see ListCommand#each_app).
|
164
|
+
|
165
|
+
def health(*app_names)
|
166
|
+
action = app_names.delete_at(0) if Symbol === app_names.first
|
167
|
+
|
168
|
+
each_app(*app_names) do |server_app|
|
169
|
+
server_app.health.send action if action
|
170
|
+
server_app.health.status
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
|
175
|
+
##
|
176
|
+
# Checks if the apps' pids are present.
|
177
|
+
# Returns a response hash (see ListCommand#each_app).
|
178
|
+
|
179
|
+
def status(*app_names)
|
180
|
+
each_app(*app_names) do |server_app|
|
181
|
+
server_app.status
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
|
186
|
+
##
|
187
|
+
# Runs a command and returns the status for each app_name:
|
188
|
+
# status_after_command 'restart', ['app1', 'app2']
|
189
|
+
|
190
|
+
def status_after_command cmd, app_names
|
191
|
+
each_app(*app_names) do |server_app|
|
192
|
+
|
193
|
+
yield(server_app) if block_given?
|
194
|
+
|
195
|
+
begin
|
196
|
+
server_app.send cmd.to_sym
|
197
|
+
server_app.running? ? 'running' : 'down'
|
198
|
+
|
199
|
+
rescue CmdError => e
|
200
|
+
raise "Failed running #{cmd}: #{server_app.status}"
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
|
206
|
+
# Do something with each server app and build a response hash:
|
207
|
+
# each_app do |server_app|
|
208
|
+
# ...
|
209
|
+
# end
|
210
|
+
#
|
211
|
+
# Restrict it to a set of apps if they are present on the server:
|
212
|
+
# each_app('app1', 'app2') do |server_app|
|
213
|
+
# ...
|
214
|
+
# end
|
215
|
+
#
|
216
|
+
# Returns a response hash:
|
217
|
+
# {"app_name" => {:success => true, :data => "somedata"} ...}
|
218
|
+
|
219
|
+
def each_app(*app_names)
|
220
|
+
app_names = @app_list.keys if app_names.empty?
|
221
|
+
|
222
|
+
response_for_each(*app_names) do |name|
|
223
|
+
path = @app_list[name]
|
224
|
+
|
225
|
+
raise "Application not found." unless path
|
226
|
+
|
227
|
+
server_app = ServerApp.new name, @shell, :root_path => path
|
228
|
+
|
229
|
+
yield(server_app) if block_given?
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
|
234
|
+
##
|
235
|
+
# Builds a response object for each item passed and returns
|
236
|
+
# the result of the passed block as its data value.
|
237
|
+
|
238
|
+
def response_for_each(*items)
|
239
|
+
response = {}
|
240
|
+
success = true
|
241
|
+
|
242
|
+
items.each do |item|
|
243
|
+
|
244
|
+
begin
|
245
|
+
data = yield(item) if block_given?
|
246
|
+
|
247
|
+
response[item] = self.class.build_response true, data
|
248
|
+
|
249
|
+
rescue => e
|
250
|
+
success = false
|
251
|
+
response[item] = self.class.build_response false, e.message
|
252
|
+
end
|
253
|
+
|
254
|
+
end
|
255
|
+
|
256
|
+
[success, response]
|
257
|
+
end
|
258
|
+
|
259
|
+
|
260
|
+
##
|
261
|
+
# Builds a standard response entry:
|
262
|
+
# {:success => true, :data => "somedata"}
|
263
|
+
|
264
|
+
def self.build_response success, data=nil
|
265
|
+
{:success => success, :data => data}
|
266
|
+
end
|
267
|
+
|
268
|
+
|
269
|
+
##
|
270
|
+
# Load the app list yaml file from the server.
|
271
|
+
|
272
|
+
def self.load_list server
|
273
|
+
list = YAML.load(server.call(Sunshine::READ_LIST_CMD))
|
274
|
+
list = {} unless Hash === list
|
275
|
+
list
|
276
|
+
end
|
277
|
+
|
278
|
+
|
279
|
+
##
|
280
|
+
# Write the app list hash to the remote server.
|
281
|
+
|
282
|
+
def self.save_list list, server
|
283
|
+
path = server.expand_path Sunshine::APP_LIST_PATH
|
284
|
+
server.make_file path, list.to_yaml
|
285
|
+
end
|
286
|
+
|
287
|
+
|
288
|
+
##
|
289
|
+
# Parses the argv passed to the command
|
290
|
+
|
291
|
+
def self.parse_args argv
|
292
|
+
parse_remote_args(argv) do |opt, options|
|
293
|
+
opt.banner = <<-EOF
|
294
|
+
|
295
|
+
Usage: #{opt.program_name} list app_name [more names...] [options]
|
296
|
+
|
297
|
+
Arguments:
|
298
|
+
app_name Name of an application to list.
|
299
|
+
EOF
|
300
|
+
|
301
|
+
opt.on('-s', '--status',
|
302
|
+
'Check if an app is running.') do
|
303
|
+
options['return'] = :status
|
304
|
+
end
|
305
|
+
|
306
|
+
opt.on('-d', '--details',
|
307
|
+
'Get details about the deployed apps.') do
|
308
|
+
options['return'] = :details
|
309
|
+
end
|
310
|
+
|
311
|
+
|
312
|
+
vals = [:enable, :disable, :remove]
|
313
|
+
desc = "Set or get the healthcheck status. (#{vals.join(", ")})"
|
314
|
+
|
315
|
+
opt.on('-h', '--health [STATUS]', vals, desc) do |status|
|
316
|
+
options['health'] = status.to_sym if status
|
317
|
+
options['return'] = :health
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Sunshine
|
2
|
+
|
3
|
+
##
|
4
|
+
# Runs the restart script of all specified sunshine apps.
|
5
|
+
#
|
6
|
+
# Usage: sunshine restart app_name [more names...] [options]
|
7
|
+
#
|
8
|
+
# Arguments:
|
9
|
+
# app_name Name of the application to restart.
|
10
|
+
#
|
11
|
+
# Options:
|
12
|
+
# -f, --format FORMAT Set the output format (txt, yml, json)
|
13
|
+
# -u, --user USER User to use for remote login. Use with -r.
|
14
|
+
# -r, --remote svr1,svr2 Run on one or more remote servers.
|
15
|
+
# -v, --verbose Run in verbose mode.
|
16
|
+
|
17
|
+
class RestartCommand < ListCommand
|
18
|
+
|
19
|
+
##
|
20
|
+
# Takes an array and a hash, runs the command and returns:
|
21
|
+
# true: success
|
22
|
+
# false: failed
|
23
|
+
# exitcode:
|
24
|
+
# code == 0: success
|
25
|
+
# code != 0: failed
|
26
|
+
# and optionally an accompanying message.
|
27
|
+
|
28
|
+
def self.exec names, config
|
29
|
+
output = exec_each_server config do |shell|
|
30
|
+
new(shell).restart(names)
|
31
|
+
end
|
32
|
+
|
33
|
+
return output
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
##
|
38
|
+
# Restart specified apps.
|
39
|
+
|
40
|
+
def restart app_names
|
41
|
+
status_after_command :restart, app_names
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
##
|
46
|
+
# Parses the argv passed to the command
|
47
|
+
|
48
|
+
def self.parse_args argv
|
49
|
+
parse_remote_args(argv) do |opt, options|
|
50
|
+
opt.banner = <<-EOF
|
51
|
+
|
52
|
+
Usage: #{opt.program_name} restart app_name [more names...] [options]
|
53
|
+
|
54
|
+
Arguments:
|
55
|
+
app_name Name of the application to restart.
|
56
|
+
EOF
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
data/lib/commands/rm.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
module Sunshine
|
2
|
+
|
3
|
+
##
|
4
|
+
# Unregister a sunshine app.
|
5
|
+
#
|
6
|
+
# Usage: sunshine rm app_name [more names...] [options]
|
7
|
+
#
|
8
|
+
# Arguments:
|
9
|
+
# app_name Name of the application to remove.
|
10
|
+
#
|
11
|
+
# Options:
|
12
|
+
# -d, --delete Delete the app directory.
|
13
|
+
# -f, --format FORMAT Set the output format (txt, yml, json)
|
14
|
+
# -u, --user USER User to use for remote login. Use with -r.
|
15
|
+
# -r, --remote svr1,svr2 Run on one or more remote servers.
|
16
|
+
# -v, --verbose Run in verbose mode.
|
17
|
+
|
18
|
+
class RmCommand < ListCommand
|
19
|
+
|
20
|
+
##
|
21
|
+
# Takes an array and a hash, runs the command and returns:
|
22
|
+
# true: success
|
23
|
+
# false: failed
|
24
|
+
# exitcode:
|
25
|
+
# code == 0: success
|
26
|
+
# code != 0: failed
|
27
|
+
# and optionally an accompanying message.
|
28
|
+
|
29
|
+
|
30
|
+
def self.exec names, config
|
31
|
+
delete_dir = config['delete_dir']
|
32
|
+
|
33
|
+
output = exec_each_server config do |shell|
|
34
|
+
server_command = new(shell)
|
35
|
+
results = server_command.remove(names, delete_dir)
|
36
|
+
|
37
|
+
self.save_list server_command.app_list, shell
|
38
|
+
|
39
|
+
results
|
40
|
+
end
|
41
|
+
|
42
|
+
return output
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
##
|
47
|
+
# Remove a registered app on a given deploy server
|
48
|
+
|
49
|
+
def remove app_names, delete_dir=false
|
50
|
+
each_app(*app_names) do |server_app|
|
51
|
+
if delete_dir
|
52
|
+
server_app.stop rescue nil
|
53
|
+
server_app.shell.call "rm -rf #{server_app.root_path}"
|
54
|
+
|
55
|
+
server_app.crontab.delete!
|
56
|
+
end
|
57
|
+
|
58
|
+
@app_list.delete server_app.name
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
##
|
64
|
+
# Parses the argv passed to the command
|
65
|
+
|
66
|
+
def self.parse_args argv
|
67
|
+
parse_remote_args(argv) do |opt, options|
|
68
|
+
opt.banner = <<-EOF
|
69
|
+
|
70
|
+
Usage: #{opt.program_name} rm app_name [more names...] [options]
|
71
|
+
|
72
|
+
Arguments:
|
73
|
+
app_name Name of the application to remove.
|
74
|
+
EOF
|
75
|
+
|
76
|
+
opt.on('-d', '--delete',
|
77
|
+
'Delete the app directory.') do
|
78
|
+
options['delete_dir'] = true
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/commands/run.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
module Sunshine
|
2
|
+
|
3
|
+
##
|
4
|
+
# Run one or more sunshine scripts.
|
5
|
+
#
|
6
|
+
# Usage: sunshine run [run_file] [options]
|
7
|
+
#
|
8
|
+
# Arguments:
|
9
|
+
# run_file Load a script or app path. Defaults to ./Sunshine
|
10
|
+
#
|
11
|
+
# Options:
|
12
|
+
# -l, --level LEVEL Set trace level. Defaults to info.
|
13
|
+
# -e, --env DEPLOY_ENV Sets the deploy env. Defaults to development.
|
14
|
+
# -a, --auto Non-interactive - automate or fail.
|
15
|
+
# --no-trace Don't trace any output.
|
16
|
+
|
17
|
+
class RunCommand < DefaultCommand
|
18
|
+
|
19
|
+
##
|
20
|
+
# Takes an array and a hash, runs the command and returns:
|
21
|
+
# true: success
|
22
|
+
# false: failed
|
23
|
+
# exitcode:
|
24
|
+
# code == 0: success
|
25
|
+
# code != 0: failed
|
26
|
+
# and optionally an accompanying message.
|
27
|
+
|
28
|
+
def self.exec run_files, config
|
29
|
+
|
30
|
+
run_files.each do |run_file|
|
31
|
+
|
32
|
+
run_file = run_file_from run_file
|
33
|
+
|
34
|
+
with_load_path File.dirname(run_file) do
|
35
|
+
|
36
|
+
puts "Running #{run_file}"
|
37
|
+
|
38
|
+
get_file_data run_file
|
39
|
+
|
40
|
+
require run_file
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
return true
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
##
|
49
|
+
# Tries to infer what run file to used based on a given path:
|
50
|
+
# run_file_from "path/to/some/dir"
|
51
|
+
# #=> "path/to/some/dir/Sunshine"
|
52
|
+
# run_file_from nil
|
53
|
+
# #=> "Sunshine"
|
54
|
+
# run_file_from "path/to/run_script.rb"
|
55
|
+
# #=> "path/to/run_script.rb"
|
56
|
+
|
57
|
+
def self.run_file_from run_file
|
58
|
+
run_file = File.join(run_file, "Sunshine") if
|
59
|
+
run_file && File.directory?(run_file)
|
60
|
+
|
61
|
+
run_file ||= "Sunshine"
|
62
|
+
|
63
|
+
File.expand_path run_file
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
##
|
68
|
+
# Adds a directory to the ruby load path and runs the passed block.
|
69
|
+
# Useful for scripts to be able to reference their own dirs.
|
70
|
+
|
71
|
+
def self.with_load_path path
|
72
|
+
path = File.expand_path path
|
73
|
+
|
74
|
+
# TODO: Find a better way to make file path accessible to App objects.
|
75
|
+
Sunshine.send :remove_const, "PATH" if defined?(Sunshine::PATH)
|
76
|
+
Sunshine.const_set "PATH", path
|
77
|
+
|
78
|
+
added = unless $:.include? path
|
79
|
+
$: << path && true
|
80
|
+
end
|
81
|
+
|
82
|
+
yield
|
83
|
+
|
84
|
+
Sunshine.send :remove_const, "PATH"
|
85
|
+
|
86
|
+
$:.delete path if added
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
##
|
91
|
+
# Returns file data in a run file as a File IO object.
|
92
|
+
|
93
|
+
def self.get_file_data run_file
|
94
|
+
# TODO: Find a better way to make file data accessible to App objects.
|
95
|
+
Sunshine.send :remove_const, "DATA" if defined?(Sunshine::DATA)
|
96
|
+
data_marker = "__END__\n"
|
97
|
+
line = nil
|
98
|
+
|
99
|
+
Sunshine.const_set("DATA", File.open(run_file, 'r'))
|
100
|
+
|
101
|
+
until line == data_marker || Sunshine::DATA.eof?
|
102
|
+
line = Sunshine::DATA.gets
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
##
|
108
|
+
# Parses the argv passed to the command
|
109
|
+
|
110
|
+
def self.parse_args argv
|
111
|
+
options = {'trace' => true}
|
112
|
+
|
113
|
+
opts = opt_parser(options) do |opt|
|
114
|
+
opt.banner = <<-EOF
|
115
|
+
|
116
|
+
Usage: #{opt.program_name} run [run_file] [options]
|
117
|
+
|
118
|
+
Arguments:
|
119
|
+
run_file Load a script or app path. Defaults to ./Sunshine
|
120
|
+
EOF
|
121
|
+
|
122
|
+
opt.separator nil
|
123
|
+
opt.separator "Options:"
|
124
|
+
|
125
|
+
opt.on('-l', '--level LEVEL',
|
126
|
+
'Set trace level. Defaults to info.') do |value|
|
127
|
+
options['level'] = value
|
128
|
+
end
|
129
|
+
|
130
|
+
opt.on('-e', '--env DEPLOY_ENV',
|
131
|
+
'Sets the deploy env. Defaults to development.') do |value|
|
132
|
+
options['deploy_env'] = value
|
133
|
+
end
|
134
|
+
|
135
|
+
opt.on('-a', '--auto',
|
136
|
+
'Non-interactive - automate or fail.') do
|
137
|
+
options['auto'] = true
|
138
|
+
end
|
139
|
+
|
140
|
+
opt.on('--no-trace',
|
141
|
+
"Don't trace any output.") do
|
142
|
+
options['trace'] = false
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
opts.parse! argv
|
147
|
+
|
148
|
+
options
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Sunshine
|
2
|
+
|
3
|
+
##
|
4
|
+
# Runs the start script of all specified sunshine apps.
|
5
|
+
#
|
6
|
+
# Usage: sunshine start app_name [more names...] [options]
|
7
|
+
#
|
8
|
+
# Arguments:
|
9
|
+
# app_name Name of the application to start.
|
10
|
+
#
|
11
|
+
# Options:
|
12
|
+
# -F, --force Stop apps that are running, then start them.
|
13
|
+
# -f, --format FORMAT Set the output format (txt, yml, json)
|
14
|
+
# -u, --user USER User to use for remote login. Use with -r.
|
15
|
+
# -r, --remote svr1,svr2 Run on one or more remote servers.
|
16
|
+
# -v, --verbose Run in verbose mode.
|
17
|
+
|
18
|
+
class StartCommand < ListCommand
|
19
|
+
|
20
|
+
##
|
21
|
+
# Takes an array and a hash, runs the command and returns:
|
22
|
+
# true: success
|
23
|
+
# false: failed
|
24
|
+
# exitcode:
|
25
|
+
# code == 0: success
|
26
|
+
# code != 0: failed
|
27
|
+
# and optionally an accompanying message.
|
28
|
+
|
29
|
+
def self.exec names, config
|
30
|
+
force = config['force']
|
31
|
+
|
32
|
+
output = exec_each_server config do |shell|
|
33
|
+
new(shell).start(names, force)
|
34
|
+
end
|
35
|
+
|
36
|
+
return output
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
##
|
41
|
+
# Start specified apps.
|
42
|
+
|
43
|
+
def start app_names, force=false
|
44
|
+
status_after_command :start, app_names do |server_app|
|
45
|
+
|
46
|
+
server_app.stop if server_app.running? && force
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
##
|
52
|
+
# Parses the argv passed to the command
|
53
|
+
|
54
|
+
def self.parse_args argv
|
55
|
+
parse_remote_args(argv) do |opt, options|
|
56
|
+
opt.banner = <<-EOF
|
57
|
+
|
58
|
+
Usage: #{opt.program_name} start app_name [more names...] [options]
|
59
|
+
|
60
|
+
Arguments:
|
61
|
+
app_name Name of the application to start.
|
62
|
+
EOF
|
63
|
+
|
64
|
+
opt.on('-F', '--force',
|
65
|
+
'Stop apps that are running before starting them again.') do
|
66
|
+
options['force'] = true
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|