X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=nfvbench%2Fnfvbench.py;h=920838abf7ea53a2d90172d2c576ec56accec567;hb=refs%2Fchanges%2F61%2F45961%2F1;hp=5b7eb91407c8405914afe30e07e5f75d5a0d2d79;hpb=f9be20deb65085a0bb2a32980bb182c10a56324a;p=nfvbench.git diff --git a/nfvbench/nfvbench.py b/nfvbench/nfvbench.py index 5b7eb91..920838a 100644 --- a/nfvbench/nfvbench.py +++ b/nfvbench/nfvbench.py @@ -25,6 +25,7 @@ import copy import credentials import datetime from factory import BasicFactory +from fluentd import FluentLogHandler import importlib import json import log @@ -41,6 +42,8 @@ import traceback from traffic_client import TrafficGeneratorFactory import utils +fluent_logger = None + class NFVBench(object): """Main class of NFV benchmarking tool.""" @@ -73,10 +76,15 @@ class NFVBench(object): def set_notifier(self, notifier): self.notifier = notifier - def run(self, opts): + def run(self, opts, args): status = NFVBench.STATUS_OK result = None message = '' + if fluent_logger: + # take a snapshot of the current time for this new run + # so that all subsequent logs can relate to this run + fluent_logger.start_new_run() + LOG.info(args) try: self.update_config(opts) self.setup() @@ -119,10 +127,14 @@ class NFVBench(object): 'error_message': message } - def print_summary(self, result): - """Print summary of the result""" - print NFVBenchSummarizer(result) - sys.stdout.flush() + def prepare_summary(self, result): + """Prepares summary of the result to print and send it to logger (eg: fluentd)""" + sender = FluentLogHandler("resultnfvbench", + fluentd_ip=self.config.fluentd.ip, + fluentd_port=self.config.fluentd.port) \ + if self.config.fluentd.logging_tag else None + summary = NFVBenchSummarizer(result, sender) + LOG.info(str(summary)) def save(self, result): """Save results in json format file.""" @@ -205,7 +217,7 @@ class NFVBench(object): raise Exception('Please provide existing path for storing results in JSON file. ' 'Path used: {path}'.format(path=self.config.std_json_path)) - self.config_plugin.validate_config(self.config) + self.config_plugin.validate_config(self.config, self.specs.openstack) def parse_opts_from_cli(): @@ -283,9 +295,6 @@ def parse_opts_from_cli(): action='store', help='Traffic generator profile to use') - parser.add_argument('-i', '--image', dest='image_name', - action='store', - help='VM image name to use') parser.add_argument('-0', '--no-traffic', dest='no_traffic', default=None, @@ -365,6 +374,11 @@ def parse_opts_from_cli(): default=None, help='Override traffic profile direction (requires -fs)') + parser.add_argument('--log-file', '--logfile', dest='log_file', + action='store', + help='Filename for saving logs', + metavar='') + opts, unknown_opts = parser.parse_known_args() return opts, unknown_opts @@ -396,17 +410,21 @@ def override_custom_traffic(config, frame_sizes, unidir): "profile": traffic_profile_name } + def check_physnet(name, netattrs): if not netattrs.physical_network: raise Exception("SRIOV requires physical_network to be specified for the {n} network" - .format(n=name)) + .format(n=name)) if not netattrs.segmentation_id: raise Exception("SRIOV requires segmentation_id to be specified for the {n} network" - .format(n=name)) + .format(n=name)) + def main(): + global fluent_logger + run_summary_required = False try: - log.setup('nfvbench') + log.setup() # load default config file config, default_cfg = load_default_config() # create factory for platform specific classes @@ -421,8 +439,17 @@ def main(): config = config_plugin.get_config() openstack_spec = config_plugin.get_openstack_spec() + # setup the fluent logger as soon as possible right after the config plugin is called + if config.fluentd.logging_tag: + fluent_logger = FluentLogHandler(config.fluentd.logging_tag, + fluentd_ip=config.fluentd.ip, + fluentd_port=config.fluentd.port) + LOG.addHandler(fluent_logger) + else: + fluent_logger = None + opts, unknown_opts = parse_opts_from_cli() - log.set_level('nfvbench', debug=opts.debug) + log.set_level(debug=opts.debug) if opts.version: print pbr.version.VersionInfo('nfvbench').version_string_with_vcs() @@ -430,7 +457,7 @@ def main(): if opts.summary: with open(opts.summary) as json_data: - print NFVBenchSummarizer(json.load(json_data)) + print NFVBenchSummarizer(json.load(json_data), None) sys.exit(0) # show default config in text/yaml format @@ -440,15 +467,17 @@ def main(): config.name = '' if opts.config: + # do not check extra_specs in flavor as it can contain any key/value pairs + whitelist_keys = ['extra_specs'] # override default config options with start config at path parsed from CLI # check if it is an inline yaml/json config or a file name if os.path.isfile(opts.config): LOG.info('Loading configuration file: ' + opts.config) - config = config_load(opts.config, config) + config = config_load(opts.config, config, whitelist_keys) config.name = os.path.basename(opts.config) else: LOG.info('Loading configuration string: ' + opts.config) - config = config_loads(opts.config, config) + config = config_loads(opts.config, config, whitelist_keys) # traffic profile override options override_custom_traffic(config, opts.frame_sizes, opts.unidir) @@ -457,6 +486,8 @@ def main(): config.generator_profile = opts.generator_profile if opts.sriov: config.sriov = True + if opts.log_file: + config.log_file = opts.log_file # show running config in json format if opts.show_config: @@ -475,11 +506,15 @@ def main(): # in a copy of the dict (config plugin still holds the original dict) config_plugin.set_config(config) + # add file log if requested + if config.log_file: + log.add_file_logger(config.log_file) + nfvbench = NFVBench(config, openstack_spec, config_plugin, factory) if opts.server: if os.path.isdir(opts.server): - server = WebSocketIoServer(opts.server, nfvbench) + server = WebSocketIoServer(opts.server, nfvbench, fluent_logger) nfvbench.set_notifier(server) try: port = int(opts.port) @@ -492,25 +527,36 @@ def main(): sys.exit(1) else: with utils.RunLock(): + run_summary_required = True if unknown_opts: - LOG.warning('Unknown options: ' + ' '.join(unknown_opts)) + err_msg = 'Unknown options: ' + ' '.join(unknown_opts) + LOG.error(err_msg) + raise Exception(err_msg) # remove unfilled values opts = {k: v for k, v in vars(opts).iteritems() if v is not None} - result = nfvbench.run(opts) + # get CLI args + params = ' '.join(str(e) for e in sys.argv[1:]) + result = nfvbench.run(opts, params) if 'error_message' in result: raise Exception(result['error_message']) if 'result' in result and result['status']: nfvbench.save(result['result']) - nfvbench.print_summary(result['result']) + nfvbench.prepare_summary(result['result']) except Exception as exc: + run_summary_required = True LOG.error({ 'status': NFVBench.STATUS_ERROR, 'error_message': traceback.format_exc() }) print str(exc) - sys.exit(1) + finally: + if fluent_logger: + # only send a summary record if there was an actual nfvbench run or + # if an error/exception was logged. + fluent_logger.send_run_summary(run_summary_required) + if __name__ == '__main__': main()