from subprocess import PIPE, Popen
from invirt.config import structs as config
import yaml

def bcast(cmd, hosts = [h.hostname for h in config.hosts]):
    """
    Given a command and a list of hostnames or IPs, issue the command to all
    the nodes and return a list of (host, output) pairs (the order should be
    the same as the order of the hosts).
    """
    pipes = [(host,
              Popen(['remctl', host, 'remote', 'web', cmd], stdout=PIPE, stderr=PIPE))
             for host in hosts]
    outputs = dict((s, p.communicate()) for (s, p) in pipes)
    for (s, p) in pipes:
        if p.returncode != 0:
            if outputs[s][1].startswith('remctl: cannot connect to %s' % s):
                del outputs[s]
            else:
                raise RuntimeError("remctl to host %s returned non-zero exit status %d; stderr:\n%s"
                                   % (s, p.returncode, outputs[s][1]))
    return [(s, yaml.load(o[0], yaml.CSafeLoader)) for (s, o) in outputs.iteritems()]
