예제 #1
0
def down(configuration, context, **kwargs):
    hv = vl.LibvirtHypervisor(configuration.libvirt_uri)
    hv.init_storage_pool(configuration.storage_pool)
    for domain in hv.list_domains():
        if context and domain.context != context:
            continue
        hv.clean_up(domain)
예제 #2
0
def ssh_config(configuration, context="default", **kwargs):
    """
    Generate an SSH configuration based on the running VM
    """
    conn = _connect_libvirt(configuration.libvirt_uri)
    hv = vl.LibvirtHypervisor(conn)

    ssh_host_template = ("Host {name}\n"
                         "     Hostname {ipv4}\n"
                         "     User {username}\n"
                         "     IdentityFile {ssh_key_file}\n")

    output = ""
    groups = {}
    for domain in hv.list_domains():
        for group in domain.groups:
            groups[group].append(domain)

        if domain.context != context:
            continue

        template = ssh_host_template

        output += template.format(
            name=domain.name,
            username=domain.username,
            ipv4=domain.ipv4.ip,
            ssh_key_file=domain.ssh_key,
        )

    for group_name, domains in groups.items():
        output += "\n[{group_name}]".format(group_name=group_name)
        for domain in domains:
            output += domain.name
    return output
예제 #3
0
def viewer(configuration, name=None, **kwargs):
    conn = libvirt.open(configuration.libvirt_uri)
    hv = vl.LibvirtHypervisor(conn)

    def virt_viewer_binary():
        paths = [
            pathlib.PosixPath(i, "virt-viewer")
            for i in os.environ["PATH"].split(os.pathsep)
        ]
        for exe in paths:
            if exe.exists():
                return exe
        raise Exception("Failed to find virt-viewer in: ", paths)

    def go_viewer(domain):
        pid = os.fork()
        if pid == 0:
            os.close(1)
            os.close(2)
            os.execlp(
                virt_viewer_binary(),
                "virt-viewer",
                "-c",
                configuration.libvirt_uri,
                "--domain-name",
                domain.name,
            )
        else:
            sys.exit(0)

    if name:
        go_viewer(hv.get_domain_by_name(name))

    ui.Selector(sorted(hv.list_domains()), go_viewer)
예제 #4
0
def ssh_config(configuration, context, **kwargs):
    conn = libvirt.open(configuration.libvirt_uri)
    hv = vl.LibvirtHypervisor(conn)

    ssh_host_template = ("Host {name}\n"
                         "     Hostname {ipv4}\n"
                         "     User {username}\n"
                         "     IdentityFile {ssh_key_file}\n")

    groups = {}
    for domain in hv.list_domains():
        for group in domain.groups:
            groups[group].append(domain)

        if domain.context != context:
            continue

        template = ssh_host_template

        print(  # noqa: T001
            template.format(
                name=domain.name,
                username=domain.username,
                ipv4=domain.ipv4.ip,
                ssh_key_file=domain.ssh_key,
            ))  # noqa: T001

    for group_name, domains in groups.items():
        print("\n[{group_name}]".format(group_name=group_name))  # noqa: T001
        for domain in domains:
            print(domain.name)  # noqa: T001
예제 #5
0
    def parse(self, inventory, loader, path, cache=False):
        super(InventoryModule, self).parse(inventory, loader, path, cache)
        try:
            configuration = virt_lightning.configuration.Configuration()
            conn = libvirt.open(configuration.libvirt_uri)
            hv = vl.LibvirtHypervisor(conn)
            for domain in hv.list_domains():
                if domain.name not in self.inventory.hosts:
                    if not domain.ipv4:
                        continue
                    self.inventory.add_host(domain.name, group='all', port=22)
                    self.inventory.set_variable(domain.name, 'ansible_host',
                                                str(domain.ipv4.ip))
                    self.inventory.set_variable(domain.name, 'ansible_user',
                                                domain.username)
                    self.inventory.set_variable(domain.name,
                                                'ansible_python_interpreter',
                                                domain.python_interpreter)
                    for group in domain.groups:
                        if group not in self.inventory.groups:
                            self.inventory.add_group(group)
                        self.inventory.groups[group].add_host(
                            self.inventory.hosts[domain.name])

        except Exception as e:
            raise AnsibleError(
                'Something happened, this was original exception: %s' %
                to_native(e))
