dblink 0.2

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.
@@ -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: []