def main():
    parser = argparse.ArgumentParser(
        description='Smoker client tool', add_help=False)

    # Action arguments
    group_action = parser.add_argument_group('Action switchers')
    group_action.add_argument(
        '-f', '--force', dest='force', action='store_true',
        help="Force plugins run (otherwise just print last results)")
    group_action.add_argument(
        '-l', '--list', dest='list', action='store_true', help="List plugins")
    group_action.add_argument(
        '-h', '--help', dest='help', action='store_true',
        help="Show this help and exit")

    # Host arguments
    group_main = parser.add_argument_group('Target host switchers')
    group_main.add_argument(
        '-s', '--hosts', dest='hosts', nargs='+',
        help="Hosts with running smokerd (default localhost)")

    # Filtering options
    # List of plugins
    group_filters = parser.add_argument_group('Filters')
    group_filters.add_argument(
        '-p', '--plugins', dest='plugins', nargs='+',
        help="Filter plugins by name")
    group_filters.add_argument(
        '--exclude-plugins', dest='exclude_plugins', nargs='+',
        help="Exclude plugins by names")

    # Other filters
    group_filters.add_argument(
        '--filter', dest='filter', default=[], nargs='+',
        help=("Filter plugins by it's parameters, "
              "eg. --filter 'Category connectors'"))
    group_filters.add_argument(
        '--exclude', action='store_true',
        help=("Negative filters (exclude) - currently works only "
              "for one filter"))
    group_filters.add_argument(
        '--category', help="Filter plugins by Category parameter")
    group_filters.add_argument(
        '--component',
        help="Filter plugins by Component parameter (eg. server)")
    group_filters.add_argument(
        '--health', action='store_true',
        help="Filter plugins by Type healthCheck")
    group_filters.add_argument(
        '--smoke', action='store_true',
        help="Filter plugins by Type smokeTest")

    # Plugin state filters
    group_filters.add_argument(
        '--filter-status', dest='filter_status', default=[], nargs='+',
        help="Filter plugins by it's state, eg. --filter-state ERROR WARN")
    group_filters.add_argument(
        '--nook', dest='state_nook', action='store_true',
        help=("Only non-OK plugins (ERROR, WARN, UNKNOWN). "
              "Can't be used together with --filter-state"))
    group_filters.add_argument(
        '--error', dest='state_error', action='store_true',
        help="Only ERROR. Can't be used together with --filter-state")
    group_filters.add_argument(
        '--warn', '--warning', dest='state_warn', action='store_true',
        help="Only WARN. Can't be used together with --filter-state")
    group_filters.add_argument(
        '--unknown', dest='state_unknown', action='store_true',
        help="Only UNKNOWN. Can't be used together with --filter-state")
    group_filters.add_argument(
        '--ok', dest='state_ok', action='store_true',
        help="Only OK. Can't be used together with --filter-state")

    # Output switchers
    group_output = parser.add_argument_group('Output switchers')
    group_output.add_argument(
        '-o', '--pretty', dest='pretty', default='normal',
        help=("Output format: minimal / normal / long / full / raw / json / "
              "tap / xml"))
    group_output.add_argument(
        '--no-colors', dest='no_colors', action='store_true',
        help="Don't use colors in output")
    group_output.add_argument(
        '--no-progress', dest='no_progress', action='store_true',
        help="Don't show progress bar")
    group_output.add_argument(
        '-v', '--verbose', dest='verbose', action='store_true',
        help="Be verbose")
    group_output.add_argument(
        '-d', '--debug', dest='debug', action='store_true',
        help="Debug output")
    group_output.add_argument(
        '-e', '--exitcode', dest='exitcode', action='store_true',
        help="Nonzero exit code if any of plugins failed")
    group_output.add_argument(
        '--junit-config-file', dest='junit_config_file',
        help="Name of configuration file for junit xml formatter")

    _add_plugin_arguments(parser)
    args = parser.parse_args()

    # Set log level and set args.no_progress option
    if args.verbose:
        lg.setLevel(logging.INFO)
        args.no_progress = True

    if args.debug:
        lg.setLevel(logging.DEBUG)
        args.no_progress = True

    if args.help:
        parser.print_help()
        sys.exit(0)

    if args.pretty == 'minimal':
        # Minimal output (only host and errored plugins)
        if not args.no_colors:
            format_host   = {
                'OK'    : '%(gold)s{name:<34}%(default)s [%(green)s{status}%(default)s]'  % COLORS,
                'WARN'  : '%(gold)s{name:<34}%(default)s [%(yellow)s{status}%(default)s]'  % COLORS,
                'ERROR' : '%(gold)s{name:<34}%(default)s [%(red)s{status}%(default)s]'  % COLORS,
                'UNKNOWN' : '%(gold)s{name:<34}%(default)s [%(magenta)s{status}%(default)s]'  % COLORS,
            }
            format_plugin = {
                'OK'    : '',
                'WARN'  : '- {name:<32} [%(yellow)s{lastResult[status]}%(default)s]   (%(gray)s{lastResult[lastRun]}%(default)s)'  % COLORS,
                'ERROR' : '- {name:<32} [%(red)s{lastResult[status]}%(default)s] (%(gray)s{lastResult[lastRun]}%(default)s)'  % COLORS,
                'UNKNOWN' : '- {name:<32} [%(magenta)s{lastResult[status]}%(default)s]'  % COLORS
            }
            format_plugin_component = {
                'OK'    : '',
                'WARN'  : ' -- {name:<30} [%(yellow)s{status}%(default)s]'  % COLORS,
                'ERROR' : ' -- {name:<30} [%(red)s{status}%(default)s]'  % COLORS,
                'UNKNOWN' : ' -- {name:<30} [%(magenta)s{status}%(default)s]'  % COLORS,
            }
        else:
            format_host   = '{name:<34} [{status}]'
            format_plugin = {
                'OK'    : '',
                'WARN'  : '- {name:<32} [{lastResult[status]}] ({lastResult[lastRun]})',
                'ERROR' : '- {name:<32} [{lastResult[status]}] ({lastResult[lastRun]})',
                'UNKNOWN' : '- {name:<32} [{lastResult[status]}]'
            }
            format_plugin_component = {
                'OK'    : '',
                'WARN'  : ' -- {name:<30} [{status}]',
                'ERROR' : ' -- {name:<30} [{status}]',
                'UNKNOWN' : ' -- {name:<30} [{status}]',
            }

        format_plugin_msg = ''
        format_plugin_component_msg = ''
        format_plugin_run = ''
        format_plugin_param = ''
    elif args.pretty == 'normal':
        # Normal output (host and it's plugins without component results)
        if not args.no_colors:
            format_host   = {
                'OK'    : '%(gold)s{name:<34}%(default)s [%(green)s{status}%(default)s]'  % COLORS,
                'WARN'  : '%(gold)s{name:<34}%(default)s [%(yellow)s{status}%(default)s]'  % COLORS,
                'ERROR' : '%(gold)s{name:<34}%(default)s [%(red)s{status}%(default)s]'  % COLORS,
                'UNKNOWN' : '%(gold)s{name:<34}%(default)s [%(magenta)s{status}%(default)s]'  % COLORS,
            }
            format_plugin = {
                'OK'   : '- {name:<32} [%(green)s{lastResult[status]}%(default)s]    (%(gray)s{lastResult[lastRun]}%(default)s)'  % COLORS,
                'WARN' : '- {name:<32} [%(yellow)s{lastResult[status]}%(default)s]   (%(gray)s{lastResult[lastRun]}%(default)s)'  % COLORS,
                'ERROR': '- {name:<32} [%(red)s{lastResult[status]}%(default)s] (%(gray)s{lastResult[lastRun]}%(default)s)'  % COLORS,
                'UNKNOWN': '- {name:<32} [%(magenta)s{lastResult[status]}%(default)s]'  % COLORS
            }
            format_plugin_msg = {
                'info'  : '',
                'warn'  : '  [%(yellow)s{level}%(default)s] {msg}'  % COLORS,
                'error' : '  [%(red)s{level}%(default)s] {msg}'  % COLORS,
            }
            format_plugin_component = {
                'OK'    : '',
                'WARN'  : ' -- {name:<30} [%(yellow)s{status}%(default)s]'  % COLORS,
                'ERROR' : ' -- {name:<30} [%(red)s{status}%(default)s]'  % COLORS,
                'UNKNOWN' : ' -- {name:<30} [%(magenta)s{status}%(default)s]'  % COLORS,
            }
            format_plugin_component_msg = {
                'info'  : '',
                'warn'  : '    [%(yellow)s{level}%(default)s] {msg}'  % COLORS,
                'error' : '    [%(red)s{level}%(default)s] {msg}'  % COLORS,
            }
        else:
            format_host   = '{name:<34} [{status}]'
            format_plugin = '- {name:<32} [{lastResult[status]}] ({lastResult[lastRun]})'
            format_plugin_msg = {
                'info'  : '',
                'warn'  : '  [{level}] {msg}',
                'error' : '  [{level}] {msg}',
            }
            format_plugin_component = {
                'OK'    : '',
                'WARN'  : ' -- {name:<30} [{status}]',
                'ERROR' : ' -- {name:<30} [{status}]',
                'UNKNOWN' : ' -- {name:<30} [{status}]',
            }
            format_plugin_component_msg = {
                'info'  : '',
                'warn'  : '    [{level}] {msg}',
                'error' : '    [{level}] {msg}',
            }

        format_plugin_run = ''
        format_plugin_param = ''
    elif args.pretty == 'long':
        if not args.no_colors:
            format_host   = {
                'OK'    : '%(gold)s{name:<34}%(default)s [%(green)s{status}%(default)s]'  % COLORS,
                'WARN'  : '%(gold)s{name:<34}%(default)s [%(yellow)s{status}%(default)s]'  % COLORS,
                'ERROR' : '%(gold)s{name:<34}%(default)s [%(red)s{status}%(default)s]'  % COLORS,
                'UNKNOWN' : '%(gold)s{name:<34}%(default)s [%(magenta)s{status}%(default)s]'  % COLORS,
            }
            format_plugin = {
                'OK'   : '- {name:<32} [%(green)s{lastResult[status]}%(default)s]    (%(gray)s{lastResult[lastRun]}%(default)s)'  % COLORS,
                'WARN' : '- {name:<32} [%(yellow)s{lastResult[status]}%(default)s]   (%(gray)s{lastResult[lastRun]}%(default)s)'  % COLORS,
                'ERROR': '- {name:<32} [%(red)s{lastResult[status]}%(default)s]    (%(gray)s{lastResult[lastRun]}%(default)s)'  % COLORS,
                'UNKNOWN': '- {name:<32} [%(magenta)s{lastResult[status]}%(default)s]'  % COLORS
            }
            format_plugin_msg = {
                'info'  : '  [%(blue)s{level}%(default)s] {msg}'  % COLORS,
                'warn'  : '  [%(yellow)s{level}%(default)s] {msg}'  % COLORS,
                'error' : '  [%(red)s{level}%(default)s] {msg}'  % COLORS,
            }
            format_plugin_component = {
                'OK'    : ' -- {name:<30} [%(green)s{status}%(default)s]'  % COLORS,
                'WARN'  : ' -- {name:<30} [%(yellow)s{status}%(default)s]'  % COLORS,
                'ERROR' : ' -- {name:<30} [%(red)s{status}%(default)s]'  % COLORS,
                'UNKNOWN' : ' -- {name:<30} [%(magenta)s{status}%(default)s]'  % COLORS,
            }
            format_plugin_component_msg = {
                'info'  : '    [%(blue)s{level}%(default)s] {msg}'  % COLORS,
                'warn'  : '    [%(yellow)s{level}%(default)s] {msg}'  % COLORS,
                'error' : '    [%(red)s{level}%(default)s] {msg}'  % COLORS,
            }
        else:
            format_host   = '{name:<34} [{status}]'
            format_plugin = '- {name:<32} [{lastResult[status]}] ({lastResult[lastRun]})'
            format_plugin_msg = '  [{level}] {msg}'
            format_plugin_component = ' -- {name:<30} [{status}]'
            format_plugin_component_msg = '    [{level}] {msg}'

        format_plugin_run = ''
        format_plugin_param = ''
    elif args.pretty == 'full':
        if not args.no_colors:
            format_host   = {
                'OK'    : '%(gold)s{name:<34}%(default)s [%(green)s{status}%(default)s]'  % COLORS,
                'WARN'  : '%(gold)s{name:<34}%(default)s [%(yellow)s{status}%(default)s]'  % COLORS,
                'ERROR' : '%(gold)s{name:<34}%(default)s [%(red)s{status}%(default)s]'  % COLORS,
                'UNKNOWN' : '%(gold)s{name:<34}%(default)s [%(magenta)s{status}%(default)s]'  % COLORS,
            }
            format_plugin = {
                'OK'   : '- {name:<32} [%(green)s{lastResult[status]}%(default)s]    (%(gray)s{lastResult[lastRun]}%(default)s)'  % COLORS,
                'WARN' : '- {name:<32} [%(yellow)s{lastResult[status]}%(default)s]   (%(gray)s{lastResult[lastRun]}%(default)s)'  % COLORS,
                'ERROR': '- {name:<32} [%(red)s{lastResult[status]}%(default)s]    (%(gray)s{lastResult[lastRun]}%(default)s)'  % COLORS,
                'UNKNOWN': '- {name:<32} [%(magenta)s{lastResult[status]}%(default)s]'  % COLORS
            }
            format_plugin_msg = {
                'info'  : '  [%(blue)s{level}%(default)s] {msg}'  % COLORS,
                'warn'  : '  [%(yellow)s{level}%(default)s] {msg}'  % COLORS,
                'error' : '  [%(red)s{level}%(default)s] {msg}'  % COLORS,
            }
            format_plugin_component = {
                'OK'    : ' -- {name:<30} [%(green)s{status}%(default)s]'  % COLORS,
                'WARN'  : ' -- {name:<30} [%(yellow)s{status}%(default)s]'  % COLORS,
                'ERROR' : ' -- {name:<30} [%(red)s{status}%(default)s]'  % COLORS,
                'UNKNOWN' : ' -- {name:<30} [%(magenta)s{status}%(default)s]'  % COLORS,
            }
            format_plugin_component_msg = {
                'info'  : '    [%(blue)s{level}%(default)s] {msg}'  % COLORS,
                'warn'  : '    [%(yellow)s{level}%(default)s] {msg}'  % COLORS,
                'error' : '    [%(red)s{level}%(default)s] {msg}'  % COLORS,
            }
        else:
            format_host   = '{name:<34} [{status}]'
            format_plugin = '- {name:<32} [{lastResult[status]}] ({lastResult[lastRun]})'
            format_plugin_msg = '  [{level}] {msg}'
            format_plugin_component = ' -- {name:<30} [{status}]'
            format_plugin_component_msg = '    [{level}] {msg}'

        format_plugin_run = '  Last run: {lastResult[lastRun]!s}\n  Next run: {nextRun!s}'
        format_plugin_param = '  {key:<10} {value}'
    elif args.pretty in ['raw', 'json', 'tap', 'xml']:
        # Raw and special outputs doesn't need formatting
        pass
    else:
        lg.error("Invalid pretty output %s" % args.pretty)
        sys.exit(1)

    # Setup custom filters
    if args.category:
        args.filter.append('Category %s' % args.category)

    if args.component:
        args.filter.append('Component %s' % args.component)

    # Health checks and smoke tests together? Don't add filter
    if args.health or args.smoke:
        if args.health:
            args.filter.append('Type healthCheck')

        if args.smoke:
            args.filter.append('Type smokeTest')

    # Setup plugins filter
    filters = []
    if args.filter:
        for f in args.filter:
            filter = {}
            try:
                filter = {
                    'key'  : f.split(' ')[0],
                    'value': f.split(' ')[1]
                }
            except:
                lg.error("Invalid filter parameter format!")
                sys.exit(1)

            filters.append(filter)

    if filters and args.plugins:
        lg.warn("Plugin filter and plugin list used together. "
                "Only plugins matching both will be displayed.")

    if args.plugins:
        filters.append(args.plugins)

    # Setup state filters
    states = []
    if args.filter_status:
        states = args.filter_status
    elif args.state_nook:
        states = ['ERROR', 'WARN', 'UNKNOWN']
    else:
        if args.state_ok:
            states.append('OK')
        if args.state_error:
            states.append('ERROR')
        if args.state_warn:
            states.append('WARN')
        if args.state_unknown:
            states.append('UNKNOWN')

    # State list cannot be empty
    if not states:
        states = ['OK', 'ERROR', 'WARN', 'UNKNOWN']
    # Add status filter
    filters.append(('status', states))

    hosts = ['localhost']
    discovered_hosts = _host_discovery(args)
    if args.hosts:
        hosts = args.hosts
        if discovered_hosts:
            hosts += discovered_hosts
    elif discovered_hosts:
        hosts = discovered_hosts

    # Initialize Client
    client = Client(hosts)
    plugins = client.get_plugins(filters, filters_negative=args.exclude,
                                 exclude_plugins=args.exclude_plugins)

    # No plugins found
    if not plugins:
        lg.error("No plugins found")
        sys.exit(1)

    # List plugins only (parameter --force is ignored)
    if args.list:
        plugins_tuple = plugins.get_host_plugins()

        if plugins.count_hosts() > 1:
            # We have more hosts than 1, print structure like:
            # server1/httpd
            # server2/crond
            for host, plugin in plugins_tuple:
                print "%s/%s" % (host['name'], plugin['name'])
        else:
            # Print only plugin-by-line structure without hostname
            for host, plugin in plugins_tuple:
                print "%s" % plugin['name']
        sys.exit(0)

    # Force plugins run
    # set progress=False if --no-progress parameter is set
    if args.force:
        plugins = client.force_run(
            plugins, progress=not args.no_progress)

    # Print raw output
    if args.pretty == 'raw':
        from pprint import pprint
        pprint(plugins)
        sys.exit(0)
    elif args.pretty == 'json':
        # We need custom encoder to encode datetime objects
        class JSONEncoder(simplejson.JSONEncoder):
            """
            JSON encoder that converts datetime.datetime object to isoformat
            string
            """
            def default(self, obj):
                if isinstance(obj, datetime.datetime):
                    return obj.isoformat()
                return simplejson.JSONEncoder.default(self, obj)

        print simplejson.dumps(plugins, cls=JSONEncoder)
        sys.exit(0)
    elif args.pretty == 'tap':
        dump = dump_tap(plugins)
        # Convert mixed string into ascii to workaround UnicodeEncodeError
        # shouldn't be needed in Python 3
        print dump.encode('ascii', 'ignore')
        sys.exit(0)
    elif args.pretty == 'xml':
        dump = plugins_to_xml(plugins, args.junit_config_file)
        print dump
        sys.exit(0)

    # Print result
    output = []
    hosts_printed = []
    for host, plugin in plugins.get_host_plugins():
        # Print host if not already printed
        if host['name'] not in hosts_printed:
            # Add empty line if any previous host
            if hosts_printed: output.append(" ")
            if isinstance(format_host, dict):
                output.append(format_host[host['status']].format(**host))
            else:
                output.append(format_host.format(**host))
            hosts_printed.append(host['name'])

        # Print plugin
        if not isinstance(plugin, dict):
            # Not a plugin
            continue
        if isinstance(format_plugin, basestring):
            output.append(format_plugin.format(**plugin))
        else:
            output.append(format_plugin[plugin['lastResult']['status']].format(**plugin))

        # Print last and next plugin run
        output.append(format_plugin_run.format(**plugin))

        # Print last and next plugin run
        for key, value in plugin['parameters'].iteritems():
            output.append(format_plugin_param.format(key=key, value=value))

        # Print plugin messages
        if plugin['lastResult']['messages']:
            # For each message level
            for level, message in plugin['lastResult']['messages'].iteritems():
                # For each message
                for msg in message:
                    if isinstance(format_plugin_msg, basestring):
                        output.append(format_plugin_msg.format(level=level, msg=msg.encode('utf8')))
                    else:
                        output.append(format_plugin_msg[level].format(level=level, msg=msg.encode('utf8')))

        # Print component result
        if plugin['lastResult']['componentResults']:
            for component in plugin['lastResult']['componentResults']:
                component = component['componentResult']
                if isinstance(format_plugin_component, basestring):
                    output.append(format_plugin_component.format(**component))
                else:
                    output.append(format_plugin_component[component['status']].format(**component))

                # Print component messages
                if component['messages']:
                    # For each message level
                    for level, message in component['messages'].iteritems():
                        # For each message
                        for msg in message:
                            if isinstance(format_plugin_component_msg, basestring):
                                output.append(format_plugin_component_msg.format(level=level, msg=msg.encode('utf8')))
                            else:
                                output.append(format_plugin_component_msg[level].format(level=level, msg=msg.encode('utf8')))

    for line in output:
        if line:
            print line

    if args.exitcode:
        statuses = [host['status'] for host, _ in plugins.get_host_plugins()]
        for status in ('ERROR', 'WARN'):
            if status in statuses:
                sys.exit(EXIT_CODES[status])
Main entrance
dataset/ETHPy150Open gooddata/smoker/smoker/client/cli.py/main