예제 #6
0
def exec_ssh(configuration, name=None, **kwargs):
    """
    Open an SSH connection on a host
    """
    conn = libvirt.open(configuration.libvirt_uri)
    hv = vl.LibvirtHypervisor(conn)
    hv.get_domain_by_name(name).exec_ssh()
예제 #7
0
def status(configuration, context=None, **kwargs):
    conn = libvirt.open(configuration.libvirt_uri)
    hv = vl.LibvirtHypervisor(conn)
    results = {}

    def iconify(v):
        if isinstance(v, str):
            return v
        elif v:
            return symbols.CHECKMARK.value
        else:
            return symbols.CROSS.value

    for status in get_status(hv, context):
        results[status["name"]] = {
            "name": status["name"],
            "ipv4": status["ipv4"] or "waiting",
            "context": status["context"],
            "username": status["username"],
        }

    output_template = "{computer} {name:<13}   {arrow}   {username}@{ipv4:>5}"
    for _, v in sorted(results.items()):
        print(  # noqa: T001
            output_template.format(computer=symbols.COMPUTER.value,
                                   arrow=symbols.RIGHT_ARROW.value,
                                   **v))
예제 #8
0
def fetch(configuration=None, progress_callback=None, hv=None, **kwargs):
    """
    Retrieve a VM image from Internet.
    """
    if hv is None:
        conn = _connect_libvirt(configuration.libvirt_uri)
        hv = vl.LibvirtHypervisor(conn)
        hv.init_storage_pool(configuration.storage_pool)

    configuration = configuration if configuration is not None else Configuration(
    )
    image_found = False
    for images_url in configuration.private_hub:
        try:
            fetch_from_url(
                progress_callback=progress_callback,
                storage_dir=hv.get_storage_dir(),
                url=images_url,
                **kwargs,
            )
            image_found = True
            break
        except ImageNotFoundUpstream:
            logger.info("Image: %s not found from url: %s", kwargs["distro"],
                        images_url)

    if not image_found:
        # image not found from custom url
        # fetch from base url
        fetch_from_url(
            progress_callback=progress_callback,
            storage_dir=hv.get_storage_dir(),
            **kwargs,
        )
예제 #9
0
def list_domains(configuration, name=None, **kwargs):
    """
    Return a list Python-libvirt instance of the running libvirt VM.
    """
    conn = _connect_libvirt(configuration.libvirt_uri)
    hv = vl.LibvirtHypervisor(conn)
    return sorted(hv.list_domains())
예제 #10
0
def ansible_inventory(configuration, context, **kwargs):
    conn = libvirt.open(configuration.libvirt_uri)
    hv = vl.LibvirtHypervisor(conn)

    ssh_cmd_template = (
        "{name} ansible_host={ipv4} ansible_user={username} "
        "ansible_python_interpreter={python_interpreter} "
        'ansible_ssh_common_args="-o UserKnownHostsFile=/dev/null '
        '-o StrictHostKeyChecking=no"')

    groups = {}
    for domain in hv.list_domains():
        if domain.context != context:
            continue

        for group in domain.groups:
            if group not in groups:
                groups[group] = []
            groups[group].append(domain)

        template = ssh_cmd_template

        print(  # noqa: T001
            template.format(
                name=domain.name,
                username=domain.username,
                ipv4=domain.ipv4.ip,
                python_interpreter=domain.python_interpreter,
            ))  # noqa: T001

    for group_name, domains in groups.items():
        print("\n[{group_name}]".format(group_name=group_name))  # noqa: T001
        for domain in domains:
            print(domain.name)  # noqa: T001
예제 #11
0
def distro_list(configuration, **kwargs):
    """
    Return a list of VM images that are available on the system.
    """
    conn = _connect_libvirt(configuration.libvirt_uri)
    hv = vl.LibvirtHypervisor(conn)
    hv.init_storage_pool(configuration.storage_pool)
    return hv.distro_available()
예제 #12
0
def storage_dir(configuration, **kwargs):
    """
    Return the location of the VM image storage directory.
    """
    conn = _connect_libvirt(configuration.libvirt_uri)
    hv = vl.LibvirtHypervisor(conn)
    hv.init_storage_pool(configuration.storage_pool)
    return hv.get_storage_dir()
