dblink 0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3b0e7af330863d700229caf232c3c2ae55931b42
4
+ data.tar.gz: bb6ab4186a21d60076e51bd484ffc3f2be908b9a
5
+ SHA512:
6
+ metadata.gz: 4316a3ab2414ee53970ef3a21c49996448f93744e2d9d720f332bfaa9202d872568b32b447ae2044a064b15453371cdc96226e453f83c8e618741b7eb79b7058
7
+ data.tar.gz: ecbb1c23a0b4aac78ebe3358cd4f5af84420e767392a7c0be7db375c5fc4dc60c38cff05e8cf1a8aab26880cc932d04fe36920d02d96b04d3dbe56430b4d120c
@@ -0,0 +1,189 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'socket'
4
+ require 'open3'
5
+ require 'tempfile'
6
+ require 'erb'
7
+ require 'securerandom'
8
+ require 'json'
9
+ require 'optparse'
10
+ require 'fileutils'
11
+
12
+ BASE_DIR = File.expand_path(File.dirname(__FILE__) + '/..')
13
+
14
+ require BASE_DIR + "/lib/dblink/network"
15
+ require BASE_DIR + "/lib/dblink/system"
16
+ require BASE_DIR + "/lib/dblink/pg_bouncer_runner"
17
+ require BASE_DIR + "/lib/dblink/tonnel_runner"
18
+ require BASE_DIR + "/lib/dblink/psql_runner"
19
+ require BASE_DIR + "/lib/dblink/web_service"
20
+ require BASE_DIR + "/lib/dblink/color"
21
+
22
+ PUBLIC_HOST = 'dblink.tk'
23
+
24
+ CLI_OPTS = {
25
+ verbose: false,
26
+ host: 'localhost',
27
+ port: 5432,
28
+ user: ENV['USER'],
29
+ database: ENV['USER'],
30
+ check_local: true,
31
+ check_tonnel: true
32
+ }
33
+
34
+ OptionParser.new do |opts|
35
+ opts.banner = "Usage: dblink [options]"
36
+
37
+ opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
38
+ CLI_OPTS[:verbose] = v
39
+ end
40
+
41
+ opts.on("-H", "--host [HOST]", "PostgreSQL host", "Default: localhost") do |value|
42
+ CLI_OPTS[:host] = value
43
+ end
44
+
45
+ opts.on("-p", "--port [PORT]", "PostgreSQL port", "Default: 5432") do |value|
46
+ CLI_OPTS[:port] = value
47
+ end
48
+
49
+ opts.on("-d", "--database [DATABASE]", "PostgreSQL database", "Default: #{ENV['USER']}") do |value|
50
+ CLI_OPTS[:database] = value
51
+ end
52
+
53
+ opts.on("-u", "--user [USER]", "User to connect to local PostgreSQL server", "Default: #{ENV['USER']}") do |value|
54
+ CLI_OPTS[:user] = value
55
+ end
56
+
57
+ opts.on("-P", "--password [PASSWORD]", "PostgreSQL password") do |value|
58
+ CLI_OPTS[:password] = value
59
+ end
60
+
61
+ opts.on("-cl", "--[no-]check-local", "Default true. Check connection to local PostgreSQL server") do |value|
62
+ CLI_OPTS[:check_local] = value
63
+ end
64
+
65
+ opts.on("-cr", "--[no-]check-remote", "Default true. Check connection via ssh tonnel") do |value|
66
+ CLI_OPTS[:check_tonnel] = value
67
+ end
68
+
69
+ opts.on_tail("-h", "--help", "Show this message") do
70
+ puts opts
71
+ exit
72
+ end
73
+
74
+ end.parse!
75
+
76
+ #p BASE_DIR
77
+
78
+ if CLI_OPTS[:check_local]
79
+ print "Checking connection to "
80
+ print "#{CLI_OPTS[:host]}:#{CLI_OPTS[:port]}".underline
81
+
82
+ result = PsqlRunner.check_connection(CLI_OPTS)
83
+
84
+ print " - "
85
+ puts result === true ? "OK".green : "FAILED".red
86
+
87
+ if result != true
88
+ puts
89
+ puts result
90
+ puts
91
+
92
+ exit(1)
93
+ end
94
+ end
95
+
96
+ pgb_runner = PgBouncerRunner.new(
97
+ pg_host: CLI_OPTS[:host],
98
+ pg_port: CLI_OPTS[:port],
99
+ pg_user: CLI_OPTS[:user],
100
+ pg_password: CLI_OPTS[:password],
101
+ pg_db: CLI_OPTS[:database],
102
+ verbose: CLI_OPTS[:verbose]
103
+ )
104
+
105
+ print "Creating configs in /tmp folder"
106
+ pgb_runner.create_config
107
+ puts " - " + "OK".green
108
+
109
+ if CLI_OPTS[:verbose]
110
+ puts "Config folder: #{pgb_runner.tmp_folder}"
111
+ end
112
+
113
+ print "Starting pgbouncer "
114
+ pgb_runner.run_async
115
+ pgb_pid = pgb_runner.wait_for_pid
116
+ puts "- " + "OK".green + " (pid: #{pgb_pid})"
117
+
118
+ print "Starting SSH tonnel "
119
+ tonnel = TonnelRunner.new(pgb_runner.pgb_port, tmp_dir: pgb_runner.tmp_folder, verbose: CLI_OPTS[:verbose])
120
+ tonnel.run_async
121
+ tonnel.wait_remote_port_allocated
122
+
123
+ puts "- " + "OK".green + " (pid: #{tonnel.runner_pid})"
124
+ puts "Remote port: #{tonnel.remote_port}"
125
+
126
+ psql_opt = {
127
+ user: pgb_runner.pgb_user,
128
+ password: pgb_runner.pgb_password,
129
+ database: pgb_runner.pg_db,
130
+ port: tonnel.remote_port,
131
+ host: PUBLIC_HOST,
132
+ verbose: CLI_OPTS[:verbose]
133
+ }
134
+
135
+ if CLI_OPTS[:check_tonnel]
136
+ print "Checking connection: "
137
+ result = PsqlRunner.check_connection(psql_opt)
138
+ puts result === true ? "OK".green : "FAILED".red
139
+
140
+ if result != true
141
+ puts
142
+ puts result
143
+ puts
144
+ end
145
+ end
146
+
147
+ db_url = pgb_runner.make_db_url(tonnel.remote_port)
148
+
149
+ puts
150
+ puts "DATABSE CONNECTION:"
151
+ puts " #{db_url}"
152
+ puts
153
+
154
+ psql_path = PsqlRunner.find_psql
155
+ if psql_path
156
+ puts "CONNECT WITH PSQL:"
157
+ passwd = pgb_runner.pgb_password == '' ? '' : "PGPASSWORD=#{pgb_runner.pgb_password}"
158
+ puts " #{passwd} #{psql_path} -h dblink.tk -p #{tonnel.remote_port} -U #{pgb_runner.pgb_user} #{pgb_runner.pg_db}"
159
+ puts
160
+ end
161
+
162
+ web_response = WebService.register_link(db_url, verbose: CLI_OPTS[:verbose])
163
+
164
+ if web_response['status'] == 'success'
165
+ puts "WEB URL:"
166
+ puts " #{web_response['web_url']}"
167
+ puts
168
+ end
169
+
170
+ at_exit do
171
+ print "Stoping pgbouncer ..."
172
+ pgb_runner.stop_async
173
+ puts
174
+ print "Stoping ssh ..."
175
+ tonnel.stop_async
176
+ puts
177
+
178
+ tonnel.runner_thread.kill
179
+
180
+ puts "Removing tmp dir ..."
181
+ FileUtils.rm_rf(pgb_runner.tmp_folder)
182
+
183
+ exit!
184
+ end
185
+
186
+ tonnel.runner_thread.value
187
+
188
+ #ssh_command = SSH_TONNEL_COMMAND.gsub('{{local_port}}', '6543')
189
+ #system ssh_command
@@ -0,0 +1,13 @@
1
+ [databases]
2
+ <%= pg_db %> = host=<%= pg_host %> port=<%= pg_port %> dbname=<%= pg_db %> user=<%= pg_user %> <%= pg_password && pg_password != '' ? "password=#{pg_password}" : '' %>
3
+
4
+ [pgbouncer]
5
+ pool_mode = session
6
+ listen_port = <%= pgb_port %>
7
+ listen_addr = 127.0.0.1
8
+ auth_type = plain
9
+ auth_file = ./users.txt
10
+ logfile = pgbouncer.log
11
+ pidfile = pgbouncer.pid
12
+ admin_users = someuser
13
+ stats_users = stat_collector
@@ -0,0 +1,16 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "dblink"
3
+ s.version = "0.2"
4
+ s.author = ["Pavel Evstigneev"]
5
+ s.description= "CLI utility to share access to your local PostgreSQL server"
6
+ s.email = ["pavel.evst@gmail.com"]
7
+ s.homepage = "http://dblink.r15.railsrumble.com"
8
+ s.summary = %q{Veritrans ruby library}
9
+ s.license = 'MIT'
10
+
11
+ s.files = `git ls-files`.split("\n")
12
+ s.test_files = []
13
+
14
+ s.require_paths = ["lib"]
15
+ s.executables = ["dblink"]
16
+ end
@@ -0,0 +1,25 @@
1
+ class String
2
+ def black; "\e[30m#{self}\e[0m" end
3
+ def red; "\e[31m#{self}\e[0m" end
4
+ def green; "\e[32m#{self}\e[0m" end
5
+ def brown; "\e[33m#{self}\e[0m" end
6
+ def blue; "\e[34m#{self}\e[0m" end
7
+ def magenta; "\e[35m#{self}\e[0m" end
8
+ def cyan; "\e[36m#{self}\e[0m" end
9
+ def gray; "\e[37m#{self}\e[0m" end
10
+
11
+ def bg_black; "\e[40m#{self}\e[0m" end
12
+ def bg_red; "\e[41m#{self}\e[0m" end
13
+ def bg_green; "\e[42m#{self}\e[0m" end
14
+ def bg_brown; "\e[43m#{self}\e[0m" end
15
+ def bg_blue; "\e[44m#{self}\e[0m" end
16
+ def bg_magenta; "\e[45m#{self}\e[0m" end
17
+ def bg_cyan; "\e[46m#{self}\e[0m" end
18
+ def bg_gray; "\e[47m#{self}\e[0m" end
19
+
20
+ def bold; "\e[1m#{self}\e[22m" end
21
+ def italic; "\e[3m#{self}\e[23m" end
22
+ def underline; "\e[4m#{self}\e[24m" end
23
+ def blink; "\e[5m#{self}\e[25m" end
24
+ def reverse_color; "\e[7m#{self}\e[27m" end
25
+ end
@@ -0,0 +1,10 @@
1
+ module Network
2
+
3
+ def self.find_available_port
4
+ server = TCPServer.new('127.0.0.1', 0)
5
+ server.addr[1]
6
+ ensure
7
+ server.close if server
8
+ end
9
+
10
+ end
@@ -0,0 +1,124 @@
1
+ class PgBouncerRunner
2
+ attr_reader :pg_port, :pg_user, :pg_password, :pg_host, :pg_db
3
+ attr_reader :pgb_port, :pgb_user, :pgb_password
4
+ attr_reader :tmp_folder, :runner_thread, :runner_pid
5
+
6
+ def initialize(pg_port: 5432, pg_user: ENV['USER'], pg_password: '', pg_host: '127.0.0.1', pg_db: ENV['USER'], verbose: true)
7
+ @pg_port = pg_port
8
+ @pg_user = pg_user
9
+ @pg_password = pg_password
10
+ @pg_host = pg_host
11
+ @pg_db = pg_db
12
+ @verbose = verbose
13
+
14
+ @pgb_port = Network.find_available_port
15
+ end
16
+
17
+ def run
18
+ create_config unless @tmp_folder
19
+
20
+ verbose_arg = @verbose ? '-v' : ''
21
+ pgb_command = "#{pgbouncer_path} #{verbose_arg} ./config.ini"
22
+
23
+ if @verbose
24
+ puts "Running pgbouncer with config at: #{@tmp_folder}"
25
+ puts "EXEC #{pgb_command}"
26
+ end
27
+
28
+ Dir.chdir(@tmp_folder) do
29
+ Open3.popen3(pgb_command) {|stdin, stdout, stderr, wait_thr|
30
+ @runner_pid = wait_thr.pid # pid of the started process.
31
+ #p "process_started: #{pid}"
32
+ Thread.new do
33
+ begin
34
+ while line = stdout.gets
35
+ puts "STDOUT: #{line}" if @verbose
36
+ end
37
+ rescue Exception => error
38
+ puts error.message
39
+ puts error.backtrace
40
+ end
41
+ end
42
+ Thread.new do
43
+ begin
44
+ while line = stderr.gets
45
+ puts "STDERR: #{line}" if @verbose
46
+ end
47
+ rescue Exception => error
48
+ puts error.message
49
+ puts error.backtrace
50
+ end
51
+ end
52
+ exit_status = wait_thr.value # Process::Status object returned.
53
+ puts "pgbouncer stoped: #{exit_status}" if @verbose
54
+ }
55
+ end
56
+ end
57
+
58
+ def pgbouncer_path
59
+ if RUBY_PLATFORM =~ /darwin/
60
+ BASE_DIR + '/pgbouncer'
61
+ else
62
+
63
+ path = `which pgbouncer 2>/dev/null`
64
+ if path == ''
65
+ puts "Can not find pgbouncer in your system"
66
+ puts "Please install it"
67
+ exit(1)
68
+ else
69
+ return path
70
+ end
71
+
72
+ end
73
+ end
74
+
75
+ def stop_async
76
+ if @runner_pid && System.process_alive?(@runner_pid, verbose: @verbose)
77
+ System.stop_process(@runner_pid)
78
+ end
79
+ end
80
+
81
+ def run_async
82
+ @runner_thread = Thread.new do
83
+ begin
84
+ run
85
+ rescue Exception => error
86
+ puts error.message
87
+ puts error.backtrace
88
+ end
89
+ end
90
+
91
+ self
92
+ end
93
+
94
+ def wait_for_pid
95
+ while !@runner_pid
96
+ sleep 0.04
97
+ end
98
+
99
+ @runner_pid
100
+ end
101
+
102
+ def create_config
103
+ @tmp_folder = Dir.mktmpdir
104
+ pgb_config = render_template('config.ini.erb', {})
105
+ File.open(@tmp_folder + '/config.ini', 'w') {|f| f.write(pgb_config) }
106
+
107
+ @pgb_user = "share"
108
+ @pgb_password = SecureRandom.hex(10)
109
+ File.open(@tmp_folder + '/users.txt', 'w') {|f|
110
+ f.write(%{"#{@pgb_user}" "#{@pgb_password}"})
111
+ }
112
+ end
113
+
114
+ def make_db_url(remote_port)
115
+ "postgres://#{pgb_user}:#{pgb_password}@dblink.tk:#{remote_port}/#{pg_db}"
116
+ end
117
+
118
+ private
119
+ def render_template(file, params)
120
+ erb = ERB.new(File.read(file))
121
+ erb.filename = file
122
+ erb.result(binding)
123
+ end
124
+ end
@@ -0,0 +1,48 @@
1
+ module PsqlRunner
2
+ extend self
3
+
4
+ def check_connection(opt = {})
5
+ psql_path = find_psql
6
+
7
+ unless psql_path
8
+ result = "Can not find #{'psql'.bold} in your system\n"
9
+ if RUBY_PLATFORM =~ /darwin/
10
+ result += "Please run 'brew install postgres' or download it from http://postgresapp.com"
11
+ else
12
+ result += "Please install postgresql package in your system"
13
+ end
14
+ result += "\nOr disable connection checking (--no-check-local and --no-check-remote)"
15
+
16
+ return result
17
+ end
18
+
19
+ passwd = opt[:password] && opt[:password] == '' ? '' : "PGPASSWORD=#{opt[:password]}"
20
+
21
+ psql_command = "#{passwd} #{psql_path} -h #{opt[:host]} -p #{opt[:port]} -U #{opt[:user]} #{opt[:database]} -c 'select now()'"
22
+
23
+ if opt[:verbose]
24
+ puts "EXEC #{psql_command}"
25
+ end
26
+
27
+ result = %x(#{psql_command} 2>&1)
28
+
29
+ #unless result.include?('(1 row)')
30
+ # puts result
31
+ #end
32
+
33
+ result.include?('(1 row)') ? true : result
34
+ end
35
+
36
+ def self.find_psql
37
+ path = `which psql`
38
+
39
+ if path != ''
40
+ path = 'psql'
41
+ elsif RUBY_PLATFORM =~ /darwin/
42
+ paths = Dir.glob('/Applications/Postgres.app/Contents/Versions/**/psql')
43
+ path = paths.last if paths.size > 0
44
+ end
45
+
46
+ path == '' ? nil : path
47
+ end
48
+ end
@@ -0,0 +1,24 @@
1
+ module System
2
+
3
+ def self.process_alive?(pid, verbose: true)
4
+ begin
5
+ Process.kill(0, pid)
6
+ return true
7
+ rescue Errno::EPERM # changed uid
8
+ puts "No permission to query #{pid}!" if verbose
9
+ rescue Errno::ESRCH
10
+ puts "#{pid} is NOT running." if verbose # or zombied
11
+ rescue
12
+ puts "Unable to determine status for #{pid} : #{$!}" if verbose
13
+ end
14
+ return false
15
+ end
16
+
17
+ def self.stop_process(pid)
18
+ Process.kill('INT', pid)
19
+ while process_alive?(pid, verbose: CLI_OPTS[:verbose])
20
+ print "."
21
+ sleep 0.3
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,90 @@
1
+ class TonnelRunner
2
+ SSH_TONNEL_COMMAND = "ssh -N -R 0.0.0.0:0:localhost:{{local_port}} -i {{pem}} -o StrictHostKeyChecking=no share@dblink.tk"
3
+ PEM_FILE = "#{BASE_DIR}/share.pem"
4
+
5
+ attr_reader :local_port, :remote_port, :runner_thread, :runner_pid
6
+
7
+ def initialize(local_port, tmp_dir:, verbose: true)
8
+ @local_port = local_port.to_i
9
+ @verbose = verbose
10
+ @tmp_dir = tmp_dir
11
+ end
12
+
13
+ def run
14
+ ssh_command = SSH_TONNEL_COMMAND.gsub('{{local_port}}', @local_port.to_s)
15
+
16
+ puts "Copying pem file to tmp folder" if @verbose
17
+
18
+ tmp_pem = @tmp_dir + '/share.pem'
19
+ File.open(tmp_pem, 'w') do |file|
20
+ file.write(File.read(PEM_FILE))
21
+ end
22
+ File.chmod(0600, tmp_pem)
23
+
24
+ ssh_command.gsub!('{{pem}}', tmp_pem)
25
+
26
+ if @verbose
27
+ puts "EXEC #{ssh_command}"
28
+ end
29
+ Open3.popen3(ssh_command) {|stdin, stdout, stderr, wait_thr|
30
+ @runner_pid = wait_thr.pid # pid of the started process.
31
+ #p "process_started: #{pid}"
32
+ Thread.new do
33
+ begin
34
+ while line = stdout.gets
35
+ puts "STDOUT: #{line}" if @verbose
36
+ end
37
+ rescue Exception => error
38
+ puts error.message
39
+ puts error.backtrace
40
+ end
41
+ end
42
+ Thread.new do
43
+ begin
44
+ while line = stderr.gets
45
+ #puts "STDERR: #{line}"
46
+ if line =~ /Allocated port/
47
+ @remote_port = line.match(/Allocated port (\d+)\s/)[1].to_i
48
+ #puts "Remote port: #{@remote_port}"
49
+ end
50
+ end
51
+ rescue Exception => error
52
+ puts error.message
53
+ puts error.backtrace
54
+ end
55
+ end
56
+ exit_status = wait_thr.value # Process::Status object returned.
57
+ puts "SSH tonnel: process stoped: #{exit_status}" if @verbose
58
+ }
59
+
60
+ self
61
+ end
62
+
63
+ def run_async
64
+ @runner_thread = Thread.new do
65
+ begin
66
+ run
67
+ rescue Exception => error
68
+ puts error.message
69
+ puts error.backtrace
70
+ end
71
+ end
72
+
73
+ self
74
+ end
75
+
76
+ def stop_async
77
+ if @runner_pid && System.process_alive?(@runner_pid, verbose: @verbose)
78
+ System.stop_process(@runner_pid)
79
+ end
80
+ end
81
+
82
+ def wait_remote_port_allocated
83
+ while @remote_port.nil?
84
+ #print '.'
85
+ sleep 0.1
86
+ end
87
+
88
+ @remote_port
89
+ end
90
+ end
@@ -0,0 +1,34 @@
1
+ module WebService
2
+ extend self
3
+
4
+ #SERVICE_URL = "http://localhost:3000/dblinks"
5
+ SERVICE_URL = "http://dblink.r15.railsrumble.com/dblinks"
6
+
7
+ def register_link(database_url, verbose: false)
8
+ require 'uri'
9
+ require 'net/http'
10
+
11
+ uri = URI(SERVICE_URL)
12
+ http = Net::HTTP.new(uri.host, uri.port)
13
+ request = Net::HTTP::Post.new(uri.path)
14
+
15
+ params = {
16
+ database_url: database_url
17
+ }
18
+
19
+ if verbose
20
+ puts "HTTP POST: #{SERVICE_URL} #{JSON.generate(params)}"
21
+ end
22
+
23
+ response = http.post(uri.path, URI.encode_www_form(params))
24
+
25
+ if verbose
26
+ puts response.class
27
+ puts response.body
28
+ end
29
+
30
+ response_json = JSON.parse(response.body)
31
+ response_json
32
+ end
33
+
34
+ end
Binary file
@@ -0,0 +1,27 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIIEpQIBAAKCAQEA0Obx6lLUY/tgzQ2RJex95iwzm19iyfWHvQ6MA9syRyaDjiyS
3
+ +0We5xtJeX+jdi+oI18CFgNMklWj3/PXD3/MDGKNTIlGXAfBLK3VjqyQlHch+jAL
4
+ PI6kZvMMcWVIlg2eCMxeIeoT1cmYbemoEWNltmzd4i+w7C9qUKPktORhlWuGp6Aj
5
+ kBmr8K7zFqvO5dQCeOowvmwvNvU106xc+YolIYvQc3cPqgWgqP3Q1ejg3JfzglZr
6
+ Z4kl/znCtdOoyGMNyq5V5XtJ6wq597BnXFO48mM4i8nwODoQM8itGEmIJJbgfzdw
7
+ 5TwKLVODqNRfw1nECUe0rHiK/75rdKvrJiiB6QIDAQABAoIBAGUsNGWEEBEMIemt
8
+ dGqliqP7LFNHcxTUsRTDAtSrSEJlSLmGpPjE0xyifoc1ZflLQ2c+EEiQ+Hi2uVMx
9
+ SSrcffpRkJVMtqLDrq7w0cjzkmIVAIOm2QpPGxgxBgm1P95MYglo0P4j289if0xc
10
+ KWWiehRLzXpKFqmMnTTI628gXJJ8TQ575UsxOeJ0xTw255XhSYcxmkNOArfHstiI
11
+ Y6kRS2h0wE+KWwLeBn2UTsmpUpqxYRiVlq4yydhd5yWZpgV1RD7AtpOuJ8g8fDRI
12
+ 9PCnXZaLFGawy2bmpsYHxod4pkSlKStJVwV0Z3cY8TPQ+iUy0rv9LtBantcsQBlc
13
+ sJjK8AECgYEA5/G+/Gw/HPgUH+BlKKJoYAtYXmjx9i18b97KuBfqm8JrHOrl3H2U
14
+ AT0VTOrF04/eVER5l822gL3bPhGOYh/8qmPytzxyx8xLWh4rJYAQxN8U5G2A8O+Y
15
+ Gr5NykIK9cRwr2cVOXVmuN5oRIxWdd+KpF2iUgKI/IUM9uLN+MF3q2kCgYEA5pFq
16
+ ZdUtqDPhlBEsY8PIz/Isif6wqjr5gp+mqtaMsRJ4vQxmqGeB53dOde7g4VOIU8PC
17
+ 1Ee0MJHuBiVYUE+3lA1scBISpJbK8/V7gRTIRlQVO658upFeAFNkAfnWD4rN6G+0
18
+ gbbIRrr2JhHcKvHunLIhovMow4k37gYRnW9n0oECgYEA0w2EjcgpvcB2/3J+WfU+
19
+ KHbqWC4CTdGh82G08MLCdiz4rn2H35RdQqtEYJMYo6O72M3eHqXPNWKMxvPOrbcR
20
+ gDImP1m/z9IzlrLw69SWba3YIusJczNxIpSb0Dk8I9o190VDaN9NM1cdZZKVcfiQ
21
+ /XM+KoWoBK9E1roWVg4lSFECgYEAmz3Bo7r7OMtl0OoXNzz1kn1+W5Nuo899e+O+
22
+ tjwrEnZbcP5OiIjYwF5mJ6WlKFGz8qJWJdP5kNJQrzap1bk246p+Hp8sikE1eTkJ
23
+ 5Ql3J1Mp0LtVI9EIt7NuHJ548JIGvb+oi8Xj5yuu3EceNJQcksilOS/7fFyBmfPg
24
+ HF6MSwECgYEAx/K84j3mE7sO+CRpjjSZyXw+ETKOhA2f1QogpHIn9/vhztAynj4g
25
+ dn6j3SntqoMK3DNK8LbPzBoKlPr+Y3IOSTgSpN1RGQTp61ikrIG3K+N7vav382PZ
26
+ tyv7MiEyLATbci1VExU/pn3Qvcv6s89fzR3ThWX3UlyC6c+uO0qIaFs=
27
+ -----END RSA PRIVATE KEY-----
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dblink
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.2'
5
+ platform: ruby
6
+ authors:
7
+ - Pavel Evstigneev
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-11-08 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: CLI utility to share access to your local PostgreSQL server
14
+ email:
15
+ - pavel.evst@gmail.com
16
+ executables:
17
+ - dblink
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - bin/dblink
22
+ - config.ini.erb
23
+ - dblink.gemspec
24
+ - lib/dblink/color.rb
25
+ - lib/dblink/network.rb
26
+ - lib/dblink/pg_bouncer_runner.rb
27
+ - lib/dblink/psql_runner.rb
28
+ - lib/dblink/system.rb
29
+ - lib/dblink/tonnel_runner.rb
30
+ - lib/dblink/web_service.rb
31
+ - pgbouncer
32
+ - share.pem
33
+ homepage: http://dblink.r15.railsrumble.com
34
+ licenses:
35
+ - MIT
36
+ metadata: {}
37
+ post_install_message:
38
+ rdoc_options: []
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ required_rubygems_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ requirements: []
52
+ rubyforge_project:
53
+ rubygems_version: 2.4.5.1
54
+ signing_key:
55
+ specification_version: 4
56
+ summary: Veritrans ruby library
57
+ test_files: []