dolphin 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 96307e5f4700eaa30d22be8103a85ddcf32c8132
4
- data.tar.gz: fc210b44ca75f5683e537f271063a15a373bca0a
3
+ metadata.gz: 64b7b1836dabf66d97b69fe469e1f8f4033f79e1
4
+ data.tar.gz: 83df23c962252ad8e9410219d8a8a69fb0be9229
5
5
  SHA512:
6
- metadata.gz: 546c32db70818adbf42cc99a2959d6613a5bfd354ce052040e12e8818a1a885fd521bdff61491718aa8752184c4d03a2cd5bdf41012369e01cb5f21d5e7ad8c5
7
- data.tar.gz: 7ae901e6f2bda4e7c9e546c7902fbd3aabdcdce0efaba45f60e2b7d67e862a873f631e5df601b57c60991c6cff4dd418f31e29a6cc97a79eca247287cc83a7e3
6
+ metadata.gz: 1cbff0b4fe5d73c500a6b99b7ef944083407fef7c4670c3d9adc9b24b369aa6a7087223d313a941ebc56fce142071bf5a6c0bebecbed1e2310480b0e8ce255c5
7
+ data.tar.gz: 7fb173b1c59804e27891accfba0a29e25f4485afaad496b669abaf7080ac54f50d3215013651bd1e97be282623ceb33730e9499c38e3b83d3f28406d30aed0fb
@@ -1,143 +1,9 @@
1
- require "thor"
2
- require 'net/ssh'
3
- require 'parallel'
4
-
5
1
  require_relative "dolphin/version"
2
+ require_relative "dolphin/base"
3
+ require_relative "dolphin/lock"
4
+ require_relative "dolphin/deploy"
6
5
 
7
6
  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)
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 can be separated into groups
40
-
41
- commands = []
42
- menu.each do |group|
43
- buffer = []
44
- group.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
- commands.push(*buffer)
51
- end
52
- commands
53
- end
54
-
55
- def ssh_connection(server)
56
- @sessions[server] ||= begin
57
- ssh = Net::SSH.start(server, @user, )
58
- at_exit { ssh.close }
59
- ssh
60
- end
61
- end
62
-
63
- def execute(menu)
64
- # execute commands defined in menu
65
- commands = parse_commands(menu)
66
- puts "#{'*'*10}Executing commands#{'*'*10}\n"
67
- commands.each do |command|
68
- puts "#{command}\n"
69
- end
70
- puts "#{'='*60}\n"
71
-
72
- # use Parallel to execute commands on multiple servers in parallel
73
- tracks = @servers.size
74
- # 3 threads maximum
75
- tracks = 3 if tracks > 3
76
- # record output to display at the end
77
- output = {}
78
-
79
- Parallel.map(@servers, in_threads: tracks) do |server|
80
- session = ssh_connection(server)
81
- output[server] = [] # output from this server
82
-
83
- channel = session.open_channel do |chan|
84
- chan.send_channel_request "shell" do |ch, success|
85
- # chan.request_pty do |ch, success|
86
- raise "could not start user shell" unless success
87
-
88
- # normal output
89
- ch.on_data do |c, data|
90
- msg = "[output]: #{data}"
91
- puts "#{server} => #{msg}"
92
- output[server] << msg
93
- end
94
-
95
- # error message
96
- ch.on_extended_data do |c, type, data|
97
- msg = "[error]: #{data}"
98
- puts "#{server} => #{msg}"
99
- output[server] << msg
100
- end
101
-
102
- # exit code
103
- ch.on_request "exit-status" do |c, data|
104
- msg = "[exit]: #{data.read_long}\n"
105
- puts "#{server} => #{msg}"
106
- output[server] << msg
107
- end
108
-
109
- # has to explicitly call shell startup script
110
- ch.send_data "source ~/.bash_profile\n"
111
-
112
- # pick up ruby
113
- ch.send_data "chruby #{@ruby_version}\n"
114
-
115
- # Output each command as if they were entered on the command line
116
- commands.each do |command|
117
- ch.send_data "#{command}\n"
118
- end
119
-
120
- # Remember to exit or we'll hang!
121
- ch.send_data "exit\n"
122
-
123
- end
124
- end
125
-
126
- # Wait for everything to complete
127
- channel.wait
128
- end
129
-
130
- # puts output
131
- puts "\n#{'*'*10}Results Review#{'*'*10}\n"
132
- output.each do |server, data|
133
- puts "\n#{'='*60}\n"
134
- puts "Executing on [#{server}] =>\n"
135
- data.each {|line| puts line}
136
- end
137
- puts "\n\n"
138
- end
139
-
140
- end
141
7
 
142
8
  # =============================================================================
143
9
  # Setup
@@ -345,49 +211,6 @@ module Dolphin
345
211
 
346
212
  end