예제 #13
0
def fetch(configuration, progress_callback=None, **kwargs):
    """
    Retrieve a VM image from Internet.
    """
    conn = libvirt.open(configuration.libvirt_uri)
    hv = vl.LibvirtHypervisor(conn)
    hv.init_storage_pool(configuration.storage_pool)
    storage_dir = hv.get_storage_dir()

    try:
        r = urllib.request.urlopen(
            "https://virt-lightning.org/images/{distro}/{distro}.qcow2".format(**kwargs)
        )
    except urllib.error.HTTPError as e:
        if e.code == 404:
            logger.error(
                (
                    "Distro %s not found!\n"
                    "Visit https://virt-lightning.org/images/ "
                    "to get an up to date list."
                ),
                kwargs["distro"],
            )

            raise ImageNotFoundUpstream()
        else:
            logger.exception(e)
            raise
    lenght = int(r.headers["Content-Length"])
    chunk_size = MB * 1
    target_file = pathlib.PosixPath(
        "{storage_dir}/upstream/{distro}.qcow2".format(
            storage_dir=storage_dir, **kwargs
        )
    )
    temp_file = target_file.with_suffix(".temp")
    if target_file.exists():
        logger.info(
            "File already exists: {target_file}".format(target_file=target_file)
        )
        return
    with temp_file.open("wb") as fd:
        while fd.tell() < lenght:
            chunk = r.read(chunk_size)
            fd.write(chunk)
            if progress_callback:
                progress_callback(fd.tell(), lenght)
    temp_file.rename(target_file)
    try:
        r = urllib.request.urlopen(
            "https://virt-lightning.org/images/{distro}/{distro}.yaml".format(**kwargs)
        )
    except urllib.error.HTTPError as e:
        if e.code == 404:
            pass
    with target_file.with_suffix(".yaml").open("wb") as fd:
        fd.write(r.read())
    logger.info("Image {distro} is ready!".format(**kwargs))
예제 #14
0
def down(configuration, context, **kwargs):
    conn = libvirt.open(configuration.libvirt_uri)
    hv = vl.LibvirtHypervisor(conn)
    hv.init_storage_pool(configuration.storage_pool)
    for domain in hv.list_domains():
        if context and domain.context != context:
            continue
        logger.info("%s purging %s", symbols.TRASHBIN.value, domain.name)
        hv.clean_up(domain)
예제 #15
0
def exec_ssh(configuration, name=None, **kwargs):
    """
    Open an SSH connection on a host
    """
    conn = _connect_libvirt(configuration.libvirt_uri)
    hv = vl.LibvirtHypervisor(conn)
    domain = hv.get_domain_by_name(name)
    if not domain:
        raise VMNotFound(name)
    domain.exec_ssh()
예제 #16
0
def hv(scope="function"):
    conn = libvirt.open("test:///default")
    conn.getURI = Mock(return_value="qemu:///system")
    hv = vl.LibvirtHypervisor(conn)
    with patch.object(pathlib.Path, 'exists') as mock_exists:
        mock_exists.return_value = False
        hv.init_storage_pool("foo_bar")
    hv.init_network("my_network", "1.0.0.0/24")
    yield hv
    clean_up()
예제 #17
0
def start(configuration,
          context="default",
          enable_console=False,
          console_fd=None,
          **kwargs):
    """
    Start a single VM
    """
    conn = _connect_libvirt(configuration.libvirt_uri)
    hv = vl.LibvirtHypervisor(conn)
    hv.init_network(configuration.network_name, configuration.network_cidr)
    hv.init_storage_pool(configuration.storage_pool)
    host = {
        k: kwargs[k]
        for k in ["name", "distro", "memory", "vcpus"] if kwargs.get(k)
    }
    _ensure_image_exists(hv, [host])
    domain = _start_domain(hv, host, context, configuration)
    if not domain:
        return

    loop = kwargs.get("loop") or asyncio.get_event_loop()

    if enable_console:
        import time

        if console_fd is None:
            console_fd = sys.stdout

        time.sleep(4)
        stream = conn.newStream(libvirt.VIR_STREAM_NONBLOCK)
        console = domain.dom.openConsole(None, stream, 0)

        _register_aio_virt_impl(loop=kwargs.get("loop"))

        def stream_callback(stream, events, _):
            content = stream.recv(1024 * 1024).decode("utf-8", errors="ignore")
            console_fd.write(content)

        stream.eventAddCallback(libvirt.VIR_STREAM_EVENT_READABLE,
                                stream_callback, console)

    async def deploy():
        await domain.reachable()

    loop.run_until_complete(deploy())
    logger.info(  # noqa: T001
        ("\033[0m\n**** System is online ****\n"
         "To connect use:\n"
         "  vl console %s (virsh console)"
         "  vl ssh %s"),
        domain.name,
        domain.name,
    )
    return domain
