'run a module on one or multiple clients'

def do_run(self, arg):

    arg_parser = PupyArgumentParser(prog='run', description='run    a    module    on    one    or    multiple    clients')
    arg_parser.add_argument('module', metavar='<module>', help='module')
    arg_parser.add_argument('-1', '--once', default=False, action='store_true', help='Unload    new    deps    after    usage')
    arg_parser.add_argument('-o', '--output', help='save    command    output    to    file.%%t    -    timestamp,    %%h    -    host,    %%m    -    mac,    %%c    -    client    shortname,    %%M    -    module    name,    %%p    -    platform,    %%u    -    user,    %%a    -    ip    address')
    arg_parser.add_argument('-f', '--filter', metavar='<client    filter>', default=self.default_filter, help='filter    to    a    subset    of    all    clients.    All    fields    available    in    the    "info"    module    can    be    used.    example:    run    get_info    -f    \'platform:win    release:7    os_arch:64\'')
    arg_parser.add_argument('--bg', action='store_true', help='run    in    background')
    arg_parser.add_argument('arguments', nargs=REMAINDER, metavar='<arguments>', help='module    arguments')
    pj = None
    try:
        modargs = arg_parser.parse_args(shlex.split(arg))
    except PupyModuleExit:
        return
    if (not modargs.arguments):
        args = ''
    else:
        args = modargs.arguments
    selected_clients = '*'
    if modargs.filter:
        selected_clients = modargs.filter
    modargs.module = self.pupsrv.get_module_name_from_category(modargs.module)
    try:
        mod = self.pupsrv.get_module(modargs.module)
    except Exception as e:
        self.display_error(('%s    :    %s' % (modargs.module, str(e))))
        return
    if (not mod):
        self.display_error(('unknown    module    %s    !' % modargs.module))
        return
    try:
        self.pupsrv.module_parse_args(modargs.module, args)
    except PupyModuleExit:
        return
    l = [None]
    if mod.need_at_least_one_client:
        l = self.pupsrv.get_clients(selected_clients)
        if (not l):
            if (not self.pupsrv.clients):
                self.display_error('no    clients    currently    connected')
            else:
                self.display_error('no    clients    match    this    search!')
            return
    if ((mod.max_clients != 0) and (len(l) > mod.max_clients)):
        self.display_error(('This    module    is    limited    to    %s    client(s)    at    a    time    and    you    selected    %s    clients' % (mod.max_clients, len(l))))
        return
    modjobs = [x for x in self.pupsrv.jobs.itervalues() if ((x.pupymodules[0].get_name() == mod.get_name()) and (x.pupymodules[0].client in l))]
    pj = None
    try:
        interactive = False
        if (mod.daemon and mod.unique_instance and modjobs):
            pj = modjobs[0]
        else:
            pj = PupyJob(self.pupsrv, ('%s    %s' % (modargs.module, args)))
            if ((len(l) == 1) and (not modargs.bg) and (not mod.daemon)):
                ps = mod(l[0], pj, stdout=self.stdout, log=modargs.output)
                pj.add_module(ps)
                interactive = True
            else:
                for c in l:
                    ps = mod(c, pj)
                    pj.add_module(ps)
        try:
            pj.start(args, once=modargs.once)
        except Exception as e:
            self.display_error(e)
            pj.stop()
        if (not mod.unique_instance):
            if modargs.bg:
                self.pupsrv.add_job(pj)
                self.display_info(('job    %s    started    in    background    !' % pj))
            elif mod.daemon:
                self.pupsrv.add_job(pj)
                self.display_info(('job    %s    started    in    background    !' % pj))
            else:
                error = pj.interactive_wait()
                if (error and (not modjobs)):
                    pj.stop()
        else:
            if (mod.daemon and (not modjobs)):
                self.pupsrv.add_job(pj)
            error = pj.interactive_wait()
            if (error and (not modjobs)):
                pj.stop()
    except KeyboardInterrupt:
        self.display_warning('interrupting    job    ...    (please    wait)')
        pj.interrupt()
        self.display_warning('job    interrupted')
    if (not interactive):
        self.display(pj.result_summary())
    elif pj:
        pj.free()
        del pj
