dolphin 0.0.1

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.
@@ -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: []