예제 #18
0
def ssh(configuration, name=None, **kwargs):
    conn = libvirt.open(configuration.libvirt_uri)
    hv = vl.LibvirtHypervisor(conn)

    def go_ssh(domain):
        domain.exec_ssh()

    if name:
        hv.get_domain_by_name(name).exec_ssh()

    ui.Selector(sorted(hv.list_domains()), go_ssh)
예제 #19
0
def console(configuration, name=None, **kwargs):
    hv = vl.LibvirtHypervisor(configuration.libvirt_uri)

    def go_console(domain):
        os.execlp("virsh", "virsh", "-c", configuration.libvirt_uri, "console",
                  domain.name)

    if name:
        go_console(hv.get_domain_by_name(name))

    ui.Selector(sorted(hv.list_domains()), go_console)
예제 #20
0
def fetch(configuration, **kwargs):
    conn = libvirt.open(configuration.libvirt_uri)
    hv = vl.LibvirtHypervisor(conn)
    hv.init_storage_pool(configuration.storage_pool)
    storage_dir = hv.get_storage_dir()
    try:
        r = urllib.request.urlopen(
            "https://virt-lightning.org/images/{distro}/{distro}.qcow2".format(
                **kwargs))
    except urllib.error.HTTPError as e:
        if e.code == 404:
            print("Distro {distro} not found!".format(**kwargs))  # noqa: T001
            print(  # noqa: T001
                "Visit https://virt-lightning.org/images/ to get an up to date list."
            )
            sys.exit(1)
        else:
            logger.exception(e)
            sys.exit(1)
    lenght = int(r.headers["Content-Length"])
    MB = 1024 * 1000
    chunk_size = MB
    target_file = pathlib.PosixPath(
        "{storage_dir}/upstream/{distro}.qcow2".format(storage_dir=storage_dir,
                                                       **kwargs))
    temp_file = target_file.with_suffix(".temp")
    if target_file.exists():
        print(  # noqa: T001
            "File already exists: {target_file}".format(
                target_file=target_file))
        sys.exit(0)
    with temp_file.open("wb") as fd:
        while fd.tell() < lenght:
            chunk = r.read(chunk_size)
            fd.write(chunk)
            percent = (fd.tell() * 100) / lenght
            line = "[{percent:06.2f}%]  {done:6}MB/{full}MB\r".format(
                percent=percent,
                done=int(fd.tell() / MB),
                full=int(lenght / MB))
            print(line, end="")  # noqa: T001
        print("\n")  # noqa: T001
    temp_file.rename(target_file)
    try:
        r = urllib.request.urlopen(
            "https://virt-lightning.org/images/{distro}/{distro}.yaml".format(
                **kwargs))
    except urllib.error.HTTPError as e:
        if e.code == 404:
            pass
    with target_file.with_suffix(".yaml").open("wb") as fd:
        fd.write(r.read())
    print("Image {distro} is ready!".format(**kwargs))  # noqa: T001
예제 #21
0
def stop(configuration, **kwargs):
    conn = libvirt.open(configuration.libvirt_uri)
    hv = vl.LibvirtHypervisor(conn)
    hv.init_network(configuration.network_name, configuration.network_cidr)
    hv.init_storage_pool(configuration.storage_pool)
    domain = hv.get_domain_by_name(kwargs["name"])
    if not domain:
        vm_list = [d.name for d in hv.list_domains()]
        print("No VM called {name} in {vm_list}".format(name=kwargs["name"],
                                                        vm_list=vm_list))
        exit(1)
    hv.clean_up(domain)
예제 #22
0
def down(configuration, context, **kwargs):
    conn = libvirt.open(configuration.libvirt_uri)
    hv = vl.LibvirtHypervisor(conn)
    hv.init_network(configuration.network_name, configuration.network_cidr)
    hv.init_storage_pool(configuration.storage_pool)
    for domain in hv.list_domains():
        if context and domain.context != context:
            continue
        logger.info("%s purging %s", symbols.TRASHBIN.value, domain.name)
        hv.clean_up(domain)

    if bool(distutils.util.strtobool(configuration.network_auto_clean_up)):
        hv.network_obj.destroy()