347
213
 
348
- # =============================================================================
349
- # Deploy
350
- # =============================================================================
351
- class Deploy < Base
352
- desc "bundle", "sudo bundle install"
353
- def bundle
354
- menu = [
355
- "
356
- cd #{@deploy_dir}
357
- sudo bundle install --quiet
358
- ",
359
- ]
360
-
361
- execute menu
362
- end
363
-
364
- desc "go", "normal deploy procedure"
365
- def go
366
- # update code
367
- invoke "dolphin:git:update"
368
-
369
- # no need to invoke since it is within the same class
370
- bundle
371
-
372
- # restart app server
373
- invoke "dolphin:puma:restart"
374
- end
375
-
376
- desc "try", "normal deploy procedure"
377
- def try
378
- menu = [
379
- "
380
- cd #{@deploy_dir}
381
- pwd
382
- bundle check
383
- ",
384
- ]
385
-
386
- execute menu
387
- end
388
-
389
- end
390
-
391
214
  # =============================================================================
392
215
  # Git
393
216
  # =============================================================================
@@ -463,6 +286,7 @@ module Dolphin
463
286
  register(Puma, 'puma', 'puma', 'Puma related commands')
464
287
  register(Nginx, 'nginx', 'nginx', 'Nginx related commands')
465
288
  register(Git, 'git', 'git', 'Git related commands')
289
+ register(Lock, 'lock', 'lock', 'Lock resource to avoid simultaneous deployments')
466
290
  end
467
291
 
468
292
  end
