webbynode 1.0.5.beta2 → 1.0.5.beta3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of webbynode might be problematic. Click here for more details.

data/Gemfile CHANGED
@@ -5,6 +5,7 @@ gem 'domainatrix'
5
5
  gem 'net-ssh'
6
6
  gem 'highline'
7
7
  gem 'rainbow'
8
+ gem 'taps'
8
9
 
9
10
  group :development do
10
11
  gem 'rspec'
data/Gemfile.lock CHANGED
@@ -31,13 +31,17 @@ GEM
31
31
  launchy (0.3.7)
32
32
  configuration (>= 0.0.5)
33
33
  rake (>= 0.8.1)
34
+ mime-types (1.16)
34
35
  net-ssh (2.1.0)
35
36
  open_gem (1.4.2)
36
37
  launchy (~> 0.3.5)
38
+ rack (1.2.1)
37
39
  rainbow (1.1.1)
38
40
  rake (0.8.7)
39
41
  rb-fsevent (0.4.0)
40
42
  rcov (0.9.9)
43
+ rest-client (1.6.1)
44
+ mime-types (>= 1.16)
41
45
  rspec (2.5.0)
42
46
  rspec-core (~> 2.5.0)
43
47
  rspec-expectations (~> 2.5.0)
@@ -48,6 +52,18 @@ GEM
48
52
  rspec-mocks (2.5.0)
49
53
  rubyforge (2.0.4)
50
54
  json_pure (>= 1.1.7)
55
+ sequel (3.20.0)
56
+ sinatra (1.0)
57
+ rack (>= 1.0)
58
+ sqlite3 (1.3.3)
59
+ sqlite3-ruby (1.3.3)
60
+ sqlite3 (>= 1.3.3)
61
+ taps (0.3.19)
62
+ rack (>= 1.0.1)
63
+ rest-client (< 1.7.0, >= 1.4.0)
64
+ sequel (~> 3.20.0)
65
+ sinatra (~> 1.0.0)
66
+ sqlite3-ruby (~> 1.2)
51
67
  thor (0.14.6)
52
68
 
53
69
  PLATFORMS
@@ -71,3 +87,4 @@ DEPENDENCIES
71
87
  rb-fsevent
72
88
  rcov
73
89
  rspec
90
+ taps
data/Manifest CHANGED
@@ -22,6 +22,7 @@ lib/templates/backup
22
22
  lib/templates/gitignore
23
23
  lib/templates/help
24
24
  lib/webbynode.rb
25
+ lib/webbynode/action_command.rb
25
26
  lib/webbynode/api_client.rb
26
27
  lib/webbynode/application.rb
27
28
  lib/webbynode/attribute_accessors.rb
@@ -36,6 +37,7 @@ lib/webbynode/commands/authorize_root.rb
36
37
  lib/webbynode/commands/change_dns.rb
37
38
  lib/webbynode/commands/config.rb
38
39
  lib/webbynode/commands/console.rb
40
+ lib/webbynode/commands/database.rb
39
41
  lib/webbynode/commands/delete.rb
40
42
  lib/webbynode/commands/guides.rb
41
43
  lib/webbynode/commands/help.rb
@@ -46,6 +48,7 @@ lib/webbynode/commands/push.rb
46
48
  lib/webbynode/commands/remote.rb
47
49
  lib/webbynode/commands/restart.rb
48
50
  lib/webbynode/commands/settings.rb
51
+ lib/webbynode/commands/ssh.rb
49
52
  lib/webbynode/commands/start.rb
50
53
  lib/webbynode/commands/stop.rb
51
54
  lib/webbynode/commands/tasks.rb
@@ -74,6 +77,7 @@ lib/webbynode/remote_executor.rb
74
77
  lib/webbynode/server.rb
75
78
  lib/webbynode/ssh.rb
76
79
  lib/webbynode/ssh_keys.rb
80
+ lib/webbynode/taps.rb
77
81
  lib/webbynode/trial.rb
78
82
  lib/webbynode/updater.rb
79
83
  spec/fixtures/aliases
@@ -116,6 +120,7 @@ spec/webbynode/commands/authorize_root_spec.rb
116
120
  spec/webbynode/commands/change_dns_spec.rb
117
121
  spec/webbynode/commands/config_spec.rb
118
122
  spec/webbynode/commands/console_spec.rb
123
+ spec/webbynode/commands/database_spec.rb
119
124
  spec/webbynode/commands/delete_spec.rb
120
125
  spec/webbynode/commands/guides_spec.rb
121
126
  spec/webbynode/commands/help_spec.rb
@@ -125,6 +130,7 @@ spec/webbynode/commands/open_spec.rb
125
130
  spec/webbynode/commands/push_spec.rb
126
131
  spec/webbynode/commands/remote_spec.rb
127
132
  spec/webbynode/commands/settings_spec.rb
133
+ spec/webbynode/commands/ssh_spec.rb
128
134
  spec/webbynode/commands/tasks_spec.rb
129
135
  spec/webbynode/commands/user_spec.rb
130
136
  spec/webbynode/commands/version_spec.rb
@@ -148,5 +154,5 @@ spec/webbynode/push_and_spec.rb
148
154
  spec/webbynode/remote_executor_spec.rb
149
155
  spec/webbynode/server_spec.rb
150
156
  spec/webbynode/ssh_spec.rb
157
+ spec/webbynode/taps_spec.rb
151
158
  spec/webbynode/trial_spec.rb
152
- webbynode.gemspec
data/Rakefile CHANGED
@@ -4,7 +4,7 @@ require 'rake/testtask'
4
4
 
5
5
  require 'echoe'
6
6
 
7
- Echoe.new('webbynode', '1.0.5.beta2') do |p|
7
+ Echoe.new('webbynode', '1.0.5.beta3') do |p|
8
8
  p.description = "Webbynode Deployment Gem"
9
9
  p.url = "http://webbynode.com"
10
10
  p.author = "Felipe Coury"
