dolphin 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bd0208f9074f8be9502f8e03836774c861c49943
4
+ data.tar.gz: 1aad911df6b5328bab43b6857affc253fbd30298
5
+ SHA512:
6
+ metadata.gz: 9559dddc9db2798166616886a03539314f95b129937e62ad3b625bac89abc24c1884adfdab208dc5cffb3fd5319363e9d0a42967efe89f2e3dc48ea84edefdc2
7
+ data.tar.gz: 468e2df8516c91badb5ceccb9fe504d49087ab7906905381c13f9529c265f8d5594af0f170903022c00950f284d4fb006593443741633f69ed894726afdf8d81
@@ -0,0 +1,23 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+
7
+ # ctags file
8
+ tags
9
+ .tags
10
+ .tags_sorted_by_file
11
+
12
+ Gemfile.lock
13
+ InstalledFiles
14
+ _yardoc
15
+ coverage
16
+ doc/
17
+ lib/bundler/man
18
+ pkg
19
+ rdoc
20
+ spec/reports
21
+ test/tmp
22
+ test/version_tmp
23
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dolphin.gemspec
4
+ gemspec
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2013 Neng Xu
2
+
3
+
4
+ MIT License
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining
7
+ a copy of this software and associated documentation files (the
8
+ "Software"), to deal in the Software without restriction, including
9
+ without limitation the rights to use, copy, modify, merge, publish,
10
+ distribute, sublicense, and/or sell copies of the Software, and to
11
+ permit persons to whom the Software is furnished to do so, subject to
12
+ the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ # Dolphin
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'dolphin'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install dolphin
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'dolphin/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "dolphin"
8
+ spec.version = Dolphin::VERSION
9
+ spec.authors = ["Neng Xu\n"]
10
+ spec.email = ["neng2.xu2@gmail.com"]
11
+ spec.description = %q{Dolphin: deploy smartly}
12
+ spec.summary = %q{Dolphin: deploy smartly}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "thor"
22
+ spec.add_dependency "net-ssh"
23
+ spec.add_dependency "parallel"
24
+ spec.add_development_dependency "bundler", "~> 1.3"
25
+ spec.add_development_dependency "rake"
26
+ end
@@ -0,0 +1,517 @@
1
+ require "thor"
2
+ require 'net/ssh'
3
+ require 'parallel'
4
+
5
+ require_relative "dolphin/version"
6
+
7
+ module Dolphin
8
+ # core functions
9
+ class Base < Thor
10
+ include Thor::Actions
11
+
12
+ # =============================================================================
13
+ # class options
14
+ # =============================================================================
15
+
16
+ class_option :env, :aliases => '-e', :type => :string, :default => 'alpha'
17
+
18
+ def initialize(args=[], options={}, config={})
19
+ super(args, options, config)
20
+ # set up environment
21
+ env
22
+ end
23
+
24
+ # =============================================================================
25
+ # private functions
26
+ # =============================================================================
27
+
28
+ private
29
+
30
+ # deployment environment
31
+ def env
32
+ # placeholder, to be implemented in each project
33
+
34
+ end
35
+
36
+ def parse_commands(menu, join=false)
37
+ # Helper method to parse a list of text menu of possible commands,
38
+ # which may contain empty lines or commented out with #
39
+ # commands from one menu item will be joined into one command
40
+
41
+ commands = []
42
+ menu.each do |item|
43
+ buffer = []
44
+ item.split(/\r?\n/).each do |line|
45
+ line = line.strip
46
+ unless line.empty? or line.start_with?('#') # empty or commented out
47
+ buffer << line
48
+ end
49
+ end
50
+ if join
51
+ commands << buffer.join('; ')
52
+ else
53
+ commands.push(*buffer)
54
+ end
55
+ end
56
+ commands
57
+ end
58
+
59
+ def ssh_connection(server)
60
+ @sessions[server] ||= begin
61
+ ssh = Net::SSH.start(server, @user, )
62
+ at_exit { ssh.close }
63
+ ssh
64
+ end
65
+ end
66
+
67
+ def ssh_exec(command, &block)
68
+ status = nil
69
+ output = ''
70
+
71
+ channel = ssh_connection.open_channel do |chan|
72
+ chan.exec(command) do |ch, success|
73
+ puts "#{'!'*10} command failed: #{command}" unless success
74
+ # ch.request_pty
75
+
76
+ ch.on_data do |c, data|
77
+ output << data
78
+ yield(c, :stdout, data)
79
+ end
80
+
81
+ ch.on_extended_data do |c, type, data|
82
+ output << data
83
+ yield(c, :stderr, data)
84
+ end
85
+
86
+ ch.on_request "exit-status" do |c, data|
87
+ status = data.read_long
88
+ end
89
+ end
90
+ end
91
+
92
+ channel.wait
93
+ [status, output]
94
+ end
95
+
96
+ def execute(menu)
97
+ # execute commands defined in menu
98
+ commands = parse_commands(menu, true)
99
+
100
+ puts "Executing on [#{@host}]"
101
+ commands.each do |command|
102
+ puts "\n#{'='*60}\n#{command}\n...... =>\n\n"
103
+
104
+ status, output = ssh_exec command do |ch, stream, data|
105
+ case stream
106
+ when :stdout then $stdout.print data
107
+ when :stderr then $stderr.print data
108
+ end
109
+ ch.send_data(askpass) if data =~ /^sudo password: /
110
+ end
111
+ end
112
+ end
113
+
114
+ def run(menu)
115
+ # execute commands defined in menu
116
+ commands = parse_commands(menu)
117
+ puts "#{'*'*10}Executing commands#{'*'*10}\n"
118
+ commands.each do |command|
119
+ puts "#{command}\n"
120
+ end
121
+ puts "#{'='*60}\n"
122
+
123
+ # use Parallel to run commands on multiple servers in parallel
124
+ tracks = @servers.size
125
+ # 3 threads maximum
126
+ tracks = 3 if tracks > 3
127
+ # record output to display at the end
128
+ output = {}
129
+
130
+ Parallel.map(@servers, in_threads: 3) do |server|
131
+ session = ssh_connection(server)
132
+ output[server] = [] # output from this server
133
+
134
+ channel = session.open_channel do |chan|
135
+ chan.send_channel_request "shell" do |ch, success|
136
+ # chan.request_pty do |ch, success|
137
+ raise "could not start user shell" unless success
138
+
139
+ # normal output
140
+ ch.on_data do |c, data|
141
+ msg = "[output]: #{data}"
142
+ puts "#{server} => #{msg}"
143
+ output[server] << msg
144
+ end
145
+
146
+ # error message
147
+ ch.on_extended_data do |c, type, data|
148
+ msg = "[error]: #{data}"
149
+ puts "#{server} => #{msg}"
150
+ output[server] << msg
151
+ end
152
+
153
+ # exit code
154
+ ch.on_request "exit-status" do |c, data|
155
+ msg = "[exit]: #{data.read_long}\n"
156
+ puts "#{server} => #{msg}"
157
+ output[server] << msg
158
+ end
159
+
160
+ # has to explicitly call shell startup script
161
+ ch.send_data "source ~/.bash_profile\n"
162
+
163
+ # pick up ruby
164
+ ch.send_data "chruby #{@ruby_version}\n"
165
+
166
+ # Output each command as if they were entered on the command line
167
+ commands.each do |command|
168
+ ch.send_data "#{command}\n"
169
+ end
170
+
171
+ # Remember to exit or we'll hang!
172
+ ch.send_data "exit\n"
173
+
174
+ end
175
+ end
176
+
177
+ # Wait for everything to complete
178
+ channel.wait
179
+ end
180
+
181
+ # puts output
182
+ puts "\n#{'*'*10}Results Review#{'*'*10}\n"
183
+ output.each do |server, data|
184
+ puts "\n#{'='*60}\n"
185
+ puts "Executing on [#{server}] =>\n"
186
+ data.each {|line| puts line}
187
+ end
188
+ puts "\n\n"
189
+ end
190
+
191
+ end
192
+
193
+ # =============================================================================
194
+ # Setup
195
+ # =============================================================================
196
+ class Setup < Base
197
+ desc "chruby", "install chruby"
198
+ def chruby
199
+ menu = [
200
+ "
201
+ # install chruby
202
+ wget -O chruby-0.3.5.tar.gz https://github.com/postmodern/chruby/archive/v0.3.5.tar.gz
203
+ tar -xzvf chruby-0.3.5.tar.gz
204
+ cd chruby-0.3.5/
205
+ sudo make install
206
+ ",
207
+ ]
208
+
209
+ execute menu
210
+ end
211
+
212
+ desc "repo", "repository set up."
213
+ def repo
214
+ menu = [
215
+ "
216
+ # init git repository
217
+ cd #{@app_dir}
218
+ git clone #{@github}
219
+ ",
220
+ "
221
+ # set up tracking branch
222
+ cd #{@deploy_dir}
223
+ git checkout -b #{@branch} origin/#{@branch}
224
+ ",
225
+ ]
226
+
227
+ execute menu
228
+ end
229
+
230
+ desc "ruby", "install ruby, arg: version"
231
+ def ruby(version="2.0.0-p195")
232
+ menu = [
233
+ "
234
+ # update ruby-build
235
+ cd ruby-build
236
+ git pull
237
+ sudo ./install.sh
238
+ ",
239
+ "
240
+ # install ruby
241
+ sudo ruby-build #{version} /opt/rubies/ruby-#{version}
242
+ ",
243
+ ]
244
+
245
+ execute menu
246
+ end
247
+
248
+ desc "select", "select ruby, arg: version"
249
+ def select(version="2.0.0-p195")
250
+ menu = [
251
+ "
252
+ # select ruby
253
+ cd #{@app_dir}
254
+ echo ruby-#{version} > .ruby-version
255
+ ",
256
+ ]
257
+
258
+ execute menu
259
+ end
260
+
261
+ desc "bundler", "install bundler"
262
+ def bundler
263
+ menu = [
264
+ "
265
+ # install bundler
266
+ sudo gem install bundler
267
+ ",
268
+ ]
269
+
270
+ run menu
271
+ end
272
+
273
+ desc "rvm", "remove rvm"
274
+ def rvm
275
+ menu = [
276
+ "
277
+ sudo yum -y remove move-rvm
278
+ sudo rm -rf /usr/local/rvm
279
+ ",
280
+ ]
281
+
282
+ run menu
283
+ end
284
+
285
+ desc "apache", "remove apache"
286
+ def apache
287
+ menu = [
288
+ "
289
+ sudo chkconfig httpd.newhomesapi off
290
+ sudo chkconfig httpd.newhomesrdc off
291
+ sudo yum -y remove httpd
292
+ ",
293
+ ]
294
+
295
+ run menu
296
+ end
297
+
298
+ desc "git", "install latest git"
299
+ def git
300
+ menu = [
301
+ "
302
+ # install rpmforge
303
+ wget http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm
304
+ wget http://apt.sw.be/RPM-GPG-KEY.dag.txt
305
+ sudo rpm --import RPM-GPG-KEY.dag.txt
306
+ sudo rpm -K rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm
307
+ sudo rpm -ivh rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm
308
+ sudo cp ~/rpmforge.repo /etc/yum.repos.d/
309
+
310
+ # list repos
311
+ # yum repolist
312
+
313
+ # install git
314
+ sudo yum -y remove git
315
+ sudo yum clean all
316
+ sudo yum -y update
317
+ sudo yum -y install git
318
+ ",
319
+ ]
320
+
321
+ run menu
322
+ end
323
+
324
+ end
325
+
326
+ # =============================================================================
327
+ # Nginx
328
+ # =============================================================================
329
+ class Nginx < Base
330
+ desc "install", "install nginx"
331
+ def install
332
+ menu = [
333
+ "
334
+ # set repo
335
+ sudo cp ~/nginx.repo /etc/yum.repos.d/
336
+
337
+ # list repos
338
+ # yum repolist
339
+
340
+ # install nginx
341
+ sudo yum -y install nginx
342
+ ",
343
+ ]
344
+
345
+ run menu
346
+ end
347
+
348
+ desc "conf", "config nginx"
349
+ def conf
350
+ menu = [
351
+ "
352
+ sudo ln -sf #{@deploy_dir}/config/nginx/#{@application}.conf /etc/nginx/conf.d/#{@application}.conf
353
+ ",
354
+ ]
355
+
356
+ run menu
357
+ end
358
+
359
+ desc "start", "start nginx"
360
+ def start
361
+ menu = [
362
+ "
363
+ # common settings
364
+ sudo service nginx start
365
+ ",
366
+ ]
367
+
368
+ run menu
369
+ end
370
+
371
+ desc "stop", "stop nginx"
372
+ def stop
373
+ menu = [
374
+ "
375
+ # common settings
376
+ sudo service nginx stop
377
+ ",
378
+ ]
379
+
380
+ run menu
381
+ end
382
+
383
+ desc "restart", "restart nginx"
384
+ def restart
385
+ menu = [
386
+ "
387
+ # common settings
388
+ sudo service nginx restart
389
+ ",
390
+ ]
391
+
392
+ run menu
393
+ end
394
+
395
+ end
396
+
397
+ # =============================================================================
398
+ # Deploy
399
+ # =============================================================================
400
+ class Deploy < Base
401
+ desc "bundle", "sudo bundle install"
402
+ def bundle
403
+ menu = [
404
+ "
405
+ cd #{@deploy_dir}
406
+ sudo bundle install --quiet
407
+ ",
408
+ ]
409
+
410
+ run menu
411
+ end
412
+
413
+ desc "go", "normal deploy procedure"
414
+ def go
415
+ # update code
416
+ invoke "dolphin:git:update"
417
+
418
+ # no need to invoke since it is within the same class
419
+ bundle
420
+
421
+ # restart app server
422
+ invoke "dolphin:puma:restart"
423
+ end
424
+
425
+ desc "try", "normal deploy procedure"
426
+ def try
427
+ menu = [
428
+ "
429
+ cd #{@deploy_dir}
430
+ pwd
431
+ bundle check
432
+ ",
433
+ ]
434
+
435
+ run menu
436
+ end
437
+
438
+ end
439
+
440
+ # =============================================================================
441
+ # Git
442
+ # =============================================================================
443
+ class Git < Base
444
+ desc "update", "Update code from github and keep local changes"
445
+ def update
446
+ menu = [
447
+ "
448
+ cd #{@deploy_dir}
449
+ git fetch
450
+ git stash
451
+ git checkout #{@branch}
452
+ git rebase origin/#{@branch}
453
+ git stash apply
454
+ git stash clear
455
+ ",
456
+ ]
457
+
458
+ run menu
459
+ end
460
+
461
+ end
462
+
463
+ # =============================================================================
464
+ # Puma
465
+ # =============================================================================
466
+ class Puma < Base
467
+ desc "start", "start puma"
468
+ def start
469
+ menu = [
470
+ "
471
+ cd #{@deploy_dir}
472
+ RAILS_ENV=#{@env} bundle exec puma -t 8:32 -e #{@env} -d -b unix://#{@sockets}/#{@application}.sock -S #{@pids}/#{@application}.state --control unix://#{@sockets}/pumactl.sock --pidfile #{@pids}/#{@application}.pid
473
+ ",
474
+ ]
475
+
476
+ run menu
477
+ end
478
+
479
+ desc "stop", "stop puma"
480
+ def stop
481
+ menu = [
482
+ "
483
+ cd #{@deploy_dir}
484
+ RAILS_ENV=#{@env} bundle exec pumactl -S #{@pids}/#{@application}.state stop
485
+ ",
486
+ ]
487
+
488
+ run menu
489
+ end
490
+
491
+ desc "restart", "restart puma"
492
+ def restart
493
+ menu = [
494
+ "
495
+ cd #{@deploy_dir}
496
+ # RAILS_ENV=#{@env} bundle exec pumactl -S #{@pids}/#{@application}.state restart
497
+ kill -s SIGUSR2 `cat #{@pids}/#{@application}.pid`
498
+ ",
499
+ ]
500
+
501
+ run menu
502
+ end
503
+
504
+ end
505
+
506
+ # =============================================================================
507
+ # CLI
508
+ # =============================================================================
509
+ class CLI < Thor
510
+ register(Setup, 'setup', 'setup', 'set up target server')
511
+ register(Deploy, 'deploy', 'deploy', 'deploy to target server')
512
+ register(Puma, 'puma', 'puma', 'Puma related commands')
513
+ register(Nginx, 'nginx', 'nginx', 'Nginx related commands')
514
+ register(Git, 'git', 'git', 'Git related commands')
515
+ end
516
+
517
+ end
@@ -0,0 +1,3 @@
1
+ module Dolphin
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dolphin
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - |
8
+ Neng Xu
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-06-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: thor
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '>='
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '>='
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: net-ssh
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: parallel
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: bundler
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: '1.3'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '1.3'
70
+ - !ruby/object:Gem::Dependency
71
+ name: rake
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ description: 'Dolphin: deploy smartly'
85
+ email:
86
+ - neng2.xu2@gmail.com
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - .gitignore
92
+ - Gemfile
93
+ - LICENSE.txt
94
+ - README.md
95
+ - Rakefile
96
+ - dolphin.gemspec
97
+ - lib/dolphin.rb
98
+ - lib/dolphin/version.rb
99
+ homepage: ''
100
+ licenses:
101
+ - MIT
102
+ metadata: {}
103
+ post_install_message:
104
+ rdoc_options: []
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - '>='
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - '>='
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ requirements: []
118
+ rubyforge_project:
119
+ rubygems_version: 2.0.2
120
+ signing_key:
121
+ specification_version: 4
122
+ summary: 'Dolphin: deploy smartly'
123
+ test_files: []