Files
vtl-appliance/web-ui/index.html

459 lines
22 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>mhvtl Configuration Manager - Adastra VTL</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<nav class="navbar">
<div class="container">
<div class="nav-brand">
<h1>🎞️ Adastra VTL</h1>
<span class="subtitle">Virtual Tape Library Configuration</span>
</div>
<div class="nav-links">
<a href="#library" class="nav-link active">Library</a>
<a href="#drives" class="nav-link">Drives</a>
<a href="#tapes" class="nav-link">Tapes</a>
<a href="#manage-tapes" class="nav-link">Manage Tapes</a>
<a href="#iscsi" class="nav-link">iSCSI</a>
<a href="#export" class="nav-link">Export</a>
</div>
</div>
</nav>
<main class="container">
<section id="library" class="section active">
<div class="section-header">
<h2>📚 Library Configuration</h2>
<p>Configure your virtual tape library settings</p>
</div>
<div class="card">
<div class="card-header">
<h3>Library Settings</h3>
</div>
<div class="card-body">
<div class="form-grid">
<div class="form-group">
<label for="lib-id">Library ID</label>
<input type="number" id="lib-id" value="10" min="0" max="99">
</div>
<div class="form-group">
<label for="lib-channel">Channel</label>
<input type="number" id="lib-channel" value="0" min="0" max="15">
</div>
<div class="form-group">
<label for="lib-target">Target</label>
<input type="number" id="lib-target" value="0" min="0" max="15">
</div>
<div class="form-group">
<label for="lib-lun">LUN</label>
<input type="number" id="lib-lun" value="0" min="0" max="7">
</div>
<div class="form-group">
<label for="lib-vendor">Vendor</label>
<input type="text" id="lib-vendor" value="STK" maxlength="8">
</div>
<div class="form-group">
<label for="lib-product">Product</label>
<input type="text" id="lib-product" value="L700" maxlength="16">
</div>
<div class="form-group">
<label for="lib-serial">Serial Number</label>
<input type="text" id="lib-serial" value="XYZZY_A" maxlength="10">
</div>
<div class="form-group">
<label for="lib-naa">NAA</label>
<input type="text" id="lib-naa" value="10:22:33:44:ab:cd:ef:00" pattern="[0-9a-f:]+">
</div>
<div class="form-group">
<label for="lib-home">Home Directory</label>
<input type="text" id="lib-home" value="/opt/mhvtl">
</div>
<div class="form-group">
<label for="lib-backoff">Backoff (ms)</label>
<input type="number" id="lib-backoff" value="400" min="0" max="10000">
</div>
</div>
</div>
</div>
</section>
<section id="drives" class="section">
<div class="section-header">
<h2>💾 Drive Configuration</h2>
<p>Manage virtual tape drives</p>
</div>
<div class="drives-container" id="drives-container">
</div>
<button class="btn btn-primary" onclick="addDrive()">
<span></span> Add Drive
</button>
</section>
<section id="tapes" class="section">
<div class="section-header">
<h2>📼 Tape Configuration</h2>
<p>Configure virtual tape media</p>
</div>
<div class="card">
<div class="card-header">
<h3>Tape Generation Settings</h3>
</div>
<div class="card-body">
<div class="form-grid">
<div class="form-group">
<label for="tape-library">Library ID</label>
<input type="number" id="tape-library" value="10" min="0" max="99">
</div>
<div class="form-group">
<label for="tape-barcode-prefix">Barcode Prefix</label>
<input type="text" id="tape-barcode-prefix" value="CLN" maxlength="6">
</div>
<div class="form-group">
<label for="tape-start-num">Starting Number</label>
<input type="number" id="tape-start-num" value="100" min="1" max="9999">
</div>
<div class="form-group">
<label for="tape-size">Tape Size (MB)</label>
<input type="number" id="tape-size" value="2500000" min="1000" max="10000000">
</div>
<div class="form-group">
<label for="tape-media-type">Media Type</label>
<select id="tape-media-type">
<option value="data">Data</option>
<option value="clean">Cleaning</option>
<option value="WORM">WORM</option>
</select>
</div>
<div class="form-group">
<label for="tape-density">Density</label>
<select id="tape-density">
<option value="LTO5">LTO-5</option>
<option value="LTO6" selected>LTO-6</option>
<option value="LTO7">LTO-7</option>
<option value="LTO8">LTO-8</option>
<option value="LTO9">LTO-9</option>
</select>
</div>
<div class="form-group">
<label for="tape-count">Number of Tapes</label>
<input type="number" id="tape-count" value="20" min="1" max="1000">
</div>
</div>
<div class="alert alert-info">
<strong> Info:</strong> Generate mktape commands for creating virtual tapes. Run these commands on the server after installation.
</div>
</div>
</div>
</section>
<section id="manage-tapes" class="section">
<div class="section-header">
<h2>🗂️ Manage Virtual Tapes</h2>
<p>Complete CRUD management for virtual tape files</p>
</div>
<div class="card">
<div class="card-header">
<h3> Create New Tapes</h3>
</div>
<div class="card-body">
<div class="form-grid">
<div class="form-group">
<label for="create-library">Library Number</label>
<input type="number" id="create-library" value="10" min="1">
</div>
<div class="form-group">
<label for="create-barcode-prefix">Barcode Prefix</label>
<input type="text" id="create-barcode-prefix" value="CLN" maxlength="6">
</div>
<div class="form-group">
<label for="create-start-num">Starting Number</label>
<input type="number" id="create-start-num" value="100" min="0">
</div>
<div class="form-group">
<label for="create-count">Number of Tapes</label>
<input type="number" id="create-count" value="1" min="1" max="100">
</div>
<div class="form-group">
<label for="create-size">Tape Size (MB)</label>
<input type="number" id="create-size" value="2500000" min="1000">
<small>Default: 2.5TB = 2,500,000 MB</small>
</div>
<div class="form-group">
<label for="create-media-type">Media Type</label>
<select id="create-media-type">
<option value="data">Data</option>
<option value="clean">Cleaning</option>
<option value="WORM">WORM</option>
</select>
</div>
<div class="form-group">
<label for="create-density">Density</label>
<select id="create-density">
<option value="LTO5">LTO-5</option>
<option value="LTO6" selected>LTO-6</option>
<option value="LTO7">LTO-7</option>
<option value="LTO8">LTO-8</option>
<option value="LTO9">LTO-9</option>
</select>
</div>
</div>
<div style="margin-top: 1rem;">
<button class="btn btn-success" onclick="createTapes()">
<span></span> Create Tapes
</button>
<div id="create-result" class="alert" style="display: none; margin-top: 1rem;"></div>
</div>
</div>
</div>
<div class="card" style="margin-top: 1rem;">
<div class="card-header">
<h3>📋 Tape Files</h3>
<button class="btn btn-primary" onclick="loadTapeList()">
<span>🔄</span> Refresh List
</button>
</div>
<div class="card-body">
<div id="tape-list-loading" style="display: none; text-align: center; padding: 2rem;">
<strong></strong> Loading tape files...
</div>
<div id="tape-list-error" class="alert alert-danger" style="display: none;"></div>
<div id="tape-list-empty" class="alert alert-info" style="display: none;">
<strong></strong> No tape files found. Create tapes using the commands from the "Tapes" section.
</div>
<div id="tape-list-container" style="display: none;">
<div style="margin-bottom: 1rem;">
<input type="text" id="tape-search" placeholder="🔍 Search tapes..."
style="width: 100%; padding: 0.5rem; border: 1px solid #ddd; border-radius: 4px;"
onkeyup="filterTapes()">
</div>
<table class="tape-table" id="tape-table">
<thead>
<tr>
<th>Barcode</th>
<th>Size</th>
<th>Modified</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="tape-list-body">
</tbody>
</table>
<div style="margin-top: 1rem; padding: 1rem; background: #f8f9fa; border-radius: 4px;">
<strong>Total Tapes:</strong> <span id="tape-count-display">0</span>
</div>
</div>
</div>
</div>
<div class="card" style="margin-top: 1rem;">
<div class="card-header">
<h3>Bulk Actions</h3>
</div>
<div class="card-body">
<p>Delete multiple tapes at once. Use with caution!</p>
<div class="form-group">
<label for="bulk-delete-pattern">Delete Pattern (e.g., CLN*)</label>
<input type="text" id="bulk-delete-pattern" placeholder="CLN*">
</div>
<button class="btn btn-danger" onclick="bulkDeleteTapes()">
<span>🗑️</span> Bulk Delete
</button>
<div id="bulk-delete-result" class="alert" style="display: none; margin-top: 1rem;"></div>
</div>
</div>
</section>
<section id="iscsi" class="section">
<div class="section-header">
<h2>🔌 iSCSI Target Management</h2>
<p>Manage iSCSI targets, initiators, and LUNs</p>
</div>
<div class="card">
<div class="card-header">
<h3>🎯 iSCSI Targets</h3>
<button class="btn btn-primary" onclick="loadTargets()">
<span>🔄</span> Refresh
</button>
</div>
<div class="card-body">
<div id="target-list-empty" class="alert alert-info">
<strong></strong> No targets configured. Create a target below.
</div>
<div id="target-list-container" style="display: none;">
<table class="tape-table" id="target-table">
<thead>
<tr>
<th>TID</th>
<th>Target Name (IQN)</th>
<th>LUNs</th>
<th>ACLs</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="target-list-body">
</tbody>
</table>
</div>
</div>
</div>
<div class="card" style="margin-top: 1rem;">
<div class="card-header">
<h3> Create New Target</h3>
</div>
<div class="card-body">
<div class="form-grid">
<div class="form-group">
<label for="target-tid">Target ID (TID)</label>
<input type="number" id="target-tid" value="1" min="1">
<small>Unique target identifier</small>
</div>
<div class="form-group">
<label for="target-name">Target Name</label>
<input type="text" id="target-name" placeholder="vtl.drive0">
<small>Will be: iqn.2024-01.com.vtl-linux:<name></small>
</div>
</div>
<button class="btn btn-success" onclick="createTarget()">
<span></span> Create Target
</button>
<div id="create-target-result" class="alert" style="display: none; margin-top: 1rem;"></div>
</div>
</div>
<div class="card" style="margin-top: 1rem;">
<div class="card-header">
<h3>💾 Add LUN (Backing Store)</h3>
</div>
<div class="card-body">
<div class="form-grid">
<div class="form-group">
<label for="lun-tid">Target ID</label>
<input type="number" id="lun-tid" value="1" min="1">
</div>
<div class="form-group">
<label for="lun-number">LUN Number</label>
<input type="number" id="lun-number" value="1" min="0">
</div>
<div class="form-group">
<label for="lun-device">Device Path</label>
<input type="text" id="lun-device" placeholder="/dev/sg1">
<small>SCSI generic device (e.g., /dev/sg1, /dev/sg2)</small>
</div>
</div>
<button class="btn btn-success" onclick="addLun()">
<span></span> Add LUN
</button>
<div id="add-lun-result" class="alert" style="display: none; margin-top: 1rem;"></div>
</div>
</div>
<div class="card" style="margin-top: 1rem;">
<div class="card-header">
<h3>🔐 Manage Initiator ACLs</h3>
</div>
<div class="card-body">
<div class="form-grid">
<div class="form-group">
<label for="acl-tid">Target ID</label>
<input type="number" id="acl-tid" value="1" min="1">
</div>
<div class="form-group">
<label for="acl-address">Initiator Address</label>
<input type="text" id="acl-address" placeholder="192.168.1.100 or ALL">
<small>IP address or "ALL" for any initiator</small>
</div>
</div>
<div style="margin-top: 1rem;">
<button class="btn btn-success" onclick="bindInitiator()">
<span></span> Allow Initiator
</button>
<button class="btn btn-danger" onclick="unbindInitiator()">
<span>🚫</span> Block Initiator
</button>
</div>
<div id="acl-result" class="alert" style="display: none; margin-top: 1rem;"></div>
</div>
</div>
</section>
<section id="export" class="section">
<div class="section-header">
<h2>📤 Export Configuration</h2>
<p>Generate and download configuration files</p>
</div>
<div class="card">
<div class="card-header">
<h3>Configuration Preview</h3>
</div>
<div class="card-body">
<pre id="config-preview" class="config-preview"></pre>
</div>
</div>
<div class="button-group">
<button class="btn btn-primary" onclick="generateConfig()">
<span>🔄</span> Generate Config
</button>
<button class="btn btn-success" onclick="applyConfig()">
<span>💾</span> Apply to Server
</button>
<button class="btn btn-success" onclick="downloadConfig()">
<span>⬇️</span> Download device.conf
</button>
<button class="btn btn-secondary" onclick="copyConfig()">
<span>📋</span> Copy to Clipboard
</button>
</div>
<div id="apply-result" class="alert" style="display: none; margin-top: 1rem;"></div>
<div class="card" style="margin-top: 1rem;">
<div class="card-header">
<h3>Service Management</h3>
</div>
<div class="card-body">
<p>After applying configuration, restart the mhvtl service to apply changes.</p>
<button class="btn btn-warning" onclick="restartService()">
<span>🔄</span> Restart mhvtl Service
</button>
<div id="restart-result" class="alert" style="display: none; margin-top: 1rem;"></div>
</div>
</div>
<div class="card">
<div class="card-header">
<h3>Installation Command</h3>
</div>
<div class="card-body">
<pre id="install-command" class="config-preview"></pre>
<button class="btn btn-secondary" onclick="copyInstallCommand()">
<span>📋</span> Copy Command
</button>
</div>
</div>
</section>
</main>
<footer class="footer">
<div class="container">
<p>© Adastra Visi Teknologi • <a href="http://adastra.id">adastra.id</a> • mhvtl Configuration Manager</p>
</div>
</footer>
<script src="script.js"></script>
</body>
</html>