| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894 |
- <!DOCTYPE html>
- <html>
- <head>
- <title>RAID</title>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0 user-scalable=no">
- <link rel="stylesheet" href="../../../script/semantic/semantic.min.css">
- <script type="text/javascript" src="../../../script/jquery.min.js"></script>
- <script type="text/javascript" src="../../../script/semantic/semantic.min.js"></script>
- <style>
- .mdevice{
- color: rgb(136, 136, 136);
- font-weight: lighter;
- }
- .mdevuuid{
- font-size: 0.6em !important;
- }
- .volinfo{
- text-align: left !important;
- margin-top: 0.6em !important;
- }
- .volinfo .numeric{
- font-weight: lighter;
- color: #0d79ea;
- }
- .volinfo .percentage{
- font-weight: lighter;
- color: rgb(102, 102, 102);
- position: absolute;
- text-align: right;
- right: 1em;
- top: 0em;
- }
- .raidVol .usedvol{
- margin-bottom: 2em !important;
- }
- .raidVol .usedvol .bar{
- background-color: #0d79ea !important;
- }
- .raidVol{
- cursor: pointer;
- }
- .raidVol:hover{
- background-color: rgb(240, 240, 240);
- }
- .raidVol.active{
- background-color: rgb(240, 240, 240);
- }
- .healthIcon{
- position: absolute;
- left: 35px;
- top: 38px;
- border-radius: 50% !important;
- background-color: white;
- }
- .healthIcon i {
- margin-right: 0 !important;
- }
- /* RAID Option Button */
- .raidOptionBtn{
- position: absolute;
- top: 1em;
- right: 1em;
- }
- /* Statistics of Device Status */
- .deviceOverview{
- background-color: #f3f3f3 !important;
- border-radius: 0.4em !important;
- }
- .deviceOverview .ui.statistics .statistic .label{
- text-transform: none !important;
- font-weight: 300;
- }
- /* RAID device members */
- .raiddevice{
- border-radius: 0.4em !important;
- margin-bottom: 0 !important;
- margin-top: 0 !important;
-
- position: relative;
- }
- .raiddevice:hover{
- background-color: #f3f3f3 !important;
- }
- .raiddevice .capinfo{
- position: absolute;
- color:rgb(136, 136, 136);
- right: 1em;
- top: 1em;
- text-align: right;
- }
- .raiddevice .capinfo .readonlytag{
- background-color: #cc3d3a;
- color:white;
- padding: 2px;
- padding-left: 5px;
- padding-right: 5px;
- }
- /* RAID memeber options */
- .raidDeviceOptions{
- width: 100%;
- min-height: 2em;
- }
- .raidDeviceOptions .content{
- float :right;
- }
- .notMountedLabel{
- color:rgb(194, 194, 194);
- font-weight: 300;
- }
- /* Danger zone css */
- .dangerzone{
- border: 1px solid #dedede;
- border-radius: 0.6em;
- overflow: hidden;
- padding-bottom: 1em;
- }
- .dangerzone .header{
- color:white;
- padding: 1em;
- background-color: #cc3d3a;
- margin-bottom: 1em;
- font-weight: bolder;
- }
- .dangerzone summary{
- cursor: pointer;
- user-select: none;
- }
- </style>
- </head>
- <body>
- <br>
- <div class="ui container">
- <!--
- <div class="ui basic segment">
- <h3 class="ui header">
- <span id="RAIDhealthyState"></span>
- <div class="sub header"><span id="RAIDvolCount">0</span> RAID Storage Volume Detected</div>
- </h3>
- </div>
- -->
- <div class="ui stackable grid">
- <div class="six wide column" style="border-right: 1px solid #e0e0e0;">
- <div id="raidVolList">
- <p style="text-align: center;"><i class="ui loading spinner icon"></i></p>
- </div>
- <div class="ui divider"></div>
- <div style="width: 100%;" align="center">
- <button title="Add new RAID volume" onclick="addNewRaidVolume()" class="circular basic green large ui icon button">
- <i class="green add icon"></i>
- </button>
- <button title="Assemble RAID Pools" onclick="assembleRaidVolumes()" class="circular basic orange large ui button">
- <i class="orange refresh icon"></i> Assemble
- </button>
- </div>
- </div>
- <div class="ten wide column">
- <div id="volumeDetail">
- <div id="raidDiskOverview">
- <h3 class="ui header">
- <i id="RAIDOverviewStateIcon" class="ui green check circle icon"></i>
- <div class="content">
- <span id="RAIDOverviewDiskpath">Loading device details</span>
- <div class="sub header">
- <span id="RAIDOverviewDetails"></span><br>
- <small style="font-weight: 300;" id="RAIDUUID"></small>
- </div>
-
- </div>
- </h3>
-
- <div class="ui divider"></div>
- <div class="ui basic segment deviceOverview">
- <div class="ui tiny four statistics">
- <div class="statistic">
- <div class="value">
- <img src="../disk/raid/img/drive.svg" class="ui inline image">
- <span id="RAIDActiveDevices">0</span>
- </div>
- <div class="label">
- Active Devices
- </div>
- </div>
- <div class="statistic">
- <div class="value">
- <img src="../disk/raid/img/drive-working.svg" class="ui inline image">
- <span id="RAIDWorkingDevices">0</span>
- </div>
- <div class="label">
- Working Devices
- </div>
- </div>
- <div class="statistic">
- <div class="value">
- <img src="../disk/raid/img/drive-failed.svg" class="ui inline image">
- <span id="RAIDFailedDevices">0</span>
- </div>
- <div class="label">
- Failed Devices
- </div>
- </div>
- <div class="statistic">
- <div class="value">
- <img src="../disk/raid/img/drive-spare.svg" class="ui inline image">
- <span id="RAIDSpareDevices">0</span>
- </div>
- <div class="label">
- Spare Devices
- </div>
- </div>
- </div>
- </div>
- <div class="raidOptionBtn">
- <button onclick="reloadRAIDVolDetail();" class="ui basic circular icon button"><i class="ui green refresh icon"></i></button>
- </div>
- <div>
- <button onclick="addDiskToArray();" title="Add new disk to this volume" class="circular small basic ui button">
- <i class="green add icon"></i> Add Disk
- </button>
- <button onclick="expandRAIDArray();" title="Expand volume to fit disks capacity" class="circular small basic ui button">
- <i class="purple expand icon"></i> Expand Volume
- </button>
- </div>
- </div>
- <div class="ui divider"></div>
- <div id="raidDiskList">
-
- </div>
- <div class="ui message" style="display:none;" id="raidDataLossWarning">
- <i class="yellow exclamation triangle icon"></i> Minimum disk number reached. "Remove Disk" function is disabled to prevent data loss.<br>
- </div>
- <div class="ui divider"></div>
- <div style="width: 100%; text-align: center; margin-bottom: 1em;">
- <p><i class="yellow exclamation triangle icon"></i> Danger Zone <i class="yellow exclamation triangle icon"></i></p>
- </div>
- <div style="width: 100%;" align="center">
- <button onclick="RAIDRemove();" class="circular red ui button">
- <i class="trash icon"></i> Remove RAID
- </button>
- </div>
-
-
-
-
- <br><br><br><br>
- </div>
- <div id="noRAIDVolumeWarning" style="display:none;">
- <div class="ui basic segment">
- <h4 class="ui header">
- <img src="../disk/raid/img/drive-notfound.svg">
- <div class="content">
- <span>No RAID Volume</span>
- <div class="sub header">Create a new RAID volume by pressing the <i class="ui green circle add icon" style="margin-right: 0;"></i> button</div>
- </div>
- </h4>
- </div>
- </div>
- </div>
- </div>
- <!-- Disk Remove Confirmation -->
- <div id="confirmDiskRemove" class="ui mini modal">
- <i class="close icon"></i>
- <div class="header">
- Confirm Disk Remove
- </div>
- <div class="image content">
- <div class="ui small image">
- <img src="../disk/raid/img/remove-warning.svg">
- </div>
- <div class="description">
- <p id="oprconfirm"></p>
- <p><b>Removing a disk from RAID volume might risk data loss.</b> Make sure you know what you are doing.<br></p>
- </div>
- </div>
- <div class="actions">
- <div class="ui black deny button">
- Cancel
- </div>
- <div class="ui negative left labeled icon button" onclick="confirmRemoveDisk();">
- <i class="trash icon"></i>
- REMOVE
- </div>
- </div>
- </div>
- <!-- RAID Remove Confirmation -->
- <div id="confirmRAIDRemove" class="ui small modal">
- <i class="close icon"></i>
- <div class="header">
- Confirm RAID Volume Remove
- </div>
- <div class="image content">
- <div class="ui small image">
- <img src="../disk/raid/img/remove-warning.svg">
- </div>
- <div class="description">
- <h4 style="color: rgb(206, 31, 31);"><span id="removingRAIDName"></span></h4>
- <p><b>This will clear all stored data in this volume. Please make sure you have backup all important data.</b> Confirm Remove?<br></p>
- </div>
- </div>
- <div class="actions">
- <div class="ui black deny button">
- Cancel
- </div>
- <div class="ui negative left labeled icon button" onclick="confirmRAIDRemove();">
- <i class="trash icon"></i>
- REMOVE
- </div>
- </div>
- </div>
- <script>
- var raidManager = {
- raidDetails: {}, //The raid array details from last server req
- editingArray: "",
- removePendingDisk: "",
- removePendingSourceVol: ""
- };
- var raidInfoTicker = undefined;
- /* Information Update Ticker */
- function RAIDInfoUpdateTicker(){
- function compareRAIDstate(oldState, newState) {
- const fieldsToCompare = [
- "Consistency",
- "FailedDevices",
- "RebuildStatus",
- "SpareDevices",
- "State",
- "TotalDevices",
- "WorkingDevices"
- ];
- for (const field of fieldsToCompare) {
- if (oldState[field] !== newState[field]) {
- return false;
- }
- }
- return true;
- }
- if ($("#raidDiskOverview").length > 0){
- //Still on the RAID manager page
- if (raidManager.editingArray == undefined || raidManager.editingArray == ""){
- //Nothing selected or loaded. Skip this round
- setTimeout(RAIDInfoUpdateTicker, 10000);
- return;
- }
- $.get("../../system/disk/raid/detail?devName=" + raidManager.editingArray, function(data){
- if (data.error != undefined){
- //Something went wrong loading this array (removed by another admin?)
- }else{
- //Validate if both details are identical
- if (compareRAIDstate(data,raidManager.raidDetails)){
- //No information updated
- }else{
- //Something updated. Reload the RAID volume info
- loadRAIDVolDetail(raidManager.editingArray);
- }
- }
- //Update again later
- raidInfoTicker = setTimeout(RAIDInfoUpdateTicker, 5000);
- });
-
- }else{
- //Release the ticker
- console.log("RAID status ticker released");
- raidInfoTicker = undefined;
- }
-
- }
- //Set the ticker
- if (raidInfoTicker == undefined){
- console.log("RAID status ticker started");
- raidInfoTicker = setTimeout(RAIDInfoUpdateTicker, 1000);
- }
- /* RAID Create Functions */
- function addNewRaidVolume(){
- //Open newRAID window
- parent.newFloatWindow({
- url: "SystemAO/disk/raid/newRAID.html#" + Date.now(),
- width: 940,
- height: 480,
- appicon: "SystemAO/disk/raid/img/raid.svg",
- title: `New RAID volume`,
- parent: ao_module_windowID,
- callback: "handleRAIDCreateCallback"
- });
- }
- window.handleRAIDCreateCallback = function(data){
- //Done adding raid vol
- setTimeout(function(){
- reloadRAIDVolDetail();
- if (data.error != undefined){
- msgbox(capitalize(data.error), false, 5000);
- }else{
- msgbox("New RAID volume created");
- }
-
- }, 300);
- }
- /* RAID Remove Function */
- function RAIDRemove(){
- if (raidManager.editingArray == ""){
- console.log("RAID manager have no editing array set")
- return;
- }
- $("#removingRAIDName").text(raidManager.editingArray);
- $("#confirmRAIDRemove").modal("show");
- }
- function confirmRAIDRemove(){
- var apiObject = {
- api: "../system/disk/raid/remove",
- data: {
- "raidDev": raidManager.editingArray,
- },
- title: `<i class='yellow exclamation triangle icon'></i> REMOVE RAID VOLUME <i class='yellow exclamation triangle icon'></i>`,
- desc: `Confirm format and remove RAID: ${raidManager.editingArray}`,
- thisuser: true, //This username as default, set to false for entering other user
- method: "POST",
- success: undefined
- }
- apiObject = encodeURIComponent(JSON.stringify(apiObject));
-
-
- parent.newFloatWindow({
- url: "SystemAO/security/authreq.html#" + apiObject,
- width: 480,
- height: 300,
- appicon: "SystemAO/security/img/lock.svg",
- title: `Confirm Disk Remove`,
- parent: ao_module_windowID,
- callback: "handleRAIDRemoveCallback"
- });
- }
- window.handleRAIDRemoveCallback = function(data){
- if (data.error != undefined){
- //Something went wrong
- msgbox(capitalize(data.error), false, 5000);
- }else{
- setTimeout(function(){
- //RAID volume not exist anymore. Reset everything
- raidManager = {};
- initRAIDVolList();
- }, 300);
- }
-
- }
- /* New Disk Function */
- function addDiskToArray(arrayName=raidManager.editingArray){
- let payload = {
- "md": arrayName,
- }
- payload = encodeURIComponent(JSON.stringify(payload));
- parent.newFloatWindow({
- url: "SystemAO/disk/raid/newdisk.html#" + payload,
- width: 940,
- height: 480,
- appicon: "SystemAO/disk/raid/img/raid.svg",
- title: `Add new disk to RAID volume ${arrayName}`,
- parent: ao_module_windowID,
- callback: "handleAddDiskCallback"
- });
- }
- window.handleAddDiskCallback = function(data){
- //Done adding disk
- setTimeout(function(){
- msgbox("New disk added");
- reloadRAIDVolDetail();
- }, 300);
- }
- /* RAID Array Expand */
- function expandRAIDArray(arrayName=raidManager.editingArray){
- $.ajax({
- url: "../../system/disk/raid/grow",
- method: "POST",
- data: {
- "raidDev": arrayName,
- },
- success: function(data){
- if (data.error != undefined){
- msgbox(capitalize(data.error), false);
- }else{
- msgbox("mdadm grow operation started");
- reloadRAIDVolDetail();
- }
- }
- })
- }
- /* Disk Remove Functions */
- function removeDisk(arrayName, diskPath){
- console.log(arrayName, diskPath);
- $("#oprconfirm").html("Remove <b>" + diskPath + "</b> from <b>" + arrayName + "</b>");
- $("#confirmDiskRemove").modal('show');
- raidManager.removePendingDisk = diskPath;
- raidManager.removePendingSourceVol = arrayName;
- }
-
- function confirmRemoveDisk(){
- $.ajax({
- url: "../../system/disk/raid/removeMemeber",
- data: {
- raidDev: raidManager.removePendingSourceVol,
- memDev: raidManager.removePendingDisk
- },
- method: "POST",
- success: function(data){
- handleRemoveDiskCallback(data);
- }
- })
- }
- //Remove disk completed
- window.handleRemoveDiskCallback = function(succ){
- console.log(data);
- raidManager.removePendingDisk = "";
- raidManager.removePendingSourceVol = "";
- setTimeout(function(){
- msgbox("Target disk removed");
- reloadRAIDVolDetail();
- }, 300);
- }
- //Quick function to check if the disk is healthy
- function isHealthy(stateText) {
- // Check if the stateText contains any unhealthy states
- if (stateText.includes('faulty') || stateText.includes('resyncing') ||
- stateText.includes('recovering') || stateText.includes('degraded') ||
- stateText.includes('inactive')) {
- return false; // Array is not healthy
- } else {
- return true; // Array is healthy
- }
- }
- //Get the RAID health state icon from state Text
- function getStateIconFromStateText(stateText) {
- if (stateText.includes('faulty')) {
- return 'ui red times circle icon';
- } else if (stateText.includes('resyncing')) {
- return 'ui green loading sync icon';
- } else if (stateText.includes('recovering')) {
- return 'ui yellow loading sync icon';
- } else if (stateText.includes('degraded')) {
- return 'ui yellow exclamation circle icon';
- } else if (stateText.includes('inactive')) {
- return 'ui grey check sync icon';
- } else if (stateText.includes('active')) {
- return 'ui green check circle icon';
- } else if (stateText.includes('clean')) {
- return 'ui green check circle icon';
- } else if (stateText.includes('spare')) {
- return 'ui blue check circle icon';
- } else if (stateText.includes('reshape')) {
- return 'ui blue loading sync icon';
- } else if (stateText.includes('frozen')) {
- return 'ui blue snowflake icon';
- } else {
- return 'ui blue question circle icon';
- }
- }
- //Reload the current raid volume detail
- function reloadRAIDVolDetail(){
- if (raidManager.editingArray != undefined){
- initRAIDVolList(raidManager.editingArray);
- }
- }
- function capitalize(string) {
- return string.charAt(0).toUpperCase() + string.slice(1);
- }
- function loadRAIDVolDetail(deviceName){
- function bytesToSize(bytes) {
- var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB'];
- if (bytes == 0) return 'n/a';
- var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
- if (i == 0) return bytes + ' ' + sizes[i];
- return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i];
- };
- function uuidv4() {
- return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, c =>
- (+c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> +c / 4).toString(16)
- );
- }
- //Highlight the vol selected
- $(".raidVol").removeClass('active');
- $(".raidVol").each(function(){
- if ($(this).attr("devpath") == deviceName){
- $(this).addClass('active');
- }
- })
- let deiviceSizeMap = {};
- let workingDiskCount = 0;
- //Load the device size map
- $.get("../../system/disk/raid/devinfo?devName=" + deviceName, function(sizemap){
- deiviceSizeMap = sizemap;
- raidManager.editingArray = deviceName;
- //Get the information of the device
- $.get("../../system/disk/raid/detail?devName=" + deviceName, function(data){
- if (data.error != undefined){
- $("#raidDiskList").html(`<h3 class="ui header">
- <i class="ui red circle times icon"></i>
- <div class="content" style="font-weight: 300;">
- Unable to load RAID volume information
- <div class="sub header">${capitalize(data.error)}</div>
- </div>
-
- </h3>`);
- return;
- }
- raidManager.raidDetails = data
- //Update the active disks info
- $("#RAIDOverviewDiskpath").html(data.DevicePath + ` <span class="mdevice">(${data.RaidLevel.toUpperCase()})</span>`);
- $("#RAIDOverviewDetails").text("State: " + capitalize(data.State));
- $("#RAIDUUID").text(data.UUID);
- $("#RAIDActiveDevices").text(data.ActiveDevices);
- $("#RAIDWorkingDevices").text(data.WorkingDevices);
- $("#RAIDFailedDevices").text(data.FailedDevices);
- $("#RAIDSpareDevices").text(data.SpareDevices);
- $("#RAIDOverviewStateIcon").attr("class", getStateIconFromStateText(data.State));
-
- //Update the RAIDVol Button on the left menu as well
- $(".raidVol").each(function(){
- if ($(this).attr("devpath") == data.DevicePath){
- //this is the one we are updating
- $(this).find(".healthIcon i").attr("class", getStateIconFromStateText(data.State))
- }
- });
- //Render the disk list
- $("#raidDiskList").html("");
- workingDiskCount = data.DeviceInfo.length;
- for (var i = 0; i < data.DeviceInfo.length; i++){
- let thisDeviceInfo = data.DeviceInfo[i];
- let raidDeviceNo = thisDeviceInfo.RaidDevice;
- let drivePath = thisDeviceInfo.DevicePath
- let driveName = drivePath.split("/").pop();
- let driveIcon = "drive-working.svg";
- let driveSize = "Unknown"; //Overall size of the disk
- let partitionSize = data.ArraySize * 1024; //RAID partition size, mdadm report in KiB
- let driveRWState = "Read Write";
- if (thisDeviceInfo.DevicePath = ""){
- driveIcon = "drive-notfound.svg"
- drivePath = "(Drive unplugged or damaged)"
- }
- let diskIsFailed = false;
- if (thisDeviceInfo.State.includes("faulty")){
- //Disk labeled as failed
- driveIcon = "drive-failed.svg"
- workingDiskCount--;
- diskIsFailed = true;
- }else if (thisDeviceInfo.State.includes("removed")){
- driveIcon = "drive-notfound.svg"
- workingDiskCount--;
- }else if (thisDeviceInfo.State.includes("rebuilding")){
- driveIcon = "drive-spare.svg"
- }
- if (deiviceSizeMap[driveName] == undefined){
- //Disk not found. Is it failed?
- driveSize = "";
- driveRWState = "";
- }else{
- driveSize = bytesToSize(deiviceSizeMap[driveName].size);
- driveRWState = deiviceSizeMap[driveName].ro?"<span class='readonlytag'>Read Only</span>":"Read Write";
- }
- //Handle case where raidDeviceNo is -1 (Not mounted / failed)
- if (raidDeviceNo == -1){
- if (thisDeviceInfo.State.includes("complete")){
- raidDeviceNo = "Rebuilding";
- }else{
- raidDeviceNo = "Faulty";
- }
-
- }
- //A random UID for this DOM element to make handling easier
- let raiddeviceUID = uuidv4();
- $("#raidDiskList").append(`<div class="ui basic segment raiddevice ${raiddeviceUID}" domid="${raiddeviceUID}">
- <h4 class="ui header">
- <img src="../disk/raid/img/${driveIcon}">
- <div class="content">
- ${raidDeviceNo}: <span class="raidMemberLabel ${driveName}"></span><br>
- <small><i class="ui yellow folder icon" style="margin-right: 0.3em;"></i>${drivePath!=""?drivePath:`<span class="notMountedLabel">[Not Mounted]</span>`}</small>
- <div class="sub header">${thisDeviceInfo.State.join(" | ")}</div>
- </div>
- </h4>
- <div class="capinfo">
- <i class="chart pie icon"></i>${bytesToSize(partitionSize)} | <i class="hdd outline icon"></i> ${driveSize}<br>
- <span style="font-size: 0.8em;">${driveRWState}</span>
- </div>
- <div class="raidDeviceOptions">
- <div class="content">
- <button class="ui tiny basic button removeDiskBtn ${diskIsFailed?"faulty":"normal"}" onclick="removeDisk('${deviceName}','${driveName}');"><i class="ui red trash icon"></i> Remove Disk</button>
- </div>
- </div>
- </div>`);
- if (driveName != "" && drivePath != ""){
- $(".raidMemberLabel." + driveName).html(`<i class="ui loading circle notch icon"></i> Resolving disk label`);
- resolveDiskLabelToDOM(drivePath, ".raidMemberLabel." + driveName);
- }else{
- //Invalid disk, e.g. Removed
- $(".raiddevice." + raiddeviceUID).find(".raidDeviceOptions").hide();
- }
- }
- //Check if the current setup is already at the min no. of disk
- let allowRemoveDisk = true;
- if (data.RaidLevel == "raid0"){
- //Do not allow for disk remove
- allowRemoveDisk = false;
- }else if (data.RaidLevel == "raid1" && workingDiskCount < 2){
- allowRemoveDisk = false;
- }else if (data.RaidLevel == "raid5" && workingDiskCount < 3){
- allowRemoveDisk = false;
- }else if (data.RaidLevel == "raid6" && workingDiskCount < 4){
- allowRemoveDisk = false;
- }
- if (!allowRemoveDisk){
- $(".removeDiskBtn.normal").addClass("disabled");
- $("#raidDataLossWarning").show();
- }else{
- $("#raidDataLossWarning").hide();
- }
- });
- });
- }
- function resolveDiskLabelToDOM(diskPath, domSelector){
- $.get("../../system/disk/devices/model?devName=" + diskPath, function(data){
- let diskLabelName = ""
- if (data.error == undefined){
- //[0] is disk labeled name
- //[1] is disk labeled size
- diskLabelName = data[0];
- }
- $(domSelector).html(diskLabelName);
- });
- }
- //Initialize the RAID volume list on this system
- //Give selectMDName for auto selecting a volume
- function initRAIDVolList(selectMDName=""){
- $("#raidVolList").html(`<p style="text-align: center;"><i class="ui loading spinner icon"></i></p>`);
- $.get("../../system/disk/raid/list", function(data){
- if (data.error != undefined){
- $("#raidVolList").html(`<p style="text-align: center;"><i class="ui red circle remove icon"></i> ${data.error}</p>`);
- return;
- }
- $("#raidVolList").html("");
- let containUnhealthyDisk = false;
- for (var i = 0; i < data.length; i++){
- let thisDiskInfo = data[i];
- $("#raidVolList").append(`<div class="ui segment raidVol" devpath="${thisDiskInfo.DevicePath}">
- <h4 class="ui header">
- <img src="../disk/raid/img/raid.svg">
- <div class="healthIcon"><i class="${getStateIconFromStateText(thisDiskInfo.State)}"></i></div>
- <div class="content" style="margin-left: 0.6em;">
- <span>${thisDiskInfo.DevicePath}</span> <span class="mdevice">(${thisDiskInfo.RaidLevel.toUpperCase()})</span>
- <div class="sub header mdevuuid" style="margin-top: 0.4em;">
- ${thisDiskInfo.UUID}
- </div>
- </div>
- </h4>
- </div>`);
- if (!isHealthy(thisDiskInfo.State)){
- containUnhealthyDisk = true;
- }
- console.log(thisDiskInfo);
- }
- if (data.length == 0){
- $("#raidVolList").html(`<div><i class="ui green check circle icon"></i> No RAID Volumes</div>`);
- $("#volumeDetail").hide();
- $("#noRAIDVolumeWarning").show();
- }else{
- $("#volumeDetail").show();
- $("#noRAIDVolumeWarning").hide();
- //Load the first RAID vol info
- if (selectMDName){
- loadRAIDVolDetail(selectMDName);
- }else{
- loadRAIDVolDetail(data[0].DevicePath);
- }
-
- }
- $("#RAIDvolCount").text(data.length);
- //Update the overall health text
- if (containUnhealthyDisk){
- $("#RAIDhealthyState").html("<i class='ui yellow exclamation triangle icon'></i> Attention Needed!");
- }else{
- $("#RAIDhealthyState").html("<i class='ui green circle check icon'></i> Healthy");
- }
- });
- }
- initRAIDVolList();
-
- /* Force unload all RAID volume and remount them from config files */
- function assembleRaidVolumes(){
- var apiObject = {
- api: "../system/disk/raid/assemble",
- data: {},
- title: `<i class='yellow exclamation triangle icon'></i> Force Assemble`,
- desc: `Confirm force stop & reload RAID from mdadm.conf?`,
- thisuser: true, //This username as default, set to false for entering other user
- method: "POST",
- success: undefined
- }
- apiObject = encodeURIComponent(JSON.stringify(apiObject));
-
-
- parent.newFloatWindow({
- url: "SystemAO/security/authreq.html#" + apiObject,
- width: 480,
- height: 300,
- appicon: "SystemAO/security/img/lock.svg",
- title: `Confirm Force Assemble`,
- parent: ao_module_windowID,
- callback: "handleForceAssembleCallback"
- });
- }
- window.handleForceAssembleCallback = function(data){
- if (data.error != undefined){
- //Something went wrong
- msgbox(capitalize(data.error), false, 5000);
- }else{
- setTimeout(function(){
- //Reload all RAID volumes
- raidManager = {};
- initRAIDVolList();
- if (data != false){
- msgbox("Force RAID Assemble Completed");
- }
-
- }, 300);
- }
-
- }
- </script>
- </body>
- </html>
|