1#!/usr/bin/env python 2# Copyright 2009 Google Inc. All Rights Reserved. 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16 17"""Simple DNS server comparison benchmarking tool. 18 19Designed to assist system administrators in selection and prioritization. 20""" 21 22__author__ = 'tstromberg@google.com (Thomas Stromberg)' 23 24import datetime 25import math 26import sys 27 28import base_ui 29import conn_quality 30import nameserver_list 31 32 33class NameBenchCli(base_ui.BaseUI): 34 """A command-line implementation of the namebench workflow.""" 35 36 def __init__(self, options, supplied_ns, global_ns, regional_ns, version=None): 37 38 self.options = options 39 self.supplied_ns = supplied_ns 40 self.global_ns = global_ns 41 self.include_internal = True 42 self.regional_ns = regional_ns 43 self.version = version 44 self.last_msg = (None, None, None, None) 45 self.last_msg_count_posted = 0 46 self.preferred = [] 47 self.secondary = [] 48 super(NameBenchCli, self).__init__() 49 50 def UpdateStatus(self, msg, count=None, total=None, error=False, debug=False): 51 """Status updates for the command-line. A lot of voodoo here.""" 52 if self.last_msg == (msg, count, total, error): 53 return None 54 55 if debug: 56 return None 57 58 if error: 59 print 60 print '* ERROR: %s' % msg 61 sys.exit(2) 62 elif not total: 63 self.last_msg_count_posted = 0 64 sys.stdout.write('- %s\n' % msg) 65 elif self.last_msg[0] != msg: 66 self.last_msg_count_posted = 0 67 sys.stdout.write('- %s: %s/%s' % (msg, count, total)) 68 last_count = 0 69 else: 70 last_count = self.last_msg[1] 71 72 if total: 73 if count and (count - last_count > 0): 74 # Write a few dots to catch up to where we should be. 75 catch_up = int(math.ceil((count - last_count) / 2.0)) 76 sys.stdout.write('.' * catch_up) 77 78 if count == total: 79 sys.stdout.write('%s/%s\n' % (count, total)) 80 elif total > 25 and count and (count - self.last_msg_count_posted > (total * 0.20)): 81 sys.stdout.write(str(count)) 82 self.last_msg_count_posted = count 83 sys.stdout.flush() 84 self.last_msg = (msg, count, total, error) 85 86 def PrepareNameServers(self): 87 super(NameBenchCli, self).PrepareNameServers() 88 print '' 89 print 'Final list of nameservers considered:' 90 print '-' * 78 91 for n in self.nameservers.SortByFastest(): 92 print '%-15.15s %-18.18s %-4.0fms | %s' % (n.ip, n.name, n.check_average, 93 n.warnings_string) 94 print '' 95 96 def RunAndOpenReports(self): 97 self.RunBenchmark() 98 print "\n%s\n" % self.reporter.CreateReport(format='ascii') 99 self.CreateReports() 100 if self.options.open_webbrowser: 101 self.DisplayHtmlReport() 102 103 def Execute(self): 104 """Called by namebench.py to start the show.""" 105 print('namebench %s - %s (%s) on %s' % 106 (self.version, self.options.input_source or 'best source', 107 self.options.select_mode, datetime.datetime.now())) 108 print ('threads=%s/%s queries=%s runs=%s timeout=%s health_timeout=%s servers=%s' % 109 (self.options.health_thread_count, self.options.benchmark_thread_count, 110 self.options.query_count, 111 self.options.run_count, self.options.timeout, 112 self.options.health_timeout, self.options.num_servers)) 113 print '-' * 78 114 115 if self.options.only: 116 if not self.supplied_ns: 117 print 'If you use --only, you must provide nameservers to use.' 118 sys.exit(1) 119 self.include_internal = False 120 121 try: 122 self.LoadDataSources() 123 self.PrepareTestRecords() 124 print '' 125 self.PrepareNameServers() 126 self.PrepareBenchmark() 127 self.RunAndOpenReports() 128 except (nameserver_list.OutgoingUdpInterception, 129 nameserver_list.TooFewNameservers, 130 conn_quality.OfflineConnection): 131 (exc_type, exception) = sys.exc_info()[0:2] 132 self.UpdateStatus("%s - %s" % (exc_type, exception), error=True) 133 134 135 136