예제 #23
0
def main():
    argument_spec = dict(distro=dict(type=str),
                         name=dict(type=str),
                         state=dict(default='present'),
                         root_password=dict(type=str),
                         groups=dict(default=[], type=list),
                         root_disk_size=dict(type=int, default=32))
    configuration = virt_lightning.configuration.Configuration()
    module = AnsibleModule(argument_spec=argument_spec,
                           supports_check_mode=False)
    if not HAS_LIB:
        module.fail_json(
            msg='virt-lightning Python library is required for this module')

    state = module.params['state']
    context = 'default'
    distro = module.params['distro']
    groups = module.params['groups']
    root_password = module.params[
        'root_password'] or configuration.root_password
    name = module.params.get('name') or re.sub(r"\W+", "", distro)
    vcpus = 1
    memory = 512
    root_disk_size = module.params['root_disk_size']

    conn = libvirt.open(configuration.libvirt_uri)
    hv = vl.LibvirtHypervisor(conn)
    hv.init_network(configuration.network_name, configuration.network_cidr)
    hv.init_storage_pool(configuration.storage_pool)
    domain = hv.get_domain_by_name(name)

    if state == 'absent' and domain:
        hv.clean_up(domain)
        module.exit_json(changed=True)
    elif state == 'absent' and not domain:
        module.exit_json(changed=False)
    elif state == 'present' and domain:
        module.exit_json(changed=False)
    else:
        domain = create(hv,
                        configuration,
                        distro,
                        context,
                        name,
                        root_disk_size,
                        memory=memory,
                        vcpus=vcpus,
                        groups=groups)
        module.exit_json(changed=True,
                         name=domain.name,
                         ipv4=str(domain.ipv4.ip))
예제 #24
0
def ansible_inventory(configuration, context, **kwargs):
    hv = vl.LibvirtHypervisor(configuration.libvirt_uri)

    ssh_cmd_template = (
        "{name} ansible_host={ipv4} ansible_username={username} "
        'ansible_ssh_common_args="-o UserKnownHostsFile=/dev/null '
        '-o StrictHostKeyChecking=no"')

    for domain in hv.list_domains():
        if domain.context == context:
            print(  # noqa: T001
                ssh_cmd_template.format(name=domain.name,
                                        ipv4=domain.ipv4.ip,
                                        username=domain.username))
예제 #25
0
def up(virt_lightning_yaml, configuration, context, **kwargs):
    def myDomainEventAgentLifecycleCallback(conn, dom, state, reason, opaque):
        if state == 1:
            logger.info("%s %s QEMU agent found", symbols.CUSTOMS.value,
                        dom.name())

    loop = asyncio.get_event_loop()
    try:
        import libvirtaio

        libvirtaio.virEventRegisterAsyncIOImpl(loop=loop)
    except ImportError:
        libvirt.virEventRegisterDefaultImpl()
        pass
    conn = libvirt.open(configuration.libvirt_uri)
    hv = vl.LibvirtHypervisor(conn)

    conn.setKeepAlive(5, 3)
    conn.domainEventRegisterAny(
        None,
        libvirt.VIR_DOMAIN_EVENT_ID_AGENT_LIFECYCLE,
        myDomainEventAgentLifecycleCallback,
        None,
    )

    hv.init_network(configuration.network_name, configuration.network_cidr)
    hv.init_storage_pool(configuration.storage_pool)

    pool = ThreadPoolExecutor(max_workers=10)

    async def deploy():
        futures = []
        for host in virt_lightning_yaml:
            futures.append(
                loop.run_in_executor(pool, _start_domain, hv, host, context,
                                     configuration))

        domain_reachable_futures = []
        for f in futures:
            await f
            domain = f.result()
            if domain:
                domain_reachable_futures.append(domain.reachable())
        logger.info("%s ok Waiting...", symbols.HOURGLASS.value)

        await asyncio.gather(*domain_reachable_futures)

    loop.run_until_complete(deploy())
    logger.info("%s You are all set", symbols.THUMBS_UP.value)
