#!/usr/bin/env ruby require 'optparse' require 'xmlrpc/client' class LocalClient def initialize(b) @b = b end def call(cmd, query=nil) @b.set_params(query) if query if (cmd=="feeds") @b.feeds elsif (cmd=="timeseries") ts = Ts.new(@b,query) ts.compute_ts_block res = { "ts" => ts.tshash } else res = @b.process r = { "list" => res.list, "queryid" => res.queryid, "query" => res.query, "querytime" => res.querytime } end end end SERVER = "www.datapository.net" PATH = "/bgpmon/dataview-rpc.cgi" type = "bgpup" local = false timeout = 120 limit = 500 feed = nil prefix = nil prefix_rel = 'eq' origin_as = nil neighbor_as = nil aspath = nil aspath_rel = nil time = 'between' stime = nil etime = nil binsize = 600 index = 'neighbor_as' opts = OptionParser.new do |opts| opts.banner = "Usage: dataview-client.rb [options] " opts.on("-f", "--feed feedname", String, "Specify which feed to use. Required!") { |f| feed = f } opts.on("-l", "--limit maxrows", Integer, "Specify the max # of results to return") { |l| limit = l } opts.on("-T", "--timeout seconds", Integer, "Specify how long the RPC client waits before timing out") { |T| timeout = T } opts.on("-p", "--prefix prefix", String, "Specify a search prefix.") { |p| prefix = p } opts.on("-P", "--prefix-rel rel", String, "Specify a prefix relation. Valid relations are eq (exact match) ", "lte (all subnets) and gte (all supernets). Prefixes are specified ", "as ipaddr/mask") { |r| prefix_rel = r } opts.on("-o", "--origin-as as", String, "Specify the origin AS") { |o| origin_as = o } opts.on("-n", "--neighbor-as as", String, "Specify the neighbor AS") { |n| neighbor_as = n } opts.on("-a", "--as-path string", String, "Specify an AS path. May be one or multple ASes") { |a| aspath = a } opts.on("-A", "--as-rel rel", String, "Specify the AS path relationship. May be contain, start, end, or is") { |a| aspath_rel = a } opts.on("-t", "--time trel", String, "Specify the time. Can be hour, 2hours, 3hours, day, week, or between. ", "If between, specify a start and end time.\n") { |t| time = t } opts.on("-b", "--binsize seconds", String, "For timeseries, size of bins") { |b| binsize = b } opts.on("-i", "--index column", String, "For timeseries option, column to group on. Can be neighbor_as, origin_as, prefix, total") { |i| index = i } opts.on("-z", "--start-time time", String, "The start time.") { |st| stime = st } opts.on("-Z", "--end-time time", String, "The end time.") { |et| etime = et } opts.on("-L", "--[no-]local", "Run locally") do |l| local = l end end opts.parse!(ARGV) query = { "feed" => feed, "time" => time, "limit" => limit } query["origin_as"] = origin_as if origin_as query["neighbor_as"] = neighbor_as if neighbor_as query["prefix_rel"] = prefix_rel if prefix_rel query["prefix"] = prefix if prefix query["aspath"] = aspath if aspath query["aspath_rel"] = aspath_rel if aspath_rel query["stime"] = stime if stime query["etime"] = etime if etime query["binsize"] = binsize if binsize query["index"] = index if index query["type"] = type if type if (local) require 'dataview' require 'Dpdb' db = Dpdb.new b = Dataview.new("bgpup", db, nil) client = LocalClient.new(b) else client = XMLRPC::Client.new(SERVER, PATH, 80) client.timeout = timeout end tstart = Time.now if (ARGV[0] == "feeds") res = client.call("feeds") print "Feeds: " + res.map { |x| x["name"] }.join(" ") + "\n\n" elsif (ARGV[0] == "timeseries") begin res = client.call("timeseries", query) print "\# #{feed}; [#{stime}--#{etime}]; #{index}; #{binsize}\n" print res["ts"]["timeseries"] print res["ts"]["index"] rescue => err p err end else begin res = client.call("dataview", query) p res res["list"].each { |l| if (l["unixtime"] =~ /^[0-9\.]+$/) t = Time.at(l["unixtime"].to_i).utc.strftime("%Y-%m-%d %H:%M:%S") else t = l["unixtime"] end printf("%-20.20s %s %-20.20s %-20.20s %-40.40s\n", t, l["type"], l["prefix"] + "/" + l["mask"], l["next_hop"], l["aspath"]) } rescue => err puts "Error in dataview query: #{err}" end end querytime = (Time.now - tstart).to_f print "#Querytime: #{querytime} seconds\n"