#!/usr/bin/env ruby require 'socket' require 'open3' require 'tempfile' require 'erb' require 'securerandom' require 'json' require 'optparse' require 'fileutils' BASE_DIR = File.expand_path(File.dirname(__FILE__) + '/..') require BASE_DIR + "/lib/dblink/network" require BASE_DIR + "/lib/dblink/system" require BASE_DIR + "/lib/dblink/pg_bouncer_runner" require BASE_DIR + "/lib/dblink/tonnel_runner" require BASE_DIR + "/lib/dblink/psql_runner" require BASE_DIR + "/lib/dblink/web_service" require BASE_DIR + "/lib/dblink/color" PUBLIC_HOST = 'dblink.tk' CLI_OPTS = { verbose: false, host: 'localhost', port: 5432, user: ENV['USER'], database: ENV['USER'], check_local: true, check_tonnel: true } OptionParser.new do |opts| opts.banner = "Usage: dblink [options]" opts.on("-v", "--[no-]verbose", "Run verbosely") do |v| CLI_OPTS[:verbose] = v end opts.on("-H", "--host [HOST]", "PostgreSQL host", "Default: localhost") do |value| CLI_OPTS[:host] = value end opts.on("-p", "--port [PORT]", "PostgreSQL port", "Default: 5432") do |value| CLI_OPTS[:port] = value end opts.on("-d", "--database [DATABASE]", "PostgreSQL database", "Default: #{ENV['USER']}") do |value| CLI_OPTS[:database] = value end opts.on("-u", "--user [USER]", "User to connect to local PostgreSQL server", "Default: #{ENV['USER']}") do |value| CLI_OPTS[:user] = value end opts.on("-P", "--password [PASSWORD]", "PostgreSQL password") do |value| CLI_OPTS[:password] = value end opts.on("-cl", "--[no-]check-local", "Default true. Check connection to local PostgreSQL server") do |value| CLI_OPTS[:check_local] = value end opts.on("-cr", "--[no-]check-remote", "Default true. Check connection via ssh tonnel") do |value| CLI_OPTS[:check_tonnel] = value end opts.on_tail("-h", "--help", "Show this message") do puts opts exit end end.parse! #p BASE_DIR if CLI_OPTS[:check_local] print "Checking connection to " print "#{CLI_OPTS[:host]}:#{CLI_OPTS[:port]}".underline result = PsqlRunner.check_connection(CLI_OPTS) print " - " puts result === true ? "OK".green : "FAILED".red if result != true puts puts result puts exit(1) end end pgb_runner = PgBouncerRunner.new( pg_host: CLI_OPTS[:host], pg_port: CLI_OPTS[:port], pg_user: CLI_OPTS[:user], pg_password: CLI_OPTS[:password], pg_db: CLI_OPTS[:database], verbose: CLI_OPTS[:verbose] ) print "Creating configs in /tmp folder" pgb_runner.create_config puts " - " + "OK".green if CLI_OPTS[:verbose] puts "Config folder: #{pgb_runner.tmp_folder}" end pgb_runner_at_exit = Proc.new do print "Stoping pgbouncer ..." pgb_runner.stop_async puts end at_exit do pgb_runner_at_exit.call end print "Starting pgbouncer " pgb_runner.run_async pgb_pid = pgb_runner.wait_for_pid puts "- " + "OK".green + " (pid: #{pgb_pid})" print "Starting SSH tonnel " tonnel = TonnelRunner.new(pgb_runner.pgb_port, tmp_dir: pgb_runner.tmp_folder, verbose: CLI_OPTS[:verbose]) tonnel_at_exit = Proc.new do print "Stoping ssh ..." tonnel.stop_async puts tonnel.runner_thread.kill puts "Removing tmp dir ..." FileUtils.rm_rf(pgb_runner.tmp_folder) end at_exit do pgb_runner_at_exit.call tonnel_at_exit.call end tonnel.run_async tonnel.wait_remote_port_allocated puts "- " + "OK".green + " (pid: #{tonnel.runner_pid})" puts "Remote port: #{tonnel.remote_port}" psql_opt = { user: pgb_runner.pgb_user, password: pgb_runner.pgb_password, database: pgb_runner.pg_db, port: tonnel.remote_port, host: PUBLIC_HOST, verbose: CLI_OPTS[:verbose] } if CLI_OPTS[:check_tonnel] print "Checking connection: " result = PsqlRunner.check_connection(psql_opt) puts result === true ? "OK".green : "FAILED".red if result != true puts puts result puts end end db_url = pgb_runner.make_db_url(tonnel.remote_port) puts puts "DATABSE CONNECTION:" puts " #{db_url}" puts psql_path = PsqlRunner.find_psql if psql_path puts "CONNECT WITH PSQL:" passwd = pgb_runner.pgb_password == '' ? '' : "PGPASSWORD=#{pgb_runner.pgb_password}" puts " #{passwd} #{psql_path} -h dblink.tk -p #{tonnel.remote_port} -U #{pgb_runner.pgb_user} #{pgb_runner.pg_db}" puts end web_response = WebService.register_link(db_url, verbose: CLI_OPTS[:verbose]) if web_response['status'] == 'success' puts "WEB URL:" puts " #{web_response['web_url']}" puts end at_exit do pgb_runner_at_exit.call tonnel_at_exit.call tonnel.runner_thread.kill exit! end tonnel.runner_thread.value #ssh_command = SSH_TONNEL_COMMAND.gsub('{{local_port}}', '6543') #system ssh_command