porting

  1#!/usr/bin/ruby
  2# frozen_string_literal: true
  3
  4require "date"
  5require "dhall"
  6require "em-hiredis"
  7require "pg/em/connection_pool"
  8require "em-http"
  9require "em_promise"
 10require "json"
 11require "optparse"
 12require "ruby-bandwidth-iris"
 13require "securerandom"
 14require "sentry-ruby"
 15require "time"
 16
 17@verbosity = 0
 18@real_data = true
 19@dry_run = false
 20@sources = []
 21@filters = {}
 22
 23OptionParser.new do |opts|
 24	opts.banner =
 25		"Usage: porting [-vn] " \
 26		"[-c CUSTOMER_ID] " \
 27		"-s <bandwidth|db|fake> DHALL_CONFIG"
 28
 29	opts.on(
 30		"-v", "--verbose",
 31		"Print to terminal, run twice to not even send to customer"
 32	) do
 33		@verbosity += 1
 34	end
 35
 36	opts.on(
 37		"-n", "--dry-run",
 38		"Figure out what state they're in, but don't take action"
 39	) do
 40		@dry_run = true
 41	end
 42
 43	opts.on("-h", "--help", "Print this help") do
 44		puts opts
 45		exit
 46	end
 47
 48	opts.on(
 49		"-sSOURCE", "--source=SOURCE", "Source of ports (required, repeatable)"
 50	) do |source|
 51		@sources.append source
 52	end
 53
 54	opts.on(
 55		"-cCUSTOMER_ID", "--customer-id=CUSTOMER_ID",
 56		"Filter by customer ID (db source only)"
 57	) do |customer_id|
 58		@filters[:customer_id] = customer_id
 59	end
 60end.parse!
 61
 62@sources = ["db", "bandwidth"] if @sources.empty?
 63
 64SCHEMA = "{
 65	bandwidth : { account: Text, username: Text, password: Text },
 66	xmpp: { jid: Text, password: Text },
 67	notification: { endpoint: Text, source_number: Text },
 68	pubsub: { server: Text, node: Text },
 69	testing_tel: Text,
 70	admin_server: Text,
 71	sgx: Text,
 72	sgx_creds: List { mapKey: Text, mapValue: {} }
 73}"
 74
 75raise "Need a Dhall config" unless ARGV[0]
 76
 77CONFIG = Dhall::Coder
 78	.new(safe: Dhall::Coder::JSON_LIKE + [Symbol, Proc])
 79	.load("#{ARGV.first} : #{SCHEMA}", transform_keys: :to_sym)
 80
 81require_relative "../lib/blather_notify"
 82require_relative "../lib/expiring_lock"
 83require_relative "../lib/form_to_h"
 84require_relative "../lib/porting_step_repo"
 85require_relative "../lib/port_repo"
 86require_relative "../lib/postgres"
 87
 88Faraday.default_adapter = :em_synchrony
 89BandwidthIris::Client.global_options = {
 90	account_id: CONFIG[:bandwidth][:account],
 91	username: CONFIG[:bandwidth][:username],
 92	password: CONFIG[:bandwidth][:password]
 93}
 94
 95@output =
 96	case @verbosity
 97	when 0
 98		FullAutomatic.new(
 99			BlatherNotify::PubSub::Address.new(**CONFIG[:pubsub]),
100			CONFIG[:notification][:endpoint],
101			CONFIG[:notification][:source_number]
102		)
103	when 1
104		ObservedAuto.new(
105			CONFIG[:notification][:endpoint],
106			CONFIG[:notification][:source_number]
107		)
108	else
109		FullManual.new
110	end
111
112PORT_SOURCES = @sources.map(&:downcase).map { |source|
113	case source
114	when "bandwidth"
115		PortRepo::Bandwidth.new(@output, dry_run: @dry_run)
116	when "db"
117		PortRepo::Db.new(@output, dry_run: @dry_run, filters: @filters)
118	when "fake"
119		PortRepo::Fake.new(@output, dry_run: @dry_run)
120	else
121		puts <<~ERR
122			Invalid port source (-s / --source): #{source}.
123			Valid options: fake, db, endstream
124		ERR
125		# EINVAL
126		exit! 22
127	end
128}
129
130EM.run do
131	REDIS = EM::Hiredis.connect
132	DB = Postgres.connect(dbname: "jmp")
133
134	BlatherNotify.start(
135		CONFIG[:xmpp][:jid],
136		CONFIG[:xmpp][:password]
137	).then {
138		EMPromise.all(PORT_SOURCES.map(&:process))
139	}.catch { |e|
140		@output.error("ROOT", :catch, e)
141	}.then { BlatherNotify.shutdown }
142end