require 'base64' require 'kubeclient' require 'picsolve_docker_builder/composer/requirements/base' require 'picsolve_docker_builder/helpers/ssh_connection' require 'pg' module PicsolveDockerBuilder module Composer module Requirements # Postgres db requirements class Postgres < Base def ssh_forward(host, port) @ssh = PicsolveDockerBuilder::Helpers::SshConnection.new( ssh_host: kubernetes.host, ssh_port: kubernetes.port ) forward = @ssh.forward(host, port) @ssh.start forward end # get postgres secret for current container def postgres_secret get_secret(user_and_db_name) rescue KubeException => e raise e unless e.message.match(/not found/) log.info "Secret for #{user_and_db_name} database not found" create_postgres_secret end # create a new postgres secret and create the according database def create_postgres_secret admin_secret = admin_postgres_secret log.info "Create secret for #{user_and_db_name} database" container_secret = { 'name' => user_and_db_name, 'user' => user_and_db_name, 'password' => gen_password, 'host' => admin_secret['host'], 'port' => admin_secret['port'] } create_postgres_database( admin_secret, container_secret ) create_secret( user_and_db_name, container_secret ) container_secret end # create postgres database # rubocop:disable Metrics/MethodLength def create_postgres_database(admin_secret, container_secret) log.info "Create database #{user_and_db_name}" forward = ssh_forward(admin_secret['host'], admin_secret['port'].to_i) admin_secret['host'] = '127.0.0.1' admin_secret['port'] = forward.local_port conn = PG::Connection.open(admin_secret) user = conn.escape_string(container_secret['user']) password = conn.escape_string(container_secret['password']) name = conn.escape_string(container_secret['name']) # create user conn.exec( "CREATE USER \"#{user}\" " \ "WITH PASSWORD '#{password}'" ) # create db conn.exec( "CREATE DATABASE \"#{name}\"" ) # grant all rights to the user and the aws user conn.exec(" GRANT ALL PRIVILEGES ON DATABASE \"#{name}\" to \"#{user}\"; GRANT ALL PRIVILEGES ON DATABASE \"#{name}\" to \"rds_superuser\"; ") conn.close admin_secret['dbname'] = name admin_secret['user'] = user admin_secret['password'] = password conn = PG::Connection.open(admin_secret) conn.exec(" ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON TABLES TO \"#{user}\"; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON TABLES TO \"rds_superuser\"; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON SEQUENCES TO \"#{user}\"; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON SEQUENCES TO \"rds_superuser\"; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON FUNCTIONS TO \"#{user}\"; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON FUNCTIONS TO \"rds_superuser\"; ") conn.close end # rubocop:enable Metrics/MethodLength # get administrative postgres secrets def admin_postgres_secret get_secret('postgres').update('dbname' => 'postgres') end def user_and_db_name "#{stage}-#{container.name}-#{name}" end def postgres_secret_name "postgres-#{user_and_db_name}" end def environment_secret postgres_secret.map do |key, value| { 'name' => "#{name.upcase}_#{key.upcase}", 'value' => value } end end def environment environment_secret end end end end end