@@ -0,0 +1,167 @@
1
+ require "thor"
2
+ require 'net/ssh'
3
+ require 'parallel'
4
+
5
+ # core functions
6
+ class Dolphin::Base < Thor
7
+ include Thor::Actions
8
+
9
+ # =============================================================================
10
+ # class options
11
+ # =============================================================================
12
+
13
+ class_option :env, :aliases => '-e', :type => :string, :default => 'alpha'
14
+
15
+ def initialize(args=[], options={}, config={})
16
+ super(args, options, config)
17
+ # set up environment
18
+ env
19
+ end
20
+
21
+ # =============================================================================
22
+ # private functions
23
+ # =============================================================================
24
+
25
+ private
26
+
27
+ # deployment environment
28
+ def env
29
+ # placeholder, to be implemented in each project
30
+
31
+ end
32
+
33
+ def parse_commands(menu)
34
+ # Helper method to parse a list of text menu of possible commands,
35
+ # which may contain empty lines or commented out with #
36
+ # commands can be separated into groups
37
+
38
+ commands = []
39
+ menu.each do |group|
40
+ buffer = []
41
+ group.split(/\r?\n/).each do |line|
42
+ line = line.strip
43
+ unless line.empty? or line.start_with?('#') # empty or commented out
44
+ buffer << line
45
+ end
46
+ end
47
+ commands.push(*buffer)
48
+ end
49
+ commands
50
+ end
51
+
52
+ def ssh_connection(server)
53
+ @sessions[server] ||= begin
54
+ ssh = Net::SSH.start(server, @user, )
55
+ at_exit { ssh.close }
56
+ ssh
57
+ end
58
+ end
59
+
60
+ def capture(command, server)
61
+ # capture output from one target server
62
+ output = ''
63
+ session = ssh_connection(server)
64
+
65
+ channel = session.open_channel do |chan|
66
+ chan.exec(command) do |ch, success|
67
+
68
+ ch.on_data do |c, data|
69
+ output << data
70
+ end
71
+
72
+ ch.on_extended_data do |c, type, data|
73
+ output << data
74
+ end
75
+
76
+ end
77
+ end
78
+
79
+ channel.wait
80
+ output
81
+ end
82
+
83
+ def execute(menu, target_server=nil)
84
+ # execute commands defined in menu, when :target_server is passed in, only execute on this server
85
+ commands = parse_commands(menu)
86
+ puts "#{'*'*10}Executing commands#{'*'*10}\n"
87
+ commands.each do |command|
88
+ puts "#{command}\n"
89
+ end
90
+ puts "#{'='*60}\n"
91
+
92
+ if target_server # solo
93
+ tracks = 1
94
+ target = [target_server]
95
+ else
96
+ # use Parallel to execute commands on multiple servers in parallel
97
+ tracks = @servers.size
98
+ # 3 threads maximum
99
+ tracks = 3 if tracks > 3
100
+ target = @servers
101
+ end
102
+
103
+ # record output to display at the end
104
+ output = {}
105
+
106
+ Parallel.map(target, in_threads: tracks) do |server|
107
+ session = ssh_connection(server)
108
+ output[server] = [] # output from this server
109
+
110
+ channel = session.open_channel do |chan|
111
+ chan.send_channel_request "shell" do |ch, success|
112
+ # chan.request_pty do |ch, success|
113
+ raise "could not start user shell" unless success
114
+
115
+ # normal output
116
+ ch.on_data do |c, data|
117
+ msg = "[output]: #{data}"
118
+ puts "#{server} => #{msg}"
119
+ output[server] << msg
120
+ end
121
+
122
+ # error message
123
+ ch.on_extended_data do |c, type, data|
124
+ msg = "[error]: #{data}"
125
+ puts "#{server} => #{msg}"
126
+ output[server] << msg
127
+ end
128
+
129
+ # exit code
130
+ ch.on_request "exit-status" do |c, data|
131
+ msg = "[exit]: #{data.read_long}\n"
132
+ puts "#{server} => #{msg}"
133
+ output[server] << msg
134
+ end
135
+
136
+ # has to explicitly call shell startup script
137
+ ch.send_data "source ~/.bash_profile\n"
138
+
139
+ # pick up ruby
140
+ ch.send_data "chruby #{@ruby_version}\n"
141
+
142
+ # Output each command as if they were entered on the command line
143
+ commands.each do |command|
144
+ ch.send_data "#{command}\n"
145
+ end
146
+
147
+ # Remember to exit or we'll hang!
148
+ ch.send_data "exit\n"
149
+
150
+ end
151
+ end
152
+
153
+ # Wait for everything to complete
154
+ channel.wait
155
+ end
156
+
157
+ # puts output
158
+ puts "\n#{'*'*10}Results Review#{'*'*10}\n"
159
+ output.each do |server, data|
160
+ puts "\n#{'='*60}\n"
161
+ puts "Executing on [#{server}] =>\n"
162
+ data.each {|line| puts line}
163
+ end
164
+ puts "\n\n"
165
+ end
166
+
167
+ end
@@ -0,0 +1,49 @@
1
+ # Deploy tasks
2
+ class Dolphin::Deploy < Dolphin::Base
3
+
4
+ desc "bundle", "sudo bundle install"
5
+ def bundle
6
+ menu = [
7
+ "
8
+ cd #{@deploy_dir}
9
+ sudo bundle install --quiet
10
+ ",
11
+ ]
12
+
13
+ execute menu
14
+ end
15
+
16
+ desc "go", "normal deploy procedure"
17
+ def go
18
+ # check lock
19
+ invoke "dolphin:lock:check"
20
+ # put lock
21
+ invoke "dolphin:lock:create"
22
+
23
+ # update code
24
+ invoke "dolphin:git:update"
25
+
26
+ # no need to invoke since it is within the same class
27
+ bundle
28
+
29
+ # restart app server
30
+ invoke "dolphin:puma:restart"
31
+
32
+ # remove lock
33
+ invoke "dolphin:lock:release"
34
+ end
35
+
36
+ desc "try", "normal deploy procedure"
37
+ def try
38
+ menu = [
39
+ "
40
+ cd #{@deploy_dir}
41
+ pwd
42
+ bundle check
43
+ ",
44
+ ]
45
+
46
+ execute menu
47
+ end
48
+
49
+ end
@@ -0,0 +1,29 @@
1
+ # Use lock to avoid simultaneous deployments
2
+ class Dolphin::Lock < Dolphin::Base
3
+
4
+ desc "check", "Check lock"
5
+ def check
6
+ command = "if [ -e #{@lock_file} ]; then cat #{@lock_file}; fi"
7
+ output = capture(command, @lead_server)
8
+ if output.empty?
9
+ puts "OK to proceed"
10
+ else
11
+ puts "[output]: #{output}"
12
+ abort "\e[0;31m A deployment is already in progress\n Please wait for its completion\nOr in case of stale lock, remove #{@lock_file} to unlock \e[0m\n"
13
+ end
14
+ end
15
+
16
+ desc "create", "Create lock"
17
+ def create
18
+ lock_message = "Deploy started at #{@deploy_date} in progress\n"
19
+ command = "echo '#{lock_message}' > #{@lock_file}"
20
+ puts capture(command, @lead_server)
21
+ end
22
+
23
+ desc "release", "Release lock"
24
+ def release
25
+ command = "rm -f #{@lock_file}"
26
+ puts capture(command, @lead_server)
27
+ end
28
+
29
+ end
@@ -1,3 +1,3 @@
1
1
  module Dolphin
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dolphin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - |
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-06-11 00:00:00.000000000 Z
12
+ date: 2013-06-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: thor
@@ -95,6 +95,9 @@ files:
95
95
  - Rakefile
96
96
  - dolphin.gemspec
97
97
  - lib/dolphin.rb
98
+ - lib/dolphin/base.rb
99
+ - lib/dolphin/deploy.rb
100
+ - lib/dolphin/lock.rb
98
101
  - lib/dolphin/version.rb
99
102
  homepage: ''
100
103
  licenses: