remoting 0.2.8
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.
- data/Gemfile +8 -0
- data/Gemfile.lock +94 -0
- data/LICENSE.txt +20 -0
- data/README.md +157 -0
- data/Rakefile +26 -0
- data/VERSION +1 -0
- data/examples/remote.rake +243 -0
- data/examples/remote.yml +7 -0
- data/lib/generators/remoting/install_generator.rb +20 -0
- data/lib/remoting/commander.rb +9 -0
- data/lib/remoting/config.rb +18 -0
- data/lib/remoting/dsl/script_builder.rb +52 -0
- data/lib/remoting/dsl/string.rb +24 -0
- data/lib/remoting/engine.rb +5 -0
- data/lib/remoting/local_commander.rb +18 -0
- data/lib/remoting/remote_commander.rb +32 -0
- data/lib/remoting/shell.rb +37 -0
- data/lib/remoting/ssh.rb +57 -0
- data/lib/remoting/task.rb +50 -0
- data/lib/remoting.rb +7 -0
- data/remoting.gemspec +66 -0
- metadata +121 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
actionmailer (3.2.3)
|
5
|
+
actionpack (= 3.2.3)
|
6
|
+
mail (~> 2.4.4)
|
7
|
+
actionpack (3.2.3)
|
8
|
+
activemodel (= 3.2.3)
|
9
|
+
activesupport (= 3.2.3)
|
10
|
+
builder (~> 3.0.0)
|
11
|
+
erubis (~> 2.7.0)
|
12
|
+
journey (~> 1.0.1)
|
13
|
+
rack (~> 1.4.0)
|
14
|
+
rack-cache (~> 1.2)
|
15
|
+
rack-test (~> 0.6.1)
|
16
|
+
sprockets (~> 2.1.2)
|
17
|
+
activemodel (3.2.3)
|
18
|
+
activesupport (= 3.2.3)
|
19
|
+
builder (~> 3.0.0)
|
20
|
+
activerecord (3.2.3)
|
21
|
+
activemodel (= 3.2.3)
|
22
|
+
activesupport (= 3.2.3)
|
23
|
+
arel (~> 3.0.2)
|
24
|
+
tzinfo (~> 0.3.29)
|
25
|
+
activeresource (3.2.3)
|
26
|
+
activemodel (= 3.2.3)
|
27
|
+
activesupport (= 3.2.3)
|
28
|
+
activesupport (3.2.3)
|
29
|
+
i18n (~> 0.6)
|
30
|
+
multi_json (~> 1.0)
|
31
|
+
arel (3.0.2)
|
32
|
+
builder (3.0.0)
|
33
|
+
erubis (2.7.0)
|
34
|
+
git (1.2.5)
|
35
|
+
hike (1.2.1)
|
36
|
+
i18n (0.6.0)
|
37
|
+
jeweler (1.8.3)
|
38
|
+
bundler (~> 1.0)
|
39
|
+
git (>= 1.2.5)
|
40
|
+
rake
|
41
|
+
rdoc
|
42
|
+
journey (1.0.3)
|
43
|
+
json (1.7.0)
|
44
|
+
mail (2.4.4)
|
45
|
+
i18n (>= 0.4.0)
|
46
|
+
mime-types (~> 1.16)
|
47
|
+
treetop (~> 1.4.8)
|
48
|
+
mime-types (1.18)
|
49
|
+
multi_json (1.3.4)
|
50
|
+
net-ssh (2.3.0)
|
51
|
+
polyglot (0.3.3)
|
52
|
+
rack (1.4.1)
|
53
|
+
rack-cache (1.2)
|
54
|
+
rack (>= 0.4)
|
55
|
+
rack-ssl (1.3.2)
|
56
|
+
rack
|
57
|
+
rack-test (0.6.1)
|
58
|
+
rack (>= 1.0)
|
59
|
+
rails (3.2.3)
|
60
|
+
actionmailer (= 3.2.3)
|
61
|
+
actionpack (= 3.2.3)
|
62
|
+
activerecord (= 3.2.3)
|
63
|
+
activeresource (= 3.2.3)
|
64
|
+
activesupport (= 3.2.3)
|
65
|
+
bundler (~> 1.0)
|
66
|
+
railties (= 3.2.3)
|
67
|
+
railties (3.2.3)
|
68
|
+
actionpack (= 3.2.3)
|
69
|
+
activesupport (= 3.2.3)
|
70
|
+
rack-ssl (~> 1.3.2)
|
71
|
+
rake (>= 0.8.7)
|
72
|
+
rdoc (~> 3.4)
|
73
|
+
thor (~> 0.14.6)
|
74
|
+
rake (0.9.2.2)
|
75
|
+
rdoc (3.12)
|
76
|
+
json (~> 1.4)
|
77
|
+
sprockets (2.1.3)
|
78
|
+
hike (~> 1.2)
|
79
|
+
rack (~> 1.0)
|
80
|
+
tilt (~> 1.1, != 1.3.0)
|
81
|
+
thor (0.14.6)
|
82
|
+
tilt (1.3.3)
|
83
|
+
treetop (1.4.10)
|
84
|
+
polyglot
|
85
|
+
polyglot (>= 0.3.1)
|
86
|
+
tzinfo (0.3.33)
|
87
|
+
|
88
|
+
PLATFORMS
|
89
|
+
ruby
|
90
|
+
|
91
|
+
DEPENDENCIES
|
92
|
+
jeweler (~> 1.8.3)
|
93
|
+
net-ssh
|
94
|
+
rails (~> 3.0)
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Maurizio Casimirri
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
# Remoting
|
2
|
+
|
3
|
+
*Remoting* is a great way to turn plain rake tasks in scripts to administer the server remotingly. It provides a little framework to run remoting commands over SSH along with a DSL to define remoting scripts.
|
4
|
+
|
5
|
+
Install
|
6
|
+
|
7
|
+
gem 'remoting'
|
8
|
+
|
9
|
+
Update your bundle
|
10
|
+
|
11
|
+
bundle install
|
12
|
+
|
13
|
+
Generate `remote.yml` stub
|
14
|
+
|
15
|
+
rails g remoting:install
|
16
|
+
|
17
|
+
Edit `config/remote.yml`
|
18
|
+
|
19
|
+
``` yml
|
20
|
+
remote:
|
21
|
+
any_setting_you_like: Here you can define properties that will be available in 'config' struct inside rake tasks!
|
22
|
+
example: Below are some tipical configuration settings you may wish to define ...
|
23
|
+
login: user@server
|
24
|
+
dest: /var/ror/myapp
|
25
|
+
repo: git@gitserver:myapp.git
|
26
|
+
ruby: 1.9.3
|
27
|
+
gemset: myapp
|
28
|
+
```
|
29
|
+
|
30
|
+
## Usage
|
31
|
+
|
32
|
+
Just require `remoting/task` inside your tasks. NOTE: you can also require it globally but is not recommended cause here `String` is patched to enable bash-flavoured syntax.
|
33
|
+
|
34
|
+
_ex._
|
35
|
+
|
36
|
+
desc "Restart the server"
|
37
|
+
task :restart do
|
38
|
+
require 'remoting/task'
|
39
|
+
|
40
|
+
remote('restart', config.login) do
|
41
|
+
mkdir '-p', config.dest.join('tmp')
|
42
|
+
touch config.dest.join('tmp', 'restart.txt')
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
Methods invoked inside the `remote` block are executed inside a ssh session. `remote` takes two arguments: `name` and `login`. `name` serves only for logging purposal while `login` is the login string to access the server supplied in the form of `user@host`
|
48
|
+
|
49
|
+
### DSL
|
50
|
+
|
51
|
+
By examples
|
52
|
+
|
53
|
+
remote("my task", config.login) do
|
54
|
+
|
55
|
+
ps("aux") | grep("mysql")
|
56
|
+
echo 'noise' > "/dev/null"
|
57
|
+
echo 'setting=value' >> "settings.conf"
|
58
|
+
tail -100 config.dir.join('log', 'logfile.log')
|
59
|
+
command("[[ -f \"path\" ]] && run_a_command")
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
### Local Tasks using DSL
|
64
|
+
|
65
|
+
You can also define local tasks using the same DSL
|
66
|
+
|
67
|
+
desc "Setup git origin"
|
68
|
+
task :init do
|
69
|
+
require 'remoting/task'
|
70
|
+
|
71
|
+
local('init') do
|
72
|
+
git :init
|
73
|
+
git :remote, :add, :origin, config.repo
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
Methods invoked inside the `local` block are executed locally. `local` takes only the `name` parameter.
|
78
|
+
|
79
|
+
|
80
|
+
### Interactive tasks
|
81
|
+
|
82
|
+
Invoking `remote` with `:interactive => true` will tell `remote` to yield the process to ssh, this way you will remotely interact with the server. On the other side everithing that is supposed to be executed after `remote` wont run. Despite this interactive tasks are very useful.
|
83
|
+
|
84
|
+
#### Example 1. Rails remote console (by popular demand):
|
85
|
+
|
86
|
+
# my_remote_task.rake
|
87
|
+
|
88
|
+
desc "Open rails console on server"
|
89
|
+
task :console do
|
90
|
+
require 'remoting/task'
|
91
|
+
|
92
|
+
remote('console', config.login, :interactive => true) do
|
93
|
+
cd config.dest
|
94
|
+
source '$HOME/.rvm/scripts/rvm'
|
95
|
+
bundle :exec, "rails c production"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
#### Example 2. Reloading Apache configuration (involves sudo):
|
100
|
+
|
101
|
+
task :reload do
|
102
|
+
require 'remoting/task'
|
103
|
+
|
104
|
+
remote('reload', config.login, :interactive => true) do
|
105
|
+
sudo "/etc/init.d/apache2 reload"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
## A note on modularity
|
111
|
+
|
112
|
+
A complete deployment manager (like Capistrano even if probably not as good as it is) can be easily built over *remoting*. Capistrano recipes can be ordinary rake tasks packed as gems. Plus various _deployment strategies_ can be assembled as dependencies of a main `deploy` task.
|
113
|
+
|
114
|
+
# Gemfile
|
115
|
+
gem 'remoting_scm_git' # provides 'remoting:scm:push, remoting:scm:update_remoting_code'
|
116
|
+
gem 'remoting_server_passenger' # provides 'remoting:server:restart'
|
117
|
+
|
118
|
+
# remoting.rake
|
119
|
+
desc "Deploy application on server"
|
120
|
+
task :deploy => ["remoting:scm:push", "remoting:scm:update_remoting_code", "remoting:bundle", "remoting:server:restart"] do
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
## Examples
|
125
|
+
|
126
|
+
You can find more examples under `examples` source directory
|
127
|
+
|
128
|
+
|
129
|
+
## Coming Soon
|
130
|
+
|
131
|
+
* Ability to define bunch of commands as functions
|
132
|
+
* Pre-packed strategies
|
133
|
+
|
134
|
+
---
|
135
|
+
|
136
|
+
Copyright (c) 2012 mcasimir
|
137
|
+
|
138
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
139
|
+
a copy of this software and associated documentation files (the
|
140
|
+
"Software"), to deal in the Software without restriction, including
|
141
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
142
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
143
|
+
permit persons to whom the Software is furnished to do so, subject to
|
144
|
+
the following conditions:
|
145
|
+
|
146
|
+
The above copyright notice and this permission notice shall be
|
147
|
+
included in all copies or substantial portions of the Software.
|
148
|
+
|
149
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
150
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
151
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
152
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
153
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
154
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
155
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
156
|
+
|
157
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "remoting"
|
18
|
+
gem.homepage = "http://github.com/mcasimir/remoting"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{Turn plain rake tasks in scripts to administer the server remote.}
|
21
|
+
gem.description = %Q{Remoting is a great way to turn plain rake tasks in scripts to administer the server remote. It provides a little framework to run remoting commands over SSH along with a DSL to define remoting scripts.}
|
22
|
+
gem.email = "maurizio.cas@gmail.com"
|
23
|
+
gem.authors = ["mcasimir"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.8
|
@@ -0,0 +1,243 @@
|
|
1
|
+
namespace :remote do
|
2
|
+
|
3
|
+
task :info do
|
4
|
+
require 'remoting/task'
|
5
|
+
|
6
|
+
remote('info', config.login) do
|
7
|
+
source "~/.profile"
|
8
|
+
source "$HOME/.rvm/scripts/rvm"
|
9
|
+
|
10
|
+
which :ruby
|
11
|
+
echo "RUBY VERSION: `ruby --version`"
|
12
|
+
echo "RUBYGEM VERSION: `gem --version`"
|
13
|
+
command "RVM_VER=`rvm --version`"
|
14
|
+
echo "RVM VERSION: $RVM_VER"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Setup git origin"
|
19
|
+
task :init do
|
20
|
+
require 'remoting/task'
|
21
|
+
|
22
|
+
local('init') do
|
23
|
+
git :init
|
24
|
+
git :remote, :add, :origin, config.repo
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "Initialize remote"
|
29
|
+
task :setup do
|
30
|
+
require 'remoting/task'
|
31
|
+
|
32
|
+
remote('setup', config.login) do
|
33
|
+
git :clone, config.repo, config.dest
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "Commit everything to remote git repository"
|
38
|
+
task :push, [:message] do |t, args|
|
39
|
+
require 'remoting/task'
|
40
|
+
|
41
|
+
message = args[:message] || "commit #{Time.now}"
|
42
|
+
|
43
|
+
local('push') do
|
44
|
+
git :add, "."
|
45
|
+
git :commit, "-a", "-m", "\"#{message}\""
|
46
|
+
git :push
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
desc "Update remote code pulling from repository"
|
51
|
+
task :pull_on_remote do
|
52
|
+
require 'remoting/task'
|
53
|
+
|
54
|
+
schema = config.dest.join('db', 'schema.rb')
|
55
|
+
tmp_schema = config.tmp.join("#{config.app}_#{Time.now.to_i}_schema.rb.tmp")
|
56
|
+
|
57
|
+
remote('pull_on_remote', config.login) do
|
58
|
+
cd config.dest
|
59
|
+
command("[[ -f \"#{schema}\" ]] && cp #{schema} #{tmp_schema}")
|
60
|
+
rm schema
|
61
|
+
git :checkout, 'db/schema.rb'
|
62
|
+
git :pull
|
63
|
+
command("[[ -f \"#{tmp_schema }\" ]] && mv #{tmp_schema} #{schema}")
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
desc "Restart the server"
|
69
|
+
task :restart do
|
70
|
+
require 'remoting/task'
|
71
|
+
|
72
|
+
remote('restart', config.login) do
|
73
|
+
mkdir '-p', config.dest.join('tmp')
|
74
|
+
touch config.dest.join('tmp', 'restart.txt')
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
desc "Hard reset repo on server"
|
80
|
+
task :reset do
|
81
|
+
require 'remoting/task'
|
82
|
+
|
83
|
+
remote('reset', config.login) do
|
84
|
+
cd config.dest
|
85
|
+
git :reset , "--hard HEAD"
|
86
|
+
git :clean, "-f", "-d"
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
desc "Run bundle install on the server"
|
92
|
+
task :bundle do
|
93
|
+
require 'remoting/task'
|
94
|
+
|
95
|
+
remote('bundle', config.login) do
|
96
|
+
source "~/.profile"
|
97
|
+
source "$HOME/.rvm/scripts/rvm"
|
98
|
+
rvm :use, config.ruby
|
99
|
+
|
100
|
+
cd config.dest
|
101
|
+
export "LANG=en_US.UTF-8"
|
102
|
+
command "RAILS_ENV=production", "bundle install", "--without development test", "--deployment"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
desc "Deploy application on server"
|
107
|
+
task :deploy => [:push, :pull_on_remote, :bundle, :restart] do
|
108
|
+
end
|
109
|
+
|
110
|
+
desc "Run rake tasks on server"
|
111
|
+
task :rake, [:invocation] do |t, args|
|
112
|
+
require 'remoting/task'
|
113
|
+
|
114
|
+
invocation = args[:invocation]
|
115
|
+
|
116
|
+
remote('rake', config.login, :interactive => true) do
|
117
|
+
source "$HOME/.rvm/scripts/rvm"
|
118
|
+
rvm :use, config.ruby
|
119
|
+
|
120
|
+
cd config.dest
|
121
|
+
command("RAILS_ENV=production bundle exec rake #{invocation}")
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
desc "Open a remote shell session on server"
|
127
|
+
task :ssh do
|
128
|
+
require 'remoting/task'
|
129
|
+
remote('ssh', config.login, :interactive => true) do
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
desc "Dump a remote logfile"
|
134
|
+
task :log, [:lines, :filename] do |t, args|
|
135
|
+
require 'remoting/task'
|
136
|
+
|
137
|
+
filename, lines = args.values_at(:lines, :filename)
|
138
|
+
filename ||= "production"
|
139
|
+
filename = "#{filename}.log" unless filename =~ /\.[a-z]+$/
|
140
|
+
|
141
|
+
lines ||= 100
|
142
|
+
|
143
|
+
remote('log', config.login) do
|
144
|
+
cd config.dest
|
145
|
+
tail "-#{lines} log/#{filename}"
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
task :logs => [:log] do
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
desc "Run tail -f on logfile"
|
154
|
+
task :logtail, [:filename] do |t, args|
|
155
|
+
require 'remoting/task'
|
156
|
+
|
157
|
+
filename= args[:filename]
|
158
|
+
filename ||= "production"
|
159
|
+
filename = "#{filename}.log" unless filename =~ /\.[a-z]+$/
|
160
|
+
|
161
|
+
remote('logtail', config.login) do
|
162
|
+
cd config.dest
|
163
|
+
tail "-f log/#{filename}"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
desc "Open a remote console"
|
168
|
+
task :console do
|
169
|
+
require 'remoting/task'
|
170
|
+
|
171
|
+
remote('console', config.login, :interactive => true) do
|
172
|
+
cd config.dest
|
173
|
+
source '$HOME/.rvm/scripts/rvm'
|
174
|
+
bundle :exec, "rails c production"
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
desc "Update crontab with whenever schedule"
|
179
|
+
task :whenever do
|
180
|
+
require 'remoting/task'
|
181
|
+
|
182
|
+
remote('whenever', config.login) do
|
183
|
+
cd config.dest
|
184
|
+
whenever "-w"
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
|
189
|
+
namespace :apache do
|
190
|
+
task :ensite do
|
191
|
+
require 'remoting/task'
|
192
|
+
remote('ensite', config.login, :interactive => true) do
|
193
|
+
cd "/etc/apache2/sites-enabled"
|
194
|
+
sudo "ln -s #{config.dest.join('config', 'apache.conf')} #{config.app}"
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
task :reload do
|
199
|
+
require 'remoting/task'
|
200
|
+
|
201
|
+
remote('reload', config.login, :interactive => true) do
|
202
|
+
sudo "/etc/init.d/apache2 reload"
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
207
|
+
|
208
|
+
namespace :assets do
|
209
|
+
|
210
|
+
desc 'Precompile assets'
|
211
|
+
task :precompile do
|
212
|
+
require 'remoting/task'
|
213
|
+
|
214
|
+
remote('rake assets:precompile', config.login) do
|
215
|
+
|
216
|
+
source "$HOME/.rvm/scripts/rvm"
|
217
|
+
rvm :use, config.ruby
|
218
|
+
cd config.dest
|
219
|
+
command("RAILS_ENV=production bundle exec rake assets:precompile")
|
220
|
+
echo 'restarting ...'
|
221
|
+
mkdir '-p', config.dest.join('tmp')
|
222
|
+
touch config.dest.join('tmp', 'restart.txt')
|
223
|
+
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
namespace :db do
|
229
|
+
|
230
|
+
desc "Migrate remote database"
|
231
|
+
task :migrate do |t, args|
|
232
|
+
require 'remoting/task'
|
233
|
+
|
234
|
+
remote('rake db:migrate', config.login) do
|
235
|
+
source "$HOME/.rvm/scripts/rvm"
|
236
|
+
rvm :use, config.ruby
|
237
|
+
cd config.dest
|
238
|
+
command("RAILS_ENV=production bundle exec rake db:migrate")
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
end
|
data/examples/remote.yml
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Remoting
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
def create_remote_yml
|
5
|
+
|
6
|
+
stub = <<-STUB
|
7
|
+
remote:
|
8
|
+
login: user@server
|
9
|
+
dest: /var/ror/myapp
|
10
|
+
repo: git@gitserver:myapp
|
11
|
+
ruby: 1.9.3
|
12
|
+
gemset: myapp
|
13
|
+
STUB
|
14
|
+
|
15
|
+
create_file "config/remote.yml", stub
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
module Remoting
|
5
|
+
class Config < OpenStruct
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
hash = YAML.load_file(Rails.root.join('config', 'remote.yml'))
|
9
|
+
super(hash["remote"])
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
def config
|
15
|
+
@config ||= Config.new
|
16
|
+
end
|
17
|
+
module_function :config
|
18
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'remoting/dsl/string'
|
2
|
+
|
3
|
+
module Remoting
|
4
|
+
module Dsl
|
5
|
+
|
6
|
+
class ScriptBuilder
|
7
|
+
shadow_methods = %w(gem cd chdir chmod chmod_R chown chown_R cmp compare_file compare_stream copy copy_entry copy_file copy_stream cp cp_r getwd identical? install link ln ln_s ln_sf makedirs mkdir mkdir_p mkpath move mv pwd remove remove_dir remove_entry remove_entry_secure remove_file rm rm_f rm_r rm_rf rmdir rmtree safe_unlink symlink touch uptodate?)
|
8
|
+
|
9
|
+
shadow_methods.each do |name|
|
10
|
+
define_method name do |*args|
|
11
|
+
self.command(name, *args)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def build(&block)
|
17
|
+
instance = self.new
|
18
|
+
instance.instance_eval(&block)
|
19
|
+
instance.commands
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize
|
24
|
+
@commands = []
|
25
|
+
end
|
26
|
+
|
27
|
+
def commands()
|
28
|
+
@commands.flatten.map! do |c|
|
29
|
+
c.split(/[\r\n]/).map{|l|
|
30
|
+
line = l.strip
|
31
|
+
line.empty? ? nil : line
|
32
|
+
}
|
33
|
+
end.flatten.compact.delete_if(&:empty?)
|
34
|
+
end
|
35
|
+
|
36
|
+
def command(*args)
|
37
|
+
cmd = args.map(&:to_s).join(" ")
|
38
|
+
@commands << cmd
|
39
|
+
cmd
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def method_missing(*args)
|
45
|
+
command(*args)
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class String
|
2
|
+
def > (arg)
|
3
|
+
self << " > " << "#{arg}"
|
4
|
+
arg.clear
|
5
|
+
self
|
6
|
+
end
|
7
|
+
|
8
|
+
def >> (arg)
|
9
|
+
self << " >> " << "#{arg}"
|
10
|
+
arg.clear
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def | (arg)
|
15
|
+
self << " | " << "#{arg}"
|
16
|
+
arg.clear
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def join(*args)
|
21
|
+
Pathname.new(self).join(*args).to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'remoting/commander'
|
2
|
+
|
3
|
+
module Remoting
|
4
|
+
class LocalCommander < Commander
|
5
|
+
|
6
|
+
#overrides
|
7
|
+
def do_exec(cmds)
|
8
|
+
local(cmds)
|
9
|
+
end
|
10
|
+
|
11
|
+
def local(cmds)
|
12
|
+
runline = cmds.map{|c| "#{c} 2>&1"}.join(";")
|
13
|
+
# puts "[LOCAL] Executing '#{runline}' ..."
|
14
|
+
puts `#{runline}`
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'remoting/commander'
|
2
|
+
require 'remoting/ssh'
|
3
|
+
|
4
|
+
module Remoting
|
5
|
+
class RemoteCommander < Commander
|
6
|
+
|
7
|
+
attr_reader :login, :interactive
|
8
|
+
def initialize(login, *args)
|
9
|
+
options = args.extract_options!
|
10
|
+
@login = login
|
11
|
+
@interactive = !!options[:interactive]
|
12
|
+
end
|
13
|
+
|
14
|
+
#overrides
|
15
|
+
def do_exec(cmds)
|
16
|
+
remote(cmds)
|
17
|
+
end
|
18
|
+
|
19
|
+
def remote(cmds)
|
20
|
+
user, host = login.split("@")
|
21
|
+
|
22
|
+
ssh = ::remoting::Ssh.new(
|
23
|
+
:user => user,
|
24
|
+
:host => host,
|
25
|
+
:interactive => interactive
|
26
|
+
)
|
27
|
+
|
28
|
+
ssh.exec(cmds)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
module Remoting
|
4
|
+
class Shell < Thor::Shell::Color
|
5
|
+
def ask_password(*args)
|
6
|
+
system "stty -echo"
|
7
|
+
res = ask(*args)
|
8
|
+
system "stty echo"
|
9
|
+
puts("\n")
|
10
|
+
res
|
11
|
+
end
|
12
|
+
|
13
|
+
def continue?(message)
|
14
|
+
res = yes?(message << " (y/yes)")
|
15
|
+
if !res
|
16
|
+
say("Cancelled", BLUE)
|
17
|
+
end
|
18
|
+
res
|
19
|
+
end
|
20
|
+
|
21
|
+
def bold(message)
|
22
|
+
say(message, BOLD)
|
23
|
+
end
|
24
|
+
|
25
|
+
def no?(message)
|
26
|
+
super(message << " (n/no)")
|
27
|
+
end
|
28
|
+
|
29
|
+
def success(message)
|
30
|
+
say(message, GREEN)
|
31
|
+
end
|
32
|
+
|
33
|
+
def error(message)
|
34
|
+
say(message, RED)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/remoting/ssh.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'net/ssh'
|
2
|
+
require 'remoting/shell'
|
3
|
+
|
4
|
+
module Remoting
|
5
|
+
class Ssh
|
6
|
+
attr_reader :host, :user
|
7
|
+
|
8
|
+
def initialize(*args)
|
9
|
+
options = args.extract_options!
|
10
|
+
@host, @user, @interactive = options.values_at(:host, :user, :interactive)
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
def shell
|
15
|
+
@shell ||= ::remoting::Shell.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def exec(commands)
|
19
|
+
|
20
|
+
if interactive?
|
21
|
+
ssh = %(ssh #{user}@#{host})
|
22
|
+
Kernel.exec ssh + %( -t '#{commands.join("; ")}') # this will replace the current process and will never return the shell back
|
23
|
+
else
|
24
|
+
Net::SSH.start(host, user) do |ssh|
|
25
|
+
|
26
|
+
ssh.open_channel do |channel|
|
27
|
+
channel.exec(commands.join(";")) do |ch, success|
|
28
|
+
unless success
|
29
|
+
abort
|
30
|
+
end
|
31
|
+
|
32
|
+
channel.on_data do |ch, data|
|
33
|
+
say "#{data}"
|
34
|
+
end
|
35
|
+
|
36
|
+
channel.on_extended_data do |ch, type, data|
|
37
|
+
shell.error "#{data}"
|
38
|
+
end
|
39
|
+
|
40
|
+
channel.on_close do |ch|
|
41
|
+
shell.bold "channel is closing!\n"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
ssh.loop
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end # ~ exec
|
51
|
+
|
52
|
+
def interactive?
|
53
|
+
!!@interactive
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'remoting/dsl/script_builder'
|
2
|
+
require 'remoting/local_commander'
|
3
|
+
require 'remoting/remoting_commander'
|
4
|
+
require 'remoting/shell'
|
5
|
+
|
6
|
+
module Remoting
|
7
|
+
module Task
|
8
|
+
|
9
|
+
def _remoting_task_included
|
10
|
+
end
|
11
|
+
|
12
|
+
def config
|
13
|
+
remoting.config
|
14
|
+
end
|
15
|
+
|
16
|
+
def local(name, *args, &block)
|
17
|
+
bold("Executing '#{name}' on local ...")
|
18
|
+
commands = ::remoting::Dsl::ScriptBuilder.build(&block)
|
19
|
+
commander = LocalCommander.new(*args)
|
20
|
+
run(commander, commands)
|
21
|
+
end
|
22
|
+
|
23
|
+
def remote(name, login, *args, &block)
|
24
|
+
bold("Executing '#{name}' on '#{login}' ...")
|
25
|
+
commands = ::remoting::Dsl::ScriptBuilder.build(&block)
|
26
|
+
commander = RemoteCommander.new(login, *args)
|
27
|
+
run(commander, commands)
|
28
|
+
end
|
29
|
+
|
30
|
+
def run(commander, commands)
|
31
|
+
commander.exec(commands)
|
32
|
+
end
|
33
|
+
|
34
|
+
def shell
|
35
|
+
@shell ||= ::remoting::Shell.new
|
36
|
+
end
|
37
|
+
|
38
|
+
%w(bold error success yes? no? say continue?).each do |meth|
|
39
|
+
eval("def #{meth}(*args);shell.#{meth}(*args);end")
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
unless self.respond_to?(:_remoting_task_included)
|
46
|
+
include remoting::Task
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
|
data/lib/remoting.rb
ADDED
data/remoting.gemspec
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "remoting"
|
8
|
+
s.version = "0.2.8"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["mcasimir"]
|
12
|
+
s.date = "2012-05-08"
|
13
|
+
s.description = "Remoting is a great way to turn plain rake tasks in scripts to administer the server remote. It provides a little framework to run remoting commands over SSH along with a DSL to define remoting scripts."
|
14
|
+
s.email = "maurizio.cas@gmail.com"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.md"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
"Gemfile",
|
21
|
+
"Gemfile.lock",
|
22
|
+
"LICENSE.txt",
|
23
|
+
"README.md",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"examples/remote.rake",
|
27
|
+
"examples/remote.yml",
|
28
|
+
"lib/generators/remoting/install_generator.rb",
|
29
|
+
"lib/remoting.rb",
|
30
|
+
"lib/remoting/commander.rb",
|
31
|
+
"lib/remoting/config.rb",
|
32
|
+
"lib/remoting/dsl/script_builder.rb",
|
33
|
+
"lib/remoting/dsl/string.rb",
|
34
|
+
"lib/remoting/engine.rb",
|
35
|
+
"lib/remoting/local_commander.rb",
|
36
|
+
"lib/remoting/remote_commander.rb",
|
37
|
+
"lib/remoting/shell.rb",
|
38
|
+
"lib/remoting/ssh.rb",
|
39
|
+
"lib/remoting/task.rb",
|
40
|
+
"remoting.gemspec"
|
41
|
+
]
|
42
|
+
s.homepage = "http://github.com/mcasimir/remoting"
|
43
|
+
s.licenses = ["MIT"]
|
44
|
+
s.require_paths = ["lib"]
|
45
|
+
s.rubygems_version = "1.8.24"
|
46
|
+
s.summary = "Turn plain rake tasks in scripts to administer the server remote."
|
47
|
+
|
48
|
+
if s.respond_to? :specification_version then
|
49
|
+
s.specification_version = 3
|
50
|
+
|
51
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
52
|
+
s.add_runtime_dependency(%q<rails>, ["~> 3.0"])
|
53
|
+
s.add_runtime_dependency(%q<net-ssh>, [">= 0"])
|
54
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
|
55
|
+
else
|
56
|
+
s.add_dependency(%q<rails>, ["~> 3.0"])
|
57
|
+
s.add_dependency(%q<net-ssh>, [">= 0"])
|
58
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
|
59
|
+
end
|
60
|
+
else
|
61
|
+
s.add_dependency(%q<rails>, ["~> 3.0"])
|
62
|
+
s.add_dependency(%q<net-ssh>, [">= 0"])
|
63
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
metadata
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: remoting
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.8
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- mcasimir
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-08 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rails
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '3.0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3.0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: net-ssh
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: jeweler
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.8.3
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.8.3
|
62
|
+
description: Remoting is a great way to turn plain rake tasks in scripts to administer
|
63
|
+
the server remote. It provides a little framework to run remoting commands over
|
64
|
+
SSH along with a DSL to define remoting scripts.
|
65
|
+
email: maurizio.cas@gmail.com
|
66
|
+
executables: []
|
67
|
+
extensions: []
|
68
|
+
extra_rdoc_files:
|
69
|
+
- LICENSE.txt
|
70
|
+
- README.md
|
71
|
+
files:
|
72
|
+
- Gemfile
|
73
|
+
- Gemfile.lock
|
74
|
+
- LICENSE.txt
|
75
|
+
- README.md
|
76
|
+
- Rakefile
|
77
|
+
- VERSION
|
78
|
+
- examples/remote.rake
|
79
|
+
- examples/remote.yml
|
80
|
+
- lib/generators/remoting/install_generator.rb
|
81
|
+
- lib/remoting.rb
|
82
|
+
- lib/remoting/commander.rb
|
83
|
+
- lib/remoting/config.rb
|
84
|
+
- lib/remoting/dsl/script_builder.rb
|
85
|
+
- lib/remoting/dsl/string.rb
|
86
|
+
- lib/remoting/engine.rb
|
87
|
+
- lib/remoting/local_commander.rb
|
88
|
+
- lib/remoting/remote_commander.rb
|
89
|
+
- lib/remoting/shell.rb
|
90
|
+
- lib/remoting/ssh.rb
|
91
|
+
- lib/remoting/task.rb
|
92
|
+
- remoting.gemspec
|
93
|
+
homepage: http://github.com/mcasimir/remoting
|
94
|
+
licenses:
|
95
|
+
- MIT
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options: []
|
98
|
+
require_paths:
|
99
|
+
- lib
|
100
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
none: false
|
102
|
+
requirements:
|
103
|
+
- - ! '>='
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
segments:
|
107
|
+
- 0
|
108
|
+
hash: -1608284933107565365
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ! '>='
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
requirements: []
|
116
|
+
rubyforge_project:
|
117
|
+
rubygems_version: 1.8.24
|
118
|
+
signing_key:
|
119
|
+
specification_version: 3
|
120
|
+
summary: Turn plain rake tasks in scripts to administer the server remote.
|
121
|
+
test_files: []
|