예제 #26
0
def up(virt_lightning_yaml, configuration, context="default", **kwargs):
    """
    Create a list of VM
    """
    def _lifecycle_callback(conn, dom, state, reason, opaque):  # noqa: N802
        if state == 1:
            logger.info("%s %s QEMU agent found", symbols.CUSTOMS.value,
                        dom.name())

    loop = kwargs.get("loop") or asyncio.get_event_loop()
    _register_aio_virt_impl(loop)

    conn = _connect_libvirt(configuration.libvirt_uri)
    hv = vl.LibvirtHypervisor(conn)

    conn.setKeepAlive(interval=5, count=3)
    conn.domainEventRegisterAny(
        None,
        libvirt.VIR_DOMAIN_EVENT_ID_AGENT_LIFECYCLE,
        _lifecycle_callback,
        None,
    )

    hv.init_network(configuration.network_name, configuration.network_cidr)
    hv.init_storage_pool(configuration.storage_pool)

    _ensure_image_exists(hv, virt_lightning_yaml)
    pool = ThreadPoolExecutor(max_workers=10)

    async def deploy():
        futures = []
        for host in virt_lightning_yaml:
            futures.append(
                loop.run_in_executor(pool, _start_domain, hv, host, context,
                                     configuration))

        domain_reachable_futures = []
        for f in futures:
            await f
            domain = f.result()
            if domain:
                domain_reachable_futures.append(domain.reachable())
        logger.info("%s ok Waiting...", symbols.HOURGLASS.value)

        await asyncio.gather(*domain_reachable_futures)

    loop.run_until_complete(deploy())
    logger.info("%s You are all set", symbols.THUMBS_UP.value)
예제 #27
0
def down(configuration, context="default", **kwargs):
    """
    Stop and remove a running environment.
    """
    conn = _connect_libvirt(configuration.libvirt_uri)
    hv = vl.LibvirtHypervisor(conn)
    hv.init_network(configuration.network_name, configuration.network_cidr)
    hv.init_storage_pool(configuration.storage_pool)
    for domain in hv.list_domains():
        if domain.context != context:
            continue
        logger.info("%s purging %s", symbols.TRASHBIN.value, domain.name)
        hv.clean_up(domain)

    if bool(distutils.util.strtobool(configuration.network_auto_clean_up)):
        hv.network_obj.destroy()
예제 #28
0
def stop(configuration, **kwargs):
    """
    Stop a given VM
    """
    conn = libvirt.open(configuration.libvirt_uri)
    hv = vl.LibvirtHypervisor(conn)
    hv.init_network(configuration.network_name, configuration.network_cidr)
    hv.init_storage_pool(configuration.storage_pool)
    domain = hv.get_domain_by_name(kwargs["name"])
    if not domain:
        vm_list = [d.name for d in hv.list_domains()]
        if vm_list:
            logger.info("No VM called %s in: %s", kwargs["name"], ", ".join(vm_list))
        else:
            logger.info("No running VM.")
        raise VMNotFound()
    hv.clean_up(domain)
예제 #29
0
def status(configuration, context="default", name=None, **kwargs):
    """
    Returns the status of the VM of the envionment
    """
    conn = libvirt.open(configuration.libvirt_uri)
    hv = vl.LibvirtHypervisor(conn)

    for domain in hv.list_domains():
        if context and context != domain.context:
            continue
        name = domain.name
        if not domain.ipv4:  # Not a VL managed VM
            continue
        yield {
            "name": name,
            "ipv4": domain.ipv4 and str(domain.ipv4.ip),
            "context": domain.context,
            "username": domain.username,
        }
예제 #30
0
def start(configuration, context, **kwargs):
    conn = libvirt.open(configuration.libvirt_uri)
    hv = vl.LibvirtHypervisor(conn)
    hv.init_network(configuration.network_name, configuration.network_cidr)
    hv.init_storage_pool(configuration.storage_pool)
    host = {
        k: kwargs[k]
        for k in ["name", "distro", "memory", "vcpus"] if kwargs.get(k)
    }
    domain = _start_domain(hv, host, context, configuration)
    if not domain:
        return

    loop = asyncio.get_event_loop()

    if not kwargs["noconsole"]:
        import time

        time.sleep(4)
        stream = conn.newStream(libvirt.VIR_STREAM_NONBLOCK)
        console = domain.dom.openConsole(None, stream, 0)
        import libvirtaio

        libvirtaio.virEventRegisterAsyncIOImpl(loop=loop)

        def stream_callback(stream, events, _):
            content = stream.recv(1024).decode()
            sys.stdout.write(content)

        stream.eventAddCallback(libvirt.VIR_STREAM_EVENT_READABLE,
                                stream_callback, console)

    async def deploy():
        await domain.reachable()

    loop.run_until_complete(deploy())
    print(  # noqa: T001
        ("\033[0m\n**** System is online ****\n"
         "To connect use:\n"
         "  vl console {name} (virsh console)"
         "  vl ssh {name}").format(name=domain.name))
    if kwargs["ssh"]:
        domain.exec_ssh()