@@ -13,6 +13,7 @@ Echoe.new('webbynode', '1.0.5.beta2') do |p|
13
13
  p.dependencies = [
14
14
  ['bundler', '>=0.9.26'],
15
15
  ['net-ssh', '=2.1.0'],
16
+ ['taps', '~>0.3.19'],
16
17
  ['highline', '>=1.5.2'],
17
18
  ['httparty', '>=0.4.5'],
18
19
  ['launchy', '>=0.3.7'],
@@ -0,0 +1,22 @@
1
+ module Webbynode
2
+ class ActionCommand < Webbynode::Command
3
+ attr_reader :action
4
+
5
+ def self.allowed_actions(actions)
6
+ self.parameter :action, String, actions.join(", "),
7
+ :validate => { :in => actions },
8
+ :required => false
9
+ end
10
+
11
+ def execute
12
+ @action = param(:action) || "default"
13
+ send(action)
14
+ end
15
+
16
+ private
17
+
18
+ def default
19
+ raise "No default method for #{self.class.name}"
20
+ end
21
+ end
22
+ end
@@ -84,7 +84,7 @@ module Webbynode
84
84
  email = overwrite[:email] if overwrite.is_a?(Hash) and overwrite[:email]
85
85
  token = overwrite[:token] if overwrite.is_a?(Hash) and overwrite[:token]
86
86
 
87
- puts io.read_from_template("api_token") unless email and token
87
+ io.log io.read_from_template("api_token") unless email and token
88
88
 
89
89
  email ||= ask("Login email: ")
90
90
  token ||= ask("API token: ")
@@ -7,6 +7,12 @@ module Webbynode
7
7
  def initialize(*args)
8
8
  args = ["help", "commands"] unless args.any?
9
9
 
10
+ if args.first.include?(":")
11
+ arg = args.shift
12
+ args.unshift arg.split(":")[1]
13
+ args.unshift arg.split(":")[0]
14
+ end
15
+
10
16
  @command = args.shift
11
17
  @params = args
12
18
  end
@@ -2,19 +2,21 @@ module Webbynode::Commands
2
2
  class Accounts < Webbynode::Command
3
3
  summary "Manages multiple Webbynode accounts"
4
4
  add_alias "account"
5
+ add_alias "acc"
5
6
 
6
- parameter :action, String, "use, new, save, delete or list.",
7
- :validate => { :in => ["use", "new", "save", "delete", "list"] },
7
+ parameter :action, String, "use, new, save, rename, delete or list.",
8
+ :validate => { :in => ["use", "new", "save", "rename", "delete", "list"] },
8
9
  :default => "list",
9
10
  :required => false
10
11
  parameter :name, String, "account name", :required => false
12
+ parameter :new_name, String, "new account name", :required => false
11
13
 
12
14
  Prefix = "#{Webbynode::Io.home_dir}/.webbynode"
13
15
 
14
16
  attr_accessor :action
15
17
 
16
18
  def execute
17
- @action = param(:action) || "default"
19
+ @action = param(:action) || "list"
18
20
  send(action)
19
21
  end
20
22
 
@@ -22,7 +24,7 @@ module Webbynode::Commands
22
24
 
23
25
  def missing_target?
24
26
  unless io.file_exists?(target)
25
- io.log "Account alias '#{param(:name)}' not found. Use 'wn account list' for a full list."
27
+ io.log "Account alias #{param(:name).color(:yellow)} not found. Use #{"wn account list".color(:white).bright} for a full list."
26
28
  return true
27
29
  end
28
30
  end
@@ -33,7 +35,7 @@ module Webbynode::Commands
33
35
 
34
36
  def default
35
37
  credentials = api.credentials
36
- io.log "Current account: #{credentials["email"]}"
38
+ io.log "Current account: #{credentials["email"].color(:yellow)}"
37
39
  end
38
40
 
39
41
  def list
@@ -44,9 +46,11 @@ module Webbynode::Commands
44
46
  return
45
47
  end
46
48
 
49
+ current = api.credentials["email"]
47
50
  files.each do |f|
48
51
  if f =~ /\.webbynode_(.*)/
49
- io.log $1
52
+ mark = io.file_matches(f, /email=#{current}/) ? "* " : " "
53
+ io.log "#{mark.color(:yellow)}#{$1.color(:white).bright}"
50
54
  end
51
55
  end
52
56
  end
@@ -63,6 +67,7 @@ module Webbynode::Commands
63
67
  def use
64
68
  return if missing_target?
65
69
  io.copy_file target, "#{Prefix}"
70
+ io.log "Successfully switched to account alias #{param(:name).color(:yellow)}."
66
71
  end
67
72
 
68
73
  def new
@@ -73,5 +78,17 @@ module Webbynode::Commands
73
78
  return if missing_target?
74
79
  io.delete_file target
75
80
  end
81
+
82
+ def rename
83
+ return if missing_target?
84
+
85
+ if io.file_exists?("#{Prefix}_#{param(:new_name)}")
86
+ io.log "Account alias #{param(:new_name).color(:yellow)} already exists, use #{"wn account delete".color(:white).bright} to remove it first."
87
+ return
88
+ end
89
+
90
+ io.rename_file "#{Prefix}_#{param(:name)}", "#{Prefix}_#{param(:new_name)}"
91
+ io.log "Account alias #{param(:name).color(:yellow)} successfully renamed to #{param(:new_name).color(:yellow)}."
92
+ end
76
93
  end
77
94
  end
@@ -8,7 +8,7 @@ module Webbynode::Commands
8
8
  secret = io.general_settings['aws_secret']
9
9
 
10
10
  unless key and secret
11
- puts io.read_from_template("backup")
11
+ io.log io.read_from_template("backup")
12
12
 
13
13
  key = ask("AWS key: ")
14
14
  secret = ask("AWS secret: ") unless key.blank?
@@ -0,0 +1,93 @@
1
+ module Webbynode::Commands
2
+ class Database < Webbynode::ActionCommand
3
+ summary "Manages your application database"
4
+
5
+ add_alias "db"
6
+ allowed_actions %w(pull push)
7
+
8
+ option :debug, "Show server communication steps"
9
+
10
+ requires_initialization!
11
+ attr_reader :db
12
+
13
+ def pull
14
+ go :pull
15
+ end
16
+
17
+ def push
18
+ go :push
19
+ end
20
+
21
+ def go(action)
22
+ ask_db_credentials
23
+
24
+ io.log "#{action.to_s.capitalize}ing remote data to database #{db[:name]}"
25
+
26
+ db_name = pushand.remote_db_name
27
+ password = remote_executor.retrieve_db_password
28
+ ip = git.parse_remote_ip
29
+
30
+ if option(:debug)
31
+ io.log ""
32
+ io.log "Retrieving contents from #{db_name} database in #{ip}..."
33
+ end
34
+
35
+ taps = Webbynode::Taps.new(db_name, password, io, remote_executor)
36
+ taps.debug = option(:debug)
37
+ begin
38
+ io.log "Starting taps in server mode..." if option(:debug)
39
+ taps.start
40
+ io.log "Waiting for taps to start..." if option(:debug)
41
+ sleep 4
42
+ io.log "Sending action #{action} with db #{db[:name]}..." if option(:debug)
43
+ taps.send(action, :user => db[:user],
44
+ :password => db[:password],
45
+ :database => db[:name],
46
+ :remote_ip => ip)
47
+ ensure
48
+ io.log "Stopping taps server..."
49
+ taps.finish
50
+ end
51
+ end
52
+
53
+ def query(question, default)
54
+ answer = ask("#{question} [#{default}]: ")
55
+ answer = default if answer.blank?
56
+ answer
57
+ end
58
+
59
+ def retrieve_db_credentials
60
+ @db = {
61
+ :name => io.load_setting("database_name"),
62
+ :user => io.load_setting("database_user"),
63
+ :password => io.load_setting("database_password")
64
+ }
65
+ end
66
+
67
+ def ask_db_credentials
68
+ retrieve_db_credentials
69
+
70
+ unless db[:name]
71
+ db[:name] = query("Database name", io.db_name)
72
+ db[:user] = query(" User name", io.db_name)
73
+ end
74
+
75
+ save_password = false
76
+ unless db[:password]
77
+ db[:password] = query(" Password", "")
78
+ save_password = ask("Save password (y/n)? ").downcase == 'y'
79
+ end
80
+
81
+ save_db_credentials(save_password)
82
+ end
83
+
84
+ def save_db_credentials(save_password)
85
+ io.add_setting "database_name", db[:name]
86
+ io.add_setting "database_user", db[:user]
87
+
88
+ if save_password
89
+ io.add_setting "database_password", db[:password]
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,11 @@
1
+ module Webbynode::Commands
2
+ class Ssh < Webbynode::Command
3
+ summary "Log into your Webby via SSH"
4
+
5
+ requires_initialization!
6
+
7
+ def execute
8
+ server.ssh
9
+ end
10
+ end
11
+ end
data/lib/webbynode/git.rb CHANGED
@@ -24,7 +24,7 @@ module Webbynode
24
24
  end
25
25
 
26
26
  def clean?
27
- io.exec("git status") =~ /working directory clean/
27
+ io.exec("git status") =~ /nothing to commit/
28
28
  end
29
29
 
30
30
  def delete_file(file)
data/lib/webbynode/io.rb CHANGED
@@ -14,6 +14,13 @@ module Webbynode
14
14
  Config::CONFIG["host_os"] =~ /mswin|mingw/
15
15
  end
16
16
 
17
+ def random_password(len=10)
18
+ chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
19
+ newpass = ""
20
+ 1.upto(len) { |i| newpass << chars[rand(chars.size-1)] }
21
+ return newpass
22
+ end
23
+
17
24
  def list_files(dir)
18
25
  Dir.glob(dir)
19
26
  end
@@ -50,10 +57,18 @@ module Webbynode
50
57
  File.open(file, 'w') { |f| f.write(contents) }
51
58
  end
52
59
 
60
+ def file_matches(file, regexp)
61
+ File.read(file) =~ regexp
62
+ end
63
+
53
64
  def app_name
54
65
  Dir.pwd.split("/").last.gsub(/[\.| ]/, "_")
55
66
  end
56
67
 
68
+ def db_name
69
+ app_name.gsub(/[-._]/, "")
70
+ end
71
+
57
72
  def mkdir(path)
58
73
  # TODO: raise "Tried to create real folder: #{path}" if $testing
59
74
  FileUtils.mkdir_p(path)
@@ -73,6 +88,11 @@ module Webbynode
73
88
  [$? == 0, result]
74
89
  end
75
90
 
91
+ def execute(s)
92
+ Kernel.exec s
93
+ $?
94
+ end
95
+
76
96
  def directory?(s)
77
97
  File.directory?(s)
78
98
  end
@@ -184,6 +204,10 @@ module Webbynode
184
204
  File.delete(file_name)
185
205
  end
186
206
 
207
+ def rename_file(old_name, new_name)
208
+ File.rename(old_name, new_name)
209
+ end
210
+
187
211
  def templates_path
188
212
  TemplatesPath
189
213
  end
@@ -12,5 +12,9 @@ module Webbynode
12
12
  def parse_remote_app_name
13
13
  io.read_file(".pushand")[/^phd \$0 ([^ ]+)/, 1]
14
14
  end
15
+
16
+ def remote_db_name
17
+ parse_remote_app_name.gsub(/[-._]/, "")
18
+ end
15
19
  end
16
20
  end
@@ -20,6 +20,11 @@ module Webbynode
20
20
  exec('pwd').strip
21
21
  end
22
22
 
23
+ def retrieve_db_password
24
+ password = exec %q(echo `cat /var/webbynode/templates/rails/database.yml | grep password: | tail -1 | cut -d ":" -f 2`)
25
+ password.strip
26
+ end
27
+
23
28
  def exec(cmd, echo=false, exit_code=false)
24
29
  begin
25
30
  ssh.execute(cmd, echo, exit_code)
@@ -16,6 +16,10 @@ module Webbynode
16
16
  def io
17
17
  @io ||= Webbynode::Io.new
18
18
  end
19
+
20
+ def ssh
21
+ Kernel.exec "ssh -p #{port} git@#{ip}"
22
+ end
19
23
 
20
24
  def remote_executor
21
25
  @remote_executor ||= Webbynode::RemoteExecutor.new(ip, user, port)
@@ -0,0 +1,74 @@
1
+ require 'taps/operation'
2
+ require 'taps/cli'
3
+
4
+ module Webbynode
5
+ class Taps
6
+ attr_reader :database, :database_password
7
+ attr_reader :io, :remote_executor
8
+ attr_reader :user, :password
9
+ attr_reader :pid
10
+
11
+ attr_accessor :debug
12
+
13
+ def initialize(database, database_password, io, remote_executor)
14
+ @database = database
15
+ @database_password = database_password
16
+ @io = io
17
+ @remote_executor = remote_executor
18
+ end
19
+
20
+ def start
21
+ @user = io.random_password
22
+ @password = io.random_password
23
+
24
+ command = "bash -c 'nohup taps server mysql://#{database}:#{database_password}@localhost/#{database} #{@user} #{@password} > /dev/null 2>&1 &\necho $!'"
25
+
26
+ io.log "Executing: #{command}" if debug
27
+
28
+ result = remote_executor.exec(command)
29
+ result.strip! if result
30
+
31
+ io.log "Result: #{result}" if debug
32
+ io.log "" if debug
33
+
34
+ raise "Could not start taps on remote server" unless result =~ /^[0-9]+$/
35
+
36
+ @pid = result
37
+ end
38
+
39
+ def pull(options)
40
+ execute "pull", options
41
+ end
42
+
43
+ def push(options)
44
+ execute "push", options
45
+ end
46
+
47
+ def finish
48
+ raise "Taps server was not started" unless user
49
+
50
+ command = "kill -9 #{pid}"
51
+
52
+ io.log "Executing: #{command}" if debug
53
+
54
+ result = remote_executor.exec command
55
+
56
+ io.log "Result: #{result}\n" if debug
57
+ end
58
+
59
+ private
60
+
61
+ def execute(action, options)
62
+ raise "Taps server was not started" unless user
63
+
64
+ local_url = "mysql://#{options[:user]}:#{options[:password]}@localhost/#{options[:database]}"
65
+ remote_url = "http://#{user}:#{password}@#{options[:remote_ip]}:5000"
66
+
67
+ io.log "Running taps #{action}"
68
+
69
+ ::Taps::Cli.new([]).clientxfer(action.to_sym,
70
+ :database_url => local_url,
71
+ :remote_url => remote_url)
72
+ end
73
+ end
74
+ end
data/lib/webbynode.rb CHANGED
@@ -24,6 +24,7 @@ require File.join(File.dirname(__FILE__), 'webbynode', 'server')
24
24
  require File.join(File.dirname(__FILE__), 'webbynode', 'push_and')
25
25
  require File.join(File.dirname(__FILE__), 'webbynode', 'gemfile')
26
26
  require File.join(File.dirname(__FILE__), 'webbynode', 'command')
27
+ require File.join(File.dirname(__FILE__), 'webbynode', 'action_command')
27
28
  require File.join(File.dirname(__FILE__), 'webbynode', 'option')
28
29
  require File.join(File.dirname(__FILE__), 'webbynode', 'parameter')
29
30
  require File.join(File.dirname(__FILE__), 'webbynode', 'api_client')
@@ -31,6 +32,7 @@ require File.join(File.dirname(__FILE__), 'webbynode', 'remote_executor')
31
32
  require File.join(File.dirname(__FILE__), 'webbynode', 'notify')
32
33
  require File.join(File.dirname(__FILE__), 'webbynode', 'updater')
33
34
  require File.join(File.dirname(__FILE__), 'webbynode', 'trial')
35
+ require File.join(File.dirname(__FILE__), 'webbynode', 'taps')
34
36
  require File.join(File.dirname(__FILE__), 'webbynode', 'properties')
35
37
  require File.join(File.dirname(__FILE__), 'webbynode', 'attribute_accessors')
36
38
  require File.join(File.dirname(__FILE__), 'webbynode', 'engines', 'engine')
@@ -69,10 +71,12 @@ require File.join(File.dirname(__FILE__), 'webbynode', 'commands', 'authorize_ro
69
71
  require File.join(File.dirname(__FILE__), 'webbynode', 'commands', 'console')
70
72
  require File.join(File.dirname(__FILE__), 'webbynode', 'commands', 'logs')
71
73
  require File.join(File.dirname(__FILE__), 'webbynode', 'commands', 'guides')
74
+ require File.join(File.dirname(__FILE__), 'webbynode', 'commands', 'ssh')
75
+ require File.join(File.dirname(__FILE__), 'webbynode', 'commands', 'database')
72
76
  require File.join(File.dirname(__FILE__), 'webbynode', 'application')
73
77
 
74
78
  module Webbynode
75
- VERSION = '1.0.5.beta2'
79
+ VERSION = '1.0.5.beta3'
76
80
  end
77
81
 
78
82
  class Array
@@ -165,6 +165,8 @@ describe Webbynode::ApiClient do
165
165
  api.should_receive(:ask).with("Login email: ").once.ordered.and_return("login@email.com")
166
166
  api.should_receive(:ask).with("API token: ").once.ordered.and_return("apitoken")
167
167
 
168
+ io.stub(:log)
169
+
168
170
  creds = api.init_credentials(true)
169
171
  creds[:email].should == "login@email.com"
170
172
  creds[:token].should == "apitoken"
@@ -203,6 +205,8 @@ describe Webbynode::ApiClient do
203
205
  api.should_receive(:ask).with("Login email: ").once.ordered.and_return("login@email.com")
204
206
  api.should_receive(:ask).with("API token: ").once.ordered.and_return("apitoken")
205
207
 
208
+ io.stub(:log)
209
+
206
210
  api.init_credentials
207
211
  end
208
212
 
@@ -219,6 +223,8 @@ describe Webbynode::ApiClient do
219
223
 
220
224
  api.should_receive(:ask).with("Login email: ").once.ordered.and_return("login@email.com")
221
225
  api.should_receive(:ask).with("API token: ").once.ordered.and_return("apitoken")
226
+
227
+ io.stub(:log)
222
228
 
223
229
  lambda { api.init_credentials }.should raise_error(Webbynode::ApiClient::Unauthorized, "You have provided the wrong credentials")
224
230
  end