Example #1
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)
Example #2
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)
Example #3
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)
Example #4
0
def ssh(configuration, name=None, **kwargs):
    conn = libvirt.open(configuration.libvirt_uri)
    hv = vl.LibvirtHypervisor(conn)

    def go_ssh(domain):
        os.execlp(
            "ssh",
            "ssh",
            "-o",
            "StrictHostKeyChecking=no",
            "-o",
            "UserKnownHostsFile=/dev/null",
            "{username}@{ipv4}".format(username=domain.username, ipv4=domain.ipv4.ip),
        )

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

    ui.Selector(sorted(hv.list_domains()), go_ssh)
Example #5
0
def main():

    title = "{lightning} Virt-Lightning {lightning}".format(
        lightning=symbols.LIGHTNING.value)

    usage = """
usage: vl [--debug DEBUG] [--config CONFIG]
          {up,down,start,distro_list,storage_dir,ansible_inventory,ssh_config,console,viewer} ..."""
    example = """
Example:

 We export the list of the distro in the virt-lightning.yaml file.
   $ vl distro_list > virt-lightning.yaml

 For each line of the virt-lightning.yaml, start a VM with the associated distro.
   $ vl up

 Once the VM are up, we can generate an Ansible inventory file:
   $ vl ansible_inventory

 The file is ready to be used by Ansible:
   $ ansible all -m ping -i inventory"""

    def list_from_yaml_file(value):
        file_path = pathlib.PosixPath(value)
        if not file_path.exists():
            raise argparse.ArgumentTypeError(f"{value} does not exist.")
        with file_path.open(encoding="UTF-8") as fd:
            content = yaml.safe_load(fd.read())
            if not isinstance(content, list):
                raise argparse.ArgumentTypeError(
                    f"{value} should be a YAML list.")
            return content

    vl_lightning_yaml_args = {
        "default": "virt-lightning.yaml",
        "help":
        "point on an alternative virt-lightning.yaml file (default: %(default)s)",
        "type": list_from_yaml_file,
        "dest": "virt_lightning_yaml",
    }
    context_args = {
        "default": "default",
        "help": "alternative context (default: %(default)s)",
        "dest": "context",
    }

    parent_parser = argparse.ArgumentParser(add_help=False)
    main_parser = argparse.ArgumentParser()
    main_parser.add_argument(
        "--debug",
        action="store_true",
        default=False,
        help="Print extra information (default: %(default)s)",
    )
    main_parser.add_argument(
        "--config",
        help="path to configuration file",
        required=False,
        type=pathlib.PosixPath,
    )

    action_subparsers = main_parser.add_subparsers(title="action",
                                                   dest="action")

    up_parser = action_subparsers.add_parser(
        "up",
        help="Start the VM listed in the virt-lightning.yaml file",
        parents=[parent_parser],
    )
    up_parser.add_argument("--virt-lightning-yaml", **vl_lightning_yaml_args)
    up_parser.add_argument("--context", **context_args)

    down_parser = action_subparsers.add_parser(
        "down",
        help="Destroy all the VM created with VirtLightning",
        parents=[parent_parser],
    )
    down_parser.add_argument("--context", **context_args)

    start_parser = action_subparsers.add_parser("start",
                                                help="Start a new VM",
                                                parents=[parent_parser])
    start_parser.add_argument(
        "--ssh",
        help="Automatically open a SSH connection.",
        action="store_true",
        default=False,
    )
    start_parser.add_argument("--name", help="Name of the VM", type=str)
    start_parser.add_argument("--memory", help="Memory in MB", type=int)
    start_parser.add_argument("--vcpus", help="Number of VCPUS", type=int)
    start_parser.add_argument("--context", **context_args)
    start_parser.add_argument(
        "--show-console",
        help="Suppress console output during VM creation",
        type=bool,
        dest="enable_console",
        default=True,
    )
    start_parser.add_argument("distro", help="Name of the distro", type=str)

    stop_parser = action_subparsers.add_parser("stop",
                                               help="Stop a VM",
                                               parents=[parent_parser])
    stop_parser.add_argument("name", help="Name of the VM", type=str)

    status_parser = action_subparsers.add_parser(
        "status",
        help="List the VM currently running",
        parents=[parent_parser])
    status_parser.add_argument("--context", **context_args)

    action_subparsers.add_parser(
        "distro_list",
        help="List all the images available locally",
        parents=[parent_parser],
    )
    action_subparsers.add_parser("storage_dir",
                                 help="Print the storage directory",
                                 parents=[parent_parser])

    ansible_inventory_parser = action_subparsers.add_parser(
        "ansible_inventory",
        help="Print an ansible_inventory of the running environment",
        parents=[parent_parser],
    )
    ansible_inventory_parser.add_argument("--context", **context_args)

    ssh_config_parser = action_subparsers.add_parser(
        "ssh_config",
        help="Print a ssh config of the running environment",
        parents=[parent_parser],
    )
    ssh_config_parser.add_argument("--context", **context_args)

    ssh_parser = action_subparsers.add_parser("ssh",
                                              help="SSH to a given host",
                                              parents=[parent_parser])
    ssh_parser.add_argument("name",
                            help="Name of the host",
                            type=str,
                            nargs="?")

    console_parser = action_subparsers.add_parser(
        "console",
        help="Open the console of a given host",
        parents=[parent_parser])
    console_parser.add_argument("name",
                                help="Name of the host",
                                type=str,
                                nargs="?")

    viewer_parser = action_subparsers.add_parser(
        "viewer",
        help="Open the SPICE console of a given host with virt-viewer",
        parents=[parent_parser],
    )
    viewer_parser.add_argument("name",
                               help="Name of the host",
                               type=str,
                               nargs="?")

    fetch_parser = action_subparsers.add_parser("fetch",
                                                help="Fetch a VM image",
                                                parents=[parent_parser])
    fetch_parser.add_argument("distro", help="Name of the VM image", type=str)

    args = main_parser.parse_args()
    if not args.action:
        print(title)  # noqa: T001
        print(usage)  # noqa: T001
        print(example)  # noqa: T001
        exit(1)

    configuration = Configuration()
    if args.config:
        configuration.load_file(args.config)

    if args.debug:
        logger.setLevel(logging.DEBUG)

    if args.action == "ansible_inventory":
        print(  # noqa: T001
            virt_lightning.api.ansible_inventory(configuration=configuration,
                                                 **vars(args)))
    elif args.action == "ssh_config":
        print(  # noqa: T001
            virt_lightning.api.ssh_config(configuration=configuration,
                                          **vars(args)))
    elif args.action == "distro_list":
        for distro_name in virt_lightning.api.distro_list(
                configuration=configuration, **vars(args)):
            print("- {0}".format(distro_name))  # noqa: T001
    elif args.action == "storage_dir":
        print(  # noqa: T001
            virt_lightning.api.storage_dir(configuration=configuration,
                                           **vars(args)))
    elif args.action == "status":
        results = {}
        for status in virt_lightning.api.status(configuration=configuration,
                                                **vars(args)):
            results[status["name"]] = {
                "name": status["name"],
                "ipv4": status["ipv4"] or "waiting",
                "context": status["context"],
                "username": status["username"],
                "distro": status["distro"],
            }

        output_template = (
            "{computer} {name:<13}   {arrow}   {username}@{ipv4:>5} [{distro}]"
        )
        for _, v in sorted(results.items()):
            print(  # noqa: T001
                output_template.format(
                    computer=symbols.COMPUTER.value,
                    arrow=symbols.RIGHT_ARROW.value,
                    **v,
                ))
    elif args.action == "console":
        console(configuration=configuration, name=args.name)
    elif args.action == "viewer":
        viewer(configuration=configuration, name=args.name)
    elif args.action == "ssh":
        if args.name:
            virt_lightning.api.exec_ssh(configuration=configuration,
                                        name=args.name)

        def go_ssh(domain):
            domain.exec_ssh()

        ui.Selector(
            virt_lightning.api.list_domains(configuration=configuration,
                                            **vars(args)),
            go_ssh,
        )
    elif args.action == "fetch":

        def progress_callback(cur, length):
            percent = (cur * 100) / length
            line = "🌍 ➡️  💻 [{percent:06.2f}%]  {done:6}MB/{full}MB\r".format(
                percent=percent,
                done=int(cur / virt_lightning.api.MB),
                full=int(length / virt_lightning.api.MB),
            )
            print(line, end="")  # noqa: T001

        try:
            virt_lightning.api.fetch(
                configuration=configuration,
                progress_callback=progress_callback,
                **vars(args),
            )
        except virt_lightning.api.ImageNotFoundUpstream:
            print(  # noqa: T001
                f"Distro {args.distro} cannot be downloaded.\n"
                f"  Visit {virt_lightning.api.BASE_URL}/images/ or private image hub"
                "to get an up to date list.")
            exit(1)
    elif args.action in ["up", "start"]:
        action_func = getattr(virt_lightning.api, args.action)
        try:
            action_func(configuration=configuration, **vars(args))
        except virt_lightning.api.ImageNotFoundLocally as e:
            print(f"Image not found from url: {e.name}")  # noqa: T001
            exit(1)
    elif args.action == "start":
        domain = virt_lightning.api.start(configuration, **vars(args))
        if args.ssh:
            domain.exec_ssh()
    else:
        try:
            action_func = getattr(virt_lightning.api, args.action)
            action_func(configuration=configuration, **vars(args))
        except virt_lightning.api.ImageNotFoundLocally as e:
            print(  # noqa: T001
                ("ℹ️ You may be able to download the image with the "
                 "`vl fetch {name}` command.").format(name=e.name))
            exit(1)