dolphin 0.0.2 → 0.0.3

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.
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: