Isard CLI

A Rust CLI tool for managing IsardVDI virtual desktops on the Gencat educational platform (elmeuescriptori.gestioeducativa.gencat.cat). This tool provides a streamlined command-line interface for educators and administrators to manage virtual desktop environments.

Features

  • Seamless Authentication: Automated SAML 2.0 flow via Azure Entra ID with session caching
  • Desktop Management: Create, start, stop, delete, and list virtual desktops with detailed status information
  • Template Management: Browse and select from available desktop templates with hardware specifications
  • Remote Desktop Access: Connect to desktops via SSH or virt-viewer with SPICE protocol
  • Cross-platform virt-viewer Integration: Automatic installation of virt-viewer on Windows (MSI), macOS (Homebrew), Fedora (dnf), and Ubuntu/Debian (apt)
  • Hardware Information: View CPU and memory specifications for virtual desktops
  • Session Persistence: Automatic session management and token refresh
  • Rich CLI Experience: Beautiful console output with status indicators and progress bars

Installation

Recommended: use the web installer from https://isard.xtec.dev/.

# Linux / macOS
curl -fsSL https://isard.xtec.dev/install.sh | sh

# Windows (PowerShell)
irm https://isard.xtec.dev/install.ps1 | iex

The binary lands at ~/.local/bin/isard by default (mirroring the XDG user-bin layout on all OSes). The installer also adds that directory to your shell startup file (~/.bashrc/~/.bash_profile for bash, ~/.zshenv for zsh, ~/.config/fish/conf.d/isard.fish for fish) or to the User PATH on Windows (HKCU\Environment\Path). Open a new terminal and run isard version to verify.

Environment overrides:

VariableMeaning
ISARD_INSTALLinstall root (binary at $ISARD_INSTALL/bin/isard)
ISARD_VERSIONpin a specific version instead of the latest
ISARD_NO_MODIFY_PATHskip shell-rc / User-PATH modification
ISARD_BASE_URLalternative update server

The downloaded binary's SHA-256 is verified against the manifest at https://isard.xtec.dev/api/version before it is moved into place.

Updating

isard update           # install the latest release
isard update --check   # report up-to-date / new version available
isard update --version 0.1.3   # roll back to a specific version

update resolves the running binary's path via current_exe() and atomically replaces it, so the next invocation runs the new version (in-flight processes keep the old code). On Windows the running .exe is renamed to isard.exe.old first; that file is cleaned up on the next isard invocation.

The source tree is private. Authorised collaborators get the repository URL out-of-band.

Quick Start

Authentication

Using isard as client will ask your for your credentials.

Otherwise, you can set up your credentials using environment variables:

export GENCAT_USERNAME="your-username@edu.gencat.cat"
export GENCAT_PASSWORD="your-password"

Or create a .env file in your working directory:

GENCAT_USERNAME=your-username@edu.gencat.cat
GENCAT_PASSWORD=your-password

Basic Usage

# Login and display session information
isard login

# Show version
isard version

# List all virtual desktops
isard list

# List desktops with hardware specifications
isard list --hardware

# Browse available templates
isard template

# Browse templates with hardware info
isard template --hardware

# Create a new template — pick from the menu (currently Fedora Server / Workstation),
# download the latest ISO, boot it, install the OS, then detach + delete the media.
# The desktop name is derived from the picked variant + Fedora major version,
# e.g. `fedora-server-44` or `fedora-workstation-44`.
isard template create

# Manage media (ISO library) directly
isard media                                          # list your media
isard media list --filter ubuntu
isard media add ubuntu-22 --url https://releases.ubuntu.com/22.04/ubuntu-22.04.5-live-server-amd64.iso
isard media add my-iso --url https://example.com/x.iso --no-wait
isard media delete ubuntu-22 --yes

# Create a new desktop
isard create "My Desktop"

# Create desktop from specific template
isard create "My Desktop" --template "Ubuntu 22.04"

# Start a desktop
isard start "Desktop Name"

# Start a desktop and wait for it to be ready
isard start "Desktop Name" --wait --timeout 300

# Stop a desktop
isard stop "Desktop Name"

# Delete a desktop (move to trash - recoverable)
isard delete "Desktop Name"

# Permanently delete a desktop (irreversible)
isard delete "Desktop Name" --permanent

# Delete with confirmation skip
isard delete "Desktop Name" --yes

# Open desktop in virt-viewer
isard view "Desktop Name"

# Open desktop with auto-start if stopped
isard view "Desktop Name" --start

# SSH into a desktop
isard ssh "Desktop Name"

# SSH with auto-start if desktop is stopped
isard ssh "Desktop Name" --start

# Logout (clear cached sessions)
isard logout

Commands

CommandDescriptionOptions
loginAuthenticate and display session info
logoutDelete cached session files-
versionShow package version-
listList desktops with state/IP/OS--hardware/-H, --name/-n
template / template listList available templates--category/-c, --hardware/-H, --filter
template createInteractive: pick a source (Fedora Server / Workstation, more later), download the ISO, create a desktop named fedora-<variant>-<version>, then offer to detach + delete the media after install
media / media listList your media (ISO library)--filter
media add <name>Register a new media by HTTPS URL--url, --description/-d, --no-wait, --timeout
media delete <name>Delete a media--yes/-y
create <name>Create new desktop from template--template/-t, --description/-d, --category/-c, --filter
start <name>Start a stopped desktop--wait/-w, --timeout
stop <name>Stop a running desktop--wait/-w, --timeout
delete <name>Delete desktop (trash or permanent)--permanent, --yes/-y
view <name>Open desktop in virt-viewer via SPICE--start, --install/--no-install, --debug/--no-debug
ssh <name>SSH into desktop via bastion--start, --user/-l, --password (update guest credentials, restart, then SSH), --identity/-i, --dry-run, --timeout

Desktop Name Resolution

The CLI intelligently resolves desktop names using:

  1. Exact match (case-insensitive)
  2. Fuzzy matching for typos and partial names
  3. Substring matching as fallback

SSH Configuration

The SSH command automatically:

  • Resolves SSH private keys (--identity, ~/.ssh/id_ed25519, ~/.ssh/id_rsa)
  • Generates new ed25519 keys if none found
  • Registers public keys with IsardVDI bastion
  • Handles bastion connection on port 443

virt-viewer Installation

The view command automatically installs virt-viewer (remote-viewer) if not found:

PlatformMethod
WindowsDownloads and extracts MSI from GitLab releases (no admin required)
macOSHomebrew via jeffreywildman/homebrew-virt-manager tap (builds from source, takes several minutes)
Fedoradnf install virt-viewer
Ubuntu/Debianapt install virt-viewer

Use --no-install to skip automatic installation.

Authentication Flow

  1. SAML 2.0 Authentication: Secure login via Azure Entra ID
  2. Credentials: Read from GENCAT_USERNAME / GENCAT_PASSWORD (or a local .env file); the CLI falls back to an interactive prompt on a TTY.
  3. Session Caching: Persistent sessions stored securely in ~/.config/isard/
  4. Automatic Refresh: Validity is checked locally and a 401 from any endpoint transparently clears the cache and re-authenticates. Run isard login to force a fresh re-auth.

Library Usage

isard can also be used as a Rust library. Add it to your Cargo.toml and call the async helpers:

use isard::{
    add_ssh_key, create_desktop, create_template_from_media, delete_desktop,
    delete_desktop_permanent, get_desktops, get_media, get_media_installs, get_spice_file,
    get_templates, start_desktop, stop_desktop, wait_desktop, IsardVdiClient,
    NewFromMediaRequest,
};
use isard::installer::{install_virt_viewer, launch_virt_viewer};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Authenticate (returns a client whose `.session()` is reusable in all helpers).
    let client = IsardVdiClient::login(
        "username@edu.gencat.cat",
        "password",
        "https://elmeuescriptori.gestioeducativa.gencat.cat",
        None,
    ).await?;
    let session = client.session().clone();

    // List desktops
    let desktops = get_desktops(&session, None).await?;

    // Get available templates
    let templates = get_templates(&session, None).await?;

    // Create a new desktop from a template
    let desktop = create_desktop(&session, &templates[0].id, "My-Desktop", Some("Test desktop")).await?;

    // Or create a new template by booting an ISO from your media library
    let media = get_media(&session).await?;
    let installs = get_media_installs(&session).await?;
    let req = NewFromMediaRequest {
        name: "my-fedora".into(),
        media_id: media[0].id.clone(),
        description: None,
        xml_id: installs.iter().find(|i| i.id == "linux").map(|i| i.id.clone()),
        vcpus: 4,
        memory_mb: 8192,
        disk_gb: 100,
        disk_bus: "virtio".into(),
    };
    let from_media = create_template_from_media(&session, &req).await?;

    // Start / stop a desktop
    start_desktop(&session, &desktop.id).await?;
    wait_desktop(&session, &desktop.id, "Started", 120.0, 3.0).await?;
    stop_desktop(&session, &desktop.id).await?;

    // Get SPICE file for remote viewing
    let spice_content = get_spice_file(&session, &desktop.id).await?;

    // Install and launch virt-viewer (cross-platform)
    install_virt_viewer(false, true).await?;
    launch_virt_viewer(&spice_content, "My-Desktop", false)?;

    // SSH bastion management
    add_ssh_key(&session, &desktop.id, "ssh-ed25519 AAAA... user@host").await?;

    // Delete a desktop (move to trash — recoverable)
    delete_desktop(&session, &desktop.id).await?;

    // Permanently delete a desktop (irreversible)
    delete_desktop_permanent(&session, &desktop.id).await?;

    Ok(())
}

Configuration

Session Files

  • ~/.config/isard/session.json - Gencat SAML session (user info, cookies)
  • ~/.config/isard/isardvdi.json - IsardVDI JWT session (authentication token)

Both files are created with chmod 600 for security.

Environment Variables

  • GENCAT_USERNAME - Your Gencat username
  • GENCAT_PASSWORD - Your Gencat password

Requirements

  • Rust 1.78+ (only to build from source — release binaries have no runtime dependency)
  • Linux, macOS, or Windows
  • Internet connection for authentication
  • SSH client for desktop access

License

Private. Copyright (c) 2026 David de Mingo david@xtec.dev. All rights reserved — see LICENSE.

Support

Contact david@xtec.dev.


Note: This tool is designed specifically for the Gencat educational platform. You'll need valid credentials for the IsardVDI system to use this tool.