delayed_job-ssh_remote_worker 1.0.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f194bed80798938fa56694242c4b189775a1cb9c
4
+ data.tar.gz: 8781173a79be3b715016a9aecf1c6aaeca650172
5
+ SHA512:
6
+ metadata.gz: d1f1e47cc0c9106a5eb0138acf79288b9a55f6bd3eac58ae7d689a8382151cc98a817386908df2fb8c6f9a105a900f4e45e0f6135018ceaf0b1e101581b61020
7
+ data.tar.gz: d8848fd43a2e81f200840b552bf9f7bf8a29ce2a0a3b7dd03cac8f9c56a1c4b258e064e174c40340ef85ca122657ba811c6c117761110a7d8310918d6cfbf619
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in delayed_job-ssh_remote_worker.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Alex McHale
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # DelayedJob::SshRemoteWorker
2
+
3
+ This gem provides a rake task for executing DelayedJob backed by ActiveRecord
4
+ remotely over an SSH connection.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'delayed_job-ssh_remote_worker'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install delayed_job-ssh_remote_worker
19
+
20
+ ## Usage
21
+
22
+ Require the gem and either create a `config/remote_database.yml` file that
23
+ contains a record such as below:
24
+
25
+ ```yaml
26
+ production:
27
+ ssh_hostname: "example.com"
28
+ ssh_username: "app"
29
+ adapter: "postgresql"
30
+ encoding: "unicode"
31
+ database: "dbname"
32
+ username: "dbuser"
33
+ password: "pa$$word"
34
+ ```
35
+
36
+ Alternatively, the `ssh_hostname` and `ssh_username` can be simply added to an
37
+ entry in `config/database.yml`. You may specify the SSH port number as `ssh_port`.
38
+
39
+ The `config/remote_database.yml` top level keys can have names other than your
40
+ `Rails.env`. For example:
41
+
42
+ ```yaml
43
+ fast_server:
44
+ ssh_hostname: "example.com"
45
+ ssh_username: "app"
46
+ ssh_port: 20022
47
+ adapter: "postgresql"
48
+ encoding: "unicode"
49
+ database: "dbname"
50
+ username: "dbuser"
51
+ password: "pa$$word"
52
+
53
+ slow_server:
54
+ ssh_hostname: "example2.com"
55
+ ssh_username: "app"
56
+ adapter: "mysql"
57
+ encoding: "unicode"
58
+ database: "dbname"
59
+ username: "dbuser"
60
+ password: "pa$$word"
61
+ ```
62
+
63
+ The key can then be specified in `ENV['REMOTE_ENV']` thusly:
64
+
65
+ ```bash
66
+ RAILS_ENV=production REMOTE_ENV=fast_server bundle exec rake jobs:remote_workoff
67
+ ```
68
+
69
+ If `ENV['REMOTE_ENV']` is not set, `delayed_job-ssh_remote_worker` will default to `Rails.env`.
70
+
71
+ ## Contributing
72
+
73
+ 1. Fork it ( https://github.com/alexmchale/delayed_job-ssh_remote_worker/fork )
74
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
75
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
76
+ 4. Push to the branch (`git push origin my-new-feature`)
77
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'delayed/ssh_remote_worker/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+
9
+ spec.name = "delayed_job-ssh_remote_worker"
10
+ spec.version = DelayedJob::SshRemoteWorker::VERSION
11
+ spec.authors = ["Alex McHale"]
12
+ spec.email = ["alex@anticlever.com"]
13
+ spec.summary = %q{Run DelayedJob queues over SSH in a remote database}
14
+ spec.description = %q{Provides a few rake tasks to run DelayedJob jobs on a remote server over SSH}
15
+ spec.homepage = "http://github.com/alexmchale/delayed_job-ssh_remote_worker"
16
+ spec.license = "MIT"
17
+
18
+ spec.files = `git ls-files -z`.split("\x0")
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_runtime_dependency "delayed_job_active_record", ">= 3.0.0", "< 4.2.0"
24
+ spec.add_runtime_dependency "net-ssh-gateway", "~> 1.2"
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.6"
27
+ spec.add_development_dependency "rake", "~> 10.3"
28
+
29
+ end
@@ -0,0 +1,116 @@
1
+ require "delayed/ssh_remote_worker/version"
2
+ require "net/ssh/gateway"
3
+
4
+ module Delayed
5
+ class SshRemoteWorker
6
+
7
+ attr_reader :remote_ssh_username, :remote_ssh_hostname, :remote_ssh_port
8
+ attr_reader :remote_db_hostname, :remote_db_port
9
+ attr_reader :local_db_hostname, :local_db_port
10
+ attr_reader :gateway_ssh, :gateway_port
11
+ attr_reader :gateway_in_rd, :gateway_in_wr
12
+ attr_reader :gateway_out_rd, :gateway_out_wr
13
+ attr_reader :child
14
+ attr_reader :config
15
+
16
+ def initialize(config)
17
+ @config = Hash[config.map { |k, v| [ k.to_sym, v ] }]
18
+ @debug = !!@config[:ssh_debug]
19
+
20
+ @remote_ssh_username = @config[:ssh_username]
21
+ @remote_ssh_hostname = @config[:ssh_hostname]
22
+ @remote_ssh_port = @config[:ssh_port].to_i
23
+ @remote_ssh_port = 22 if remote_ssh_port <= 0
24
+
25
+ @remote_db_hostname = @config[:host].to_s.strip
26
+ @remote_db_hostname = "localhost" if remote_db_hostname == ""
27
+ @remote_db_port = @config[:port].to_i
28
+ @remote_db_port = default_port_number(@config[:adapter]) if remote_db_port <= 0
29
+
30
+ @local_db_hostname = "127.0.0.1"
31
+ @local_db_port = nil
32
+ end
33
+
34
+ def create_port_tunnel
35
+ # Create two pipes - one will be used to get the port number from the child
36
+ # process, the other will be used to tell the child process when it's time
37
+ # to exit.
38
+ ( @gateway_in_rd , @gateway_in_wr ) = IO.pipe
39
+ ( @gateway_out_rd , @gateway_out_wr ) = IO.pipe
40
+
41
+ # The child process will establish the SSH connection to the database server.
42
+ @child = fork {
43
+ debug "CHILD: Tunneling to #{ remote_db_hostname }:#{ remote_db_port } on #{ remote_ssh_username }@#{ remote_ssh_hostname }:#{ remote_ssh_port }."
44
+
45
+ @gateway_ssh = Net::SSH::Gateway.new(remote_ssh_hostname, remote_ssh_username, port: remote_ssh_port)
46
+ @gateway_port = gateway_ssh.open(remote_db_hostname, remote_db_port)
47
+
48
+ debug "CHILD: Notifying parent process of gateway port number #{ gateway_port }."
49
+
50
+ gateway_out_rd.close
51
+ gateway_out_wr.write(gateway_port.to_s)
52
+ gateway_out_wr.close
53
+
54
+ debug "CHILD: Waiting for parent to close pipe."
55
+
56
+ gateway_in_wr.close
57
+ gateway_in_rd.read
58
+ gateway_in_rd.close
59
+
60
+ debug "CHILD: Parent closed pipe. Exiting."
61
+
62
+ gateway_ssh.shutdown!
63
+ }
64
+
65
+ # Get the port number back from the child process once the SSH connection is established.
66
+ debug "PARENT: Reading port number from child."
67
+ gateway_out_wr.close
68
+ @local_db_port = Integer(gateway_out_rd.read)
69
+ gateway_out_rd.close
70
+
71
+ # Log and proceed with the next task.
72
+ debug "PARENT: Received port number #{ gateway_port } from child. Proceeding with execution."
73
+ end
74
+
75
+ def connect_to_tunneled_database
76
+ # Load just ActiveRecord. Do this before any part of the native Rails project is loaded.
77
+ require "active_record"
78
+
79
+ # Connect to the remote Postgres database.
80
+ ActiveRecord::Base.establish_connection(activerecord_config)
81
+
82
+ # Log a simple query just to verify that we actually have a connection.
83
+ debug "Connected to remote Postgres. Found #{ User.count } users in the remote database."
84
+ end
85
+
86
+ def destroy_port_tunnel
87
+ # Close the pipe with the gateway, indicating that it should close.
88
+ debug "PARENT: Closing pipe with child to terminate gateway."
89
+ gateway_in_wr.close
90
+ gateway_in_rd.close
91
+ Process.wait(child)
92
+ end
93
+
94
+ private
95
+
96
+ def default_port_number(adapter)
97
+ case adapter.to_s.strip
98
+ when /mysql/i then 3306
99
+ when /postgres/i then 5432
100
+ else raise "no known default port number for adapter #{ adapter.inspect }"
101
+ end
102
+ end
103
+
104
+ def activerecord_config
105
+ config.merge({
106
+ :host => local_db_hostname ,
107
+ :port => local_db_port ,
108
+ })
109
+ end
110
+
111
+ def debug(message)
112
+ @debug and puts(message)
113
+ end
114
+
115
+ end
116
+ end
@@ -0,0 +1,16 @@
1
+ require 'delayed/ssh_remote_worker'
2
+ require 'rails'
3
+
4
+ module Delayed
5
+ class SshRemoteWorker
6
+ class Railtie < Rails::Railtie
7
+
8
+ railtie_name :delayed_job_ssh_remote_worker
9
+
10
+ rake_tasks do
11
+ load "delayed/ssh_remote_worker/tasks.rb"
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,60 @@
1
+ namespace :jobs do
2
+
3
+ task :create_port_tunnel do
4
+ load_yaml = -> filename {
5
+ filename =
6
+ if defined?(Rails)
7
+ Rails.root.join("config", filename)
8
+ else
9
+ File.join("config", filename)
10
+ end
11
+
12
+ if File.file? filename
13
+ YAML.load File.read filename
14
+ end
15
+ }
16
+
17
+ get_hash = -> hash, key {
18
+ hash2 = hash[key.to_s.strip]
19
+
20
+ if hash2.kind_of? Hash
21
+ hash2
22
+ else
23
+ hash
24
+ end
25
+ }
26
+
27
+ config = load_yaml["remote_database.yml"] || load_yaml["database.yml"]
28
+ config = get_hash[config, ENV["REMOTE_ENV"]]
29
+ config = get_hash[config, Rails.env.to_s]
30
+
31
+ $ssh_remote_worker = Delayed::SshRemoteWorker.new(config)
32
+ $ssh_remote_worker and $ssh_remote_worker.create_port_tunnel
33
+ end
34
+
35
+ task :connect_to_tunneled_database do
36
+ $ssh_remote_worker and $ssh_remote_worker.connect_to_tunneled_database
37
+ end
38
+
39
+ task :destroy_port_tunnel do
40
+ $ssh_remote_worker and $ssh_remote_worker.destroy_port_tunnel
41
+ $ssh_remote_worker = nil
42
+ end
43
+
44
+ desc "Start a remote delayed_job worker"
45
+ task :remote_work => %w(
46
+ jobs:create_port_tunnel
47
+ jobs:connect_to_tunneled_database
48
+ jobs:work
49
+ jobs:destroy_port_tunnel
50
+ )
51
+
52
+ desc "Start a remote delayed_job worker and exit when all available jobs are complete"
53
+ task :remote_workoff => %w(
54
+ jobs:create_port_tunnel
55
+ jobs:connect_to_tunneled_database
56
+ jobs:workoff
57
+ jobs:destroy_port_tunnel
58
+ )
59
+
60
+ end
@@ -0,0 +1,7 @@
1
+ module DelayedJob
2
+ class SshRemoteWorker
3
+
4
+ VERSION = "1.0.0"
5
+
6
+ end
7
+ end
@@ -0,0 +1,2 @@
1
+ require "delayed/ssh_remote_worker"
2
+ require "delayed/ssh_remote_worker/railtie" if defined?(Rails)
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: delayed_job-ssh_remote_worker
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Alex McHale
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: delayed_job_active_record
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 3.0.0
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: 4.2.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 3.0.0
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: 4.2.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: net-ssh-gateway
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.2'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.2'
47
+ - !ruby/object:Gem::Dependency
48
+ name: bundler
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.6'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '1.6'
61
+ - !ruby/object:Gem::Dependency
62
+ name: rake
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '10.3'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '10.3'
75
+ description: Provides a few rake tasks to run DelayedJob jobs on a remote server over
76
+ SSH
77
+ email:
78
+ - alex@anticlever.com
79
+ executables: []
80
+ extensions: []
81
+ extra_rdoc_files: []
82
+ files:
83
+ - ".gitignore"
84
+ - Gemfile
85
+ - LICENSE.txt
86
+ - README.md
87
+ - Rakefile
88
+ - delayed_job-ssh_remote_worker.gemspec
89
+ - lib/delayed/ssh_remote_worker.rb
90
+ - lib/delayed/ssh_remote_worker/railtie.rb
91
+ - lib/delayed/ssh_remote_worker/tasks.rb
92
+ - lib/delayed/ssh_remote_worker/version.rb
93
+ - lib/delayed_job-ssh_remote_worker.rb
94
+ homepage: http://github.com/alexmchale/delayed_job-ssh_remote_worker
95
+ licenses:
96
+ - MIT
97
+ metadata: {}
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubyforge_project:
114
+ rubygems_version: 2.2.2
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: Run DelayedJob queues over SSH in a remote database
118
+ test_files: []