From f686d6634af455881afa4b8e6d365f0ca0a58084 Mon Sep 17 00:00:00 2001 From: optimans <58222345+iamoptimans@users.noreply.github.com> Date: Tue, 28 Apr 2020 22:16:16 +0800 Subject: [PATCH] 0.3.1.301 --- zfs/zfs.css | 4691 +++--- zfs/zfs.js | 41724 +++++++++++++++++++++++++------------------------- 2 files changed, 23210 insertions(+), 23205 deletions(-) diff --git a/zfs/zfs.css b/zfs/zfs.css index 78d1b07..2248519 100644 --- a/zfs/zfs.css +++ b/zfs/zfs.css @@ -1,2197 +1,2202 @@ -/* - * This file is part of Cockpit ZFS Manager. - * - * Copyright (C) 2019-2020 OPTIMANS Pty Ltd. - * - * Cockpit ZFS Manager is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 3 of the License, or (at your option) - * any later version. - * - * Cockpit ZFS Manager is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for - * more details. - * - * You should have received a copy of the GNU Lesser General Public License along - * with Cockpit ZFS Manager; If not, see . - */ - - -/* Portions of Cockpit Storage 208 and PatternFly 4 styles appended */ - -a.disabled, -a[disabled], -.btn.disabled, -.btn[disabled], -fieldset[disabled] .btn { - cursor: not-allowed !important; -} - -.btn-group > .dropdown-menu.dropdown-menu-right { - margin-right: 0px !important; - overflow-x: visible !important; -} - -.blank-slate-ct { - height: 100%; - position: fixed; - top: 0px; - width: 100%; -} - -/* Fix for extra long text in dropdown */ -.ct-form .dropdown-toggle { - position: absolute; -} - - /* Fix for extra long text in dropdown */ - .ct-form .dropdown-toggle > span { - max-width: 100%; - padding-right: 25px; - text-align: left; - } - -.ct-form-spacing { - padding-top: 1.5rem; -} - -.dialog-item-ct-popover, -.dialog-item-ct-tooltip { - margin-left: 0.5em; - white-space: nowrap; -} - -.dialog-wait-ct { - margin-top: 7px; -} - - .dialog-wait-ct .spinner { - display: inline-block; - } - - .dialog-wait-ct span { - padding-left: 10px; - vertical-align: 7px; - } - -.dropdown.dropdown-kebab-pf > .dropdown-menu.dropdown-menu-right { - margin-right: 15px !important; - overflow-x: visible !important; -} - -.list-group-ct-warning { - color: var(--pf-global--danger-color--100); -} - -.list-unstyled-ct { - word-break:break-word; -} - -.listing-ct .listing-ct-actionsmenu { - width: 60px !important; -} - - .listing-ct .listing-ct-actionsmenu .text-ct-locked { - color: var(--color-button-primary); - } - -.listing-ct .listing-ct-icon .pficon-ct-locked { - color: var(--color-button-primary); -} - -.listing-ct .pficon-ct-bootreadonly { - color: var(--pf-global--primary-color--100); -} - -.listing-ct .pficon-ct-altroot, -.listing-ct .pficon-ct-readonly { - color: var(--pf-global--secondary-color--100); -} - -.listing-ct .listing-ct-icon .pficon-ct-upgrade { - color: var(--pf-global--warning-color--100); -} - -.listing-ct-wordwrap { - word-break: break-all; -} - -.listing-ct .listing-ct-icon { - width: 35px !important; -} - -.listing-ct .listing-ct-spinner { - width: 50px !important; -} - -.listing-ct .listing-ct-toggle:empty, -.listing-ct .listing-ct-toggle-snapshots { - width: 45px !important; -} - -.listing-ct .listing-ct-body-spinner { - padding: 1rem 1.5rem; -} - -.listing-ct-item > .listing-ct-toggle + td { - font-weight: bold; -} - -.listing-ct-item > td > span.table-ct-head, -.listing-ct-item > td.listing-ct-icon > span.table-ct-text, -.table.table-ct-filesystems > tbody > tr > td > span.table-ct-head, -.table.table-ct-snapshots > tbody > tr > td > span.table-ct-head, -.table.table-ct-status-config > tbody > tr > td > span.table-ct-head, -.table.table-ct-filesystems > tbody > tr > td > span.table-ct-text, -.table.table-ct-snapshots > tbody > tr > td > span.table-ct-text, -.table.table-ct-status-config > tbody > tr > td > span.table-ct-text { - display: none; -} - -.listing-ct-wide { - table-layout: fixed; -} - -.modal-content .ct-form .alert { - line-height: var(--pf-global--LineHeight--md); -} - -.modal-content .modal-ct-name { - word-break: break-all; -} - -.modal-ct-bodytext-1 { - padding-bottom: 1.5rem; -} - -.modal-ct-bodytext-2 { - padding-bottom: 3rem; -} - -.modal-ct-buttons { - display: inline-block; -} - -.open .dropdown-toggle.btn-default { - color: var(--pf-global--Color--100); -} - -.panel { - border: 0px !important; - margin-bottom: 0px; -} - - .panel > .panel-heading > .panel-ct-heading .spinner.spinner-sm { - float: left; - } - -.pf-c-alert__description { - word-break: break-all; -} - - .pf-c-alert__description.break-word { - word-break: break-word !important; - } - -.pficon-ct-filesystems { - margin-top: 5px; -} - -.progress.progress-sm { - display: list-item; - margin-bottom: 0px; -} - -.select-ct-disk-row { - align-items: center; - cursor: pointer; - display: flex; -} - - .select-ct-disk-row :nth-child(1) { - margin-top: 0px; - } - - .select-ct-disk-row :nth-child(2) { - flex-grow: 1; - margin-left: 10px; - } - -.select-ct-disk-row-id { - display: block !important; - font-size: var(--pf-global--FontSize--xs); - padding-right: 10px; - word-break:break-all; -} - -.select-ct-pool-row { - align-items: center; - cursor: pointer; - display: flex; -} - - .select-ct-pool-row :nth-child(1) { - margin-top: 0px; - } - - .select-ct-pool-row :nth-child(2) { - flex-grow: 1; - margin-left: 10px; - } - -.select-ct-pool-row-guid { - display: block !important; - font-size: var(--pf-global--FontSize--xs); - padding-right: 5px; - word-break: break-all; -} - +/* + * This file is part of Cockpit ZFS Manager. + * + * Copyright (C) 2019-2020 OPTIMANS Pty Ltd. + * + * Cockpit ZFS Manager is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 3 of the License, or (at your option) + * any later version. + * + * Cockpit ZFS Manager is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with Cockpit ZFS Manager; If not, see . + */ + + +/* Portions of Cockpit Storage 208 and PatternFly 4 styles appended */ + +a.disabled, +a[disabled], +.btn.disabled, +.btn[disabled], +fieldset[disabled] .btn { + cursor: not-allowed !important; +} + +.btn-group > .dropdown-menu.dropdown-menu-right { + margin-right: 0px !important; + overflow-x: visible !important; +} + +.blank-slate-ct { + height: 100%; + position: fixed; + top: 0px; + width: 100%; +} + +/* Fix for extra long text in dropdown */ +.ct-form .dropdown-toggle { + position: absolute; +} + + /* Fix for extra long text in dropdown */ + .ct-form .dropdown-toggle > span { + max-width: 100%; + padding-right: 25px; + text-align: left; + } + +.ct-form-spacing { + padding-top: 1.5rem; +} + +.dialog-item-ct-popover, +.dialog-item-ct-tooltip { + margin-left: 0.5em; + white-space: nowrap; +} + +.dialog-wait-ct { + margin-top: 7px; +} + + .dialog-wait-ct .spinner { + display: inline-block; + } + + .dialog-wait-ct span { + padding-left: 10px; + vertical-align: 7px; + } + +.dropdown.dropdown-kebab-pf > .dropdown-menu.dropdown-menu-right { + margin-right: 15px !important; + overflow-x: visible !important; +} + +.list-group-ct-warning { + color: var(--pf-global--danger-color--100); +} + +.list-unstyled-ct { + word-break:break-word; +} + +.listing-ct .listing-ct-actionsmenu { + width: 60px !important; +} + + .listing-ct .listing-ct-actionsmenu .text-ct-locked { + color: var(--color-button-primary); + } + +.listing-ct .listing-ct-icon .pficon-ct-locked { + color: var(--color-button-primary); +} + +.listing-ct .pficon-ct-bootreadonly { + color: var(--pf-global--primary-color--100); +} + +.listing-ct .pficon-ct-altroot, +.listing-ct .pficon-ct-readonly { + color: var(--pf-global--secondary-color--100); +} + +.listing-ct .listing-ct-icon .pficon-ct-upgrade { + color: var(--pf-global--warning-color--100); +} + +.listing-ct-wordwrap { + word-break: break-all; +} + +.listing-ct .listing-ct-icon { + width: 35px !important; +} + +.listing-ct .listing-ct-spinner { + width: 50px !important; +} + +.listing-ct .listing-ct-toggle:empty, +.listing-ct .listing-ct-toggle-snapshots { + width: 45px !important; +} + +.listing-ct .listing-ct-body-spinner { + padding: 1rem 1.5rem; +} + +.listing-ct-item > .listing-ct-toggle + td { + font-weight: bold; +} + +.listing-ct-item > td > span.table-ct-head, +.listing-ct-item > td.listing-ct-icon > span.table-ct-text, +.table.table-ct-filesystems > tbody > tr > td > span.table-ct-head, +.table.table-ct-snapshots > tbody > tr > td > span.table-ct-head, +.table.table-ct-status-config > tbody > tr > td > span.table-ct-head, +.table.table-ct-filesystems > tbody > tr > td > span.table-ct-text, +.table.table-ct-snapshots > tbody > tr > td > span.table-ct-text, +.table.table-ct-status-config > tbody > tr > td > span.table-ct-text { + display: none; +} + +.listing-ct-wide { + table-layout: fixed; +} + +.modal-content .ct-form .alert { + line-height: var(--pf-global--LineHeight--md); +} + +.modal-content .modal-ct-name { + word-break: break-all; +} + +.modal-ct-bodytext-1 { + padding-bottom: 1.5rem; +} + +.modal-ct-bodytext-2 { + padding-bottom: 3rem; +} + +.modal-ct-buttons { + display: inline-block; +} + +/* Temp fix for modal buttons with Cockpit 217. 0.4 will be in React which will resolve this */ +.modal-footer { + text-align: right; +} + +.open .dropdown-toggle.btn-default { + color: var(--pf-global--Color--100); +} + +.panel { + border: 0px !important; + margin-bottom: 0px; +} + + .panel > .panel-heading > .panel-ct-heading .spinner.spinner-sm { + float: left; + } + +.pf-c-alert__description { + word-break: break-all; +} + + .pf-c-alert__description.break-word { + word-break: break-word !important; + } + +.pficon-ct-filesystems { + margin-top: 5px; +} + +.progress.progress-sm { + display: list-item; + margin-bottom: 0px; +} + +.select-ct-disk-row { + align-items: center; + cursor: pointer; + display: flex; +} + + .select-ct-disk-row :nth-child(1) { + margin-top: 0px; + } + + .select-ct-disk-row :nth-child(2) { + flex-grow: 1; + margin-left: 10px; + } + +.select-ct-disk-row-id { + display: block !important; + font-size: var(--pf-global--FontSize--xs); + padding-right: 10px; + word-break:break-all; +} + +.select-ct-pool-row { + align-items: center; + cursor: pointer; + display: flex; +} + + .select-ct-pool-row :nth-child(1) { + margin-top: 0px; + } + + .select-ct-pool-row :nth-child(2) { + flex-grow: 1; + margin-left: 10px; + } + +.select-ct-pool-row-guid { + display: block !important; + font-size: var(--pf-global--FontSize--xs); + padding-right: 5px; + word-break: break-all; +} + .select-ct-pool-row-health { white-space: nowrap; -} - -.select-ct-pool-row-identifier, -.select-ct-pool-row-physec { - font-size: var(--pf-global--FontSize--xs); - margin-left: 0px !important; -} - -.select-ct-filesystem-row { - align-items: center; - cursor: pointer; - display: flex; - word-break: break-all; -} - - .select-ct-filesystem-row :nth-child(1) { - margin-top: 0px; - } - - .select-ct-filesystem-row :nth-child(2) { - flex-grow: 1; - margin-left: 10px; - } - -.slider-pf { - margin: 0 0 0 8px; -} - - .slider-pf > .size-ct-text { - display: inline; - margin: 2px 2px 2px 8px; - text-align: right; - width: 5em; - } - - .slider-pf > .size-ct-text .disabled { - cursor: not-allowed !important; - pointer-events: inherit !important; - } - - .slider-pf > .dropdown { - flex: 1 0 80px; - } - - .slider-pf > .dropdown > .size-ct-unit > span { - padding-right: 0px; - } - - .slider-pf > span { - padding-left: 5px; - } - -.slider-selection { - background-color: var(--color-link); - background-image: linear-gradient(to bottom,var(--color-link) 0%,var(--color-link) 100%); -} - -.slider.slider-horizontal { - height: 16px; - margin: 0 8px 0 0; - width: 100%; -} - - .slider.slider-horizontal .slider-track { - height: 5px; - left: 0; - margin-top: -2px; - top: 50%; - width: 100%; - } - -.slider-handle { - background-color: var(--color-link) !important; - background-image: linear-gradient(to bottom,var(--color-link) 0%,var(--color-link) 100%) !important; - border: 0px; - border-radius: 9px; - cursor: pointer !important; - height: 18px; - margin: 0 0 0 -8px !important; - width: 18px; -} - - .slider-handle.disabled { - background-color: var(--color-subtle-copy) !important; - background-image: linear-gradient(to bottom,var(--color-subtle-copy) 0%,var(--color-subtle-copy) 100%) !important; - cursor: not-allowed !important; - } - -.slider-selection.disabled { - background-color: var(--color-subtle-copy); - background-image: linear-gradient(to bottom,var(--color-subtle-copy) 0%,var(--color-subtle-copy) 100%); -} - -.slider-track { - background-color: #ededed; - border: 0px; - box-shadow: none; -} - - .slider-track.disabled { - background-color: var(--color-subtle-copy); - border: 0px; - } - -.slider-track-high { - background-color: #ededed; -} - -.slider-track-low { - background-color: var(--color-link); - background-image: linear-gradient(to bottom,var(--color-link) 0%,var(--color-link) 100%); -} - - .slider-track-low.disabled { - background-color: var(--color-subtle-copy); - background-image: linear-gradient(to bottom,var(--color-subtle-copy) 0%,var(--color-subtle-copy) 100%); - } - -.table { - table-layout: fixed !important; -} - - .table > thead > tr > th, - .table > tbody > tr > td { - padding: 0.4rem; - vertical-align: middle; - } - - .table > tbody > tr > td.ct-spacing { - padding-bottom: 1.7rem; - } - - .table > tbody > tr > td.config-level-0-sub-hidden { - padding: 0px !important; - } - - .table > tbody > tr > td.config-level-1 { - padding-left: 3em !important; - } - - .table > tbody > tr > td.config-level-2 { - padding-left: 5em !important; - } - - .table > tbody > tr > td.config-level-3 { - padding-left: 7em !important; - } - - .table > tbody > tr > td.config-level-4 { - padding-left: 9em !important; - } - - .table > tbody > tr > td > span.config-count-danger { - color: var(--pf-global--danger-color--100); - } - - .table > tbody > tr > td > span.config-count-warning { - color: var(--pf-global--warning-color--100); - } - - .table[id^="table-storagepool-status-"] > thead, - .table[id^="table-storagepool-status-"] > thead > tr, - .table[id^="table-storagepool-status-"] > thead > tr > th { - border: 0 none !important; - height: 0 !important; - opacity: 0 !important; - padding: 0 !important; - } - - .table.table-ct-snapshots { - margin-bottom: 0px !important; - } - -tbody > tr.listing-ct-item.listing-ct-storagepoolsnotfound { - cursor: default !important; -} - - tbody > tr.listing-ct-item.listing-ct-storagepoolsnotfound > td:first-child { - padding-left: 50px; - } - -tbody > tr.listing-ct-item-snapshots { - border-bottom: 0px !important; -} - -.toast-notifications-list-pf { - top: 20px; -} - -.toast-pf > span > span.toast-ct-description { - word-break: break-all; -} - - .toast-pf > span > span.toast-ct-description.break-word { - word-break: break-word !important; - } - -/* Fix for flashing tooltip */ -.tooltip { - pointer-events: none !important; - position: fixed; -} - -.tooltip-inner { - overflow-wrap: break-word; -} - -@media screen and (max-width: 343px) { - .dropdown-menu-right { - left: auto; - right: auto; - } -} - -@media screen and (max-width: 480px) { - .dropdown-ct-status { - left: auto !important; - right: auto !important; - } - - .panel > .panel-heading > .panel-ct-actions { - text-align: left !important; - } - - .panel > .panel-heading > .panel-ct-heading, - .panel > .panel-heading > .panel-ct-heading > .panel-title { - min-height: 32px; - min-width: 100%; - } -} - -@media screen and (min-width: 401px) and (max-width: 525px) { - .dropdown-menu-right { - left: auto; - right: auto; - } -} - -@media screen and (min-width: 481px) and (max-width: 525px) { - .dropdown-ct-status { - left: auto !important; - right: 0 !important; - } -} - -@media screen and (max-width: 640px) { - .dialog-wait-ct { - margin-bottom: 0.5em; - } - - .listing-ct > thead > tr:first-child { - display: none; - } - - .listing-ct-actions > div > button.btn, - .listing-ct-actions > div > div.btn-group { - margin-bottom: 5px !important; - } - - .listing-ct-item > td { - padding: 0.5rem !important; - vertical-align: middle !important; - } - - .listing-ct-item > td.listing-ct-actionsmenu { - display: table-cell !important; - } - - .listing-ct-item > td:not(:first-child), - .listing-ct-item > th { - display: block; - max-width: 100% !important; - } - - .listing-ct-item > td > span.table-ct-head, - .table.table-ct-filesystems > tbody > tr > td > span.table-ct-head, - .table.table-ct-snapshots > tbody > tr > td > span.table-ct-head, - .table.table-ct-status-config > tbody > tr > td > span.table-ct-head { - color: var(--color-subtle-copy); - display: inherit !important; - float: left; - font-weight: normal; - padding-right: 0.5em; - } - - .listing-ct-item > td.listing-ct-icon > span.table-ct-text, - .table.table-ct-filesystems > tbody > tr > td > span.table-ct-text, - .table.table-ct-snapshots > tbody > tr > td > span.table-ct-text, - .table.table-ct-status-config > tbody > tr > td > span.table-ct-text { - display: inline-block !important; - padding-right: 0.5em; - } - - .listing-ct-item > td.listing-ct-icon, - .table.table-ct-filesystems > tbody > tr > td.listing-ct-icon, - .table.table-ct-snapshots > tbody > tr > td.listing-ct-icon, - .listing-ct .listing-ct-icon { - width: 100% !important; - } - - .listing-ct-wide { - table-layout: initial; - } - - .panel { - overflow-x: visible !important; - } - - .panel > .panel-heading { - position: inherit !important; - } - - .panel > .panel-heading > .panel-actions > button.btn { - margin-bottom: 5px !important; - } - - .table tbody tr > :first-child { - padding-left: 0.4rem !important; - } - - .table > tbody > tr > td.config-level-0-sub { - clear: both; - } - - .table > tbody > tr > td.config-level-0-sub::after, - .table > tbody > tr > td.config-level-1-sub::after, - .table > tbody > tr > td.config-level-2-sub::after, - .table > tbody > tr > td.config-level-3-sub::after, - .table > tbody > tr > td.config-level-4-sub::after { - content: "\00a0"; - } - - .table > tbody > tr > td.config-level-0-sub-hidden, - .table > tbody > tr > td.config-level-1-sub-hidden { - display: none !important; - } - - .table > tbody > tr > td.config-level-1, - .table > tbody > tr > td.config-level-1-sub { - padding-left: 1.5em !important; - } - - .table > tbody > tr > td.config-level-2, - .table > tbody > tr > td.config-level-2-sub { - padding-left: 3em !important; - } - - .table > tbody > tr > td.config-level-3, - .table > tbody > tr > td.config-level-3-sub { - padding-left: 4.5em !important; - } - - .table > tbody > tr > td.config-level-4, - .table > tbody > tr > td.config-level-4-sub { - padding-left: 6em !important; - } - - .table-ct-filesystems > thead, - .table-ct-snapshots > thead, - .table-ct-status-config > thead { - display: none; - } - - .table-ct-filesystems > tbody > tr > td:not(:last-child), - .table-ct-snapshots > tbody > tr > td:not(:last-child), - .table-ct-status-config > tbody > tr > td:not(:nth-last-child(-n+2)) { - display: block; - max-width: 100% !important; - } - - .table-ct-status-config > tbody > tr.table-ct-confighead { - display: none; - } - - .table-ct-status-config > tbody > tr > td.config-level-0-virtualdevice { - display: table-cell !important; - } -} - - - -/* - * This file is part of Cockpit. - * - * Copyright (C) 2015 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - - -.btn-group, .btn-group-vertical { - /* Fix button groups from wrapping in narrow widths */ - display: inline-flex; -} - -.dropdown-menu > li > a.disabled, -.dropdown-menu > li > a.disabled:hover, -.dropdown-menu > li > a.disabled:focus { - color: var(--color-subtle-copy); -} - - .dropdown-menu > li > a.disabled:hover, - .dropdown-menu > li > a.disabled:focus { - text-decoration: none; - background-color: transparent; - background-image: none; - border-color: transparent; - filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); - cursor: default; - } - -/* Limit dropdown menus to 90% of the viewport size */ -.dropdown-menu { - height: auto; - overflow-y: auto; - max-height: 90vh; -} - -/* Allow kebab menus to have a ^ with overflowing */ -/* Note: This means kebab menus cannot be _too_ long */ -.dropdown-kebab-pf > .dropdown-menu { - overflow: visible; -} - -.dialog-list-ct { - max-height: 230px; - overflow-x: auto; - border: 1px solid var(--color-light-gray); - margin-bottom: 0px; -} - -:root { - /* Custom font aliases */ - --font-family: var(--pf-global--FontFamily--sans-serif); - --font-family-mono: var(--pf-global--FontFamily--monospace); - --font-size: var(--pf-global--FontSize--md); - --font-size-s: var(--pf-global--FontSize--sm); - --font-size-xs: var(--pf-global--FontSize--xs); - --font-size-l: var(--pf-global--FontSize--lg); - --font-size-xl: var(--pf-global--FontSize--xl); - --font-size-2xl: var(--pf-global--FontSize--2xl); - --font-size-3xl: var(--pf-global--FontSize--3xl); - - /* Cockpit custom colors */ - --color-ct-light-red-1: #f8cccc; - --color-ct-light-red-2: #f8acac; - --color-ct-light-red-3: #f98383; - --color-ct-brick-gold: #ffa763; - --color-ct-brick-red: #a53131; - - --color-ct-nav: #1b1b1b; - --color-ct-nav-sub: var(--pf-global--BackgroundColor--dark-300); - --color-ct-nav-text: var(--pf-global--BackgroundColor--light-300); - --color-ct-nav-active: var(--pf-global--BackgroundColor--dark-400); - --color-ct-nav-active-text: var(--pf-global--BackgroundColor--light-100); - --color-ct-nav-hover: var(--pf-global--BackgroundColor--dark-400); - --color-ct-nav-hover-text: var(--pf-global--BackgroundColor--light-100); - --color-ct-nav-border: var(--pf-global--BorderColor--100); - --color-ct-nav-cover-up: linear-gradient(to bottom, var(--color-ct-nav-sub), rgba(21,21,21, 0)); - --color-ct-nav-cover-down: linear-gradient(to top, var(--color-ct-nav-sub), rgba(21,21,21, 0)); - - --color-ct-nav-main: #1b1b1b; - --color-ct-nav-main-text: var(--color-ct-nav-text); - --color-ct-nav-main-border: var(--pf-global--BackgroundColor--dark-200); - --color-ct-nav-main-active: var(--color-ct-nav-sub); - --color-ct-nav-main-active-text: var(--color-ct-nav-active-text); - --color-ct-nav-main-hover: var(--color-ct-nav-hover); - --color-ct-nav-main-hover-text: var(--color-ct-nav-hover-text); - - --color-border: var(--pf-global--BorderColor--100); - - --color-ct-list-text: var(--color-text); - --color-ct-list-link: var(--color-link); - --color-ct-list-bg: var(--color-bg); - --color-ct-list-border: var(--color-border); - --color-ct-list-hover-text: var(--color-link); - --color-ct-list-hover-bg: var(--pf-global--BackgroundColor--150); - --color-ct-list-hover-border: var(--pf-global--BackgroundColor--150); - --color-ct-list-hover-icon: var(--color-blue); - --color-ct-list-selected-text: var(--color-link); - --color-ct-list-selected-bg: var(--pf-global--BackgroundColor--150); - --color-ct-list-selected-border: var(--pf-global--BackgroundColor--150); - --color-ct-list-active-text: var(--color-link-focus); - --color-ct-list-active-bg: var(--color-bg); - --color-ct-list-active-border: var(--color-ct-list-border); - --color-ct-list-critical-bg: var(--color-ct-light-red-1); - --color-ct-list-critical-border: var(--color-ct-light-red-2); - --color-ct-list-critical-bg-hover: var(--color-ct-light-red-2); - --color-ct-list-critical-border-hover: var(--color-ct-light-red-3); - - --color-link-hover-bg: var(--color-light-blue-2); - --color-link-hover-icon: var(--color-blue-5); - - /* Red Hat Digital Design System 2019 named colors */ - --color-red-hat-red: #ee0000; - --color-red-1: #cc0000; - --color-red-2: #a30000; - --color-red-3: #820000; - --color-dark-red-4: #5a0000; - --color-dark-red-5: #460000; - --color-dark-red-6: #320000; - --color-black: #000000; - --color-white: #ffffff; - --color-dark-blue: #004153; - --color-light-blue: #a3dbe8; - --color-dark-gray: #4c4c4c; - --color-light-gray: #dcdcdc; - --color-purple: #3b0083; - --color-gold: #f0ab00; - --color-teal: #007987; - --color-blue: #00b9e4; - --color-green: #92d400; - --color-storage: #ec7a08; - --color-infra: #0088ce; - --color-app-dev: #3f9c35; - --color-light-blue-1: #e8f6f9; - --color-light-blue-2: #d1edf4; - --color-light-blue-3: #b6e2ec; - --color-dark-blue-1: #80a0a9; - --color-dark-blue-2: #4e7a86; - --color-dark-blue-3: #1b5764; - --color-blue-1: #d9f5fb; - --color-blue-2: #c0edf7; - --color-blue-3: #9ae4f3; - --color-blue-4: #82ddf1; - --color-blue-5: #68d6ee; - --color-blue-6: #38c8e8; - --color-teal-1: #d9ebed; - --color-teal-2: #cbe4f1; - --color-teal-3: #b3d7db; - --color-teal-4: #9acacf; - --color-teal-5: #68afb6; - --color-teal-6: #36959e; - --color-green-1: #eaf5cd; - --color-green-2: #dff1b4; - --color-green-3: #d4ec9c; - --color-green-4: #cae883; - --color-green-5: #b5df56; - --color-green-6: #aadb40; - --color-gold-1: #fcedcd; - --color-gold-2: #fae5b4; - --color-gold-3: #f9dc9c; - --color-gold-4: #f8d384; - --color-gold-5: #f5c255; - --color-gold-6: #f2b22d; - --color-purple-1: #e2daec; - --color-purple-2: #cdc0df; - --color-purple-3: #b09bcc; - --color-purple-4: #9c82c0; - --color-purple-5: #8869b3; - --color-purple-6: #7551a6; - --color-gray-1: #f0f0f0; - --color-gray-2: #e6e6e6; - --color-gray-3: #d2d2d2; - --color-gray-4: #bebebe; - --color-gray-5: #aaaaaa; - --color-gray-6: #969696; - --color-gray-7: #828282; - --color-gray-8: #6e6e6e; - --color-gray-9: #5a5a5a; - --color-gray-10: #464646; - --color-gray-11: #323232; - --color-gray-12: #1e1e1e; - - /* Semantic colors */ - --color-fg: #151515; - --color-bg: #fff; - --color-text: var(--color-fg); - - --color-link: #0066cc; - --color-link-visited: #0066cc; - --color-link-hover: #004080; - --color-link-focus: #004080; - --color-link-dark: #73bcf7; - --color-link-visited-dark: #73bcf7; - --color-link-hover-dark: #2b9af3; - --color-link-focus-dark: #2b9af3; - - --color-heading: #151515; - --color-heading-dark: #ffffff; - --color-body-copy: #151515; - --color-body-copy-dark: #cccccc; - --color-body-copy-dark-color: rbga(255,255,255,0.8); - --color-subtle-copy: #72767b; - --color-subtle-text-dark: #cccccc; - - --color-alert-success-bg: #ffffff; - --color-alert-sucess-icon: #92d400; - --color-alert-sucess-border: #92d400; - --color-alert-success-text: #486b00; - --color-alert-info-bg: #ffffff; - --color-alert-info-icon: #39a5dc; - --color-alert-info-border: #39a5dc; - --color-alert-info-text: #004368; - --color-alert-warning-bg: #ffffff; - --color-alert-warning-icon: #f0ab00; - --color-alert-warning-border: #f0ab00; - --color-alert-warning-text: #795600; - --color-alert-danger-bg: #ffffff; - --color-alert-danger-icon: #c9190b; - --color-alert-danger-border: #c9190b; - --color-alert-danger-text: #7d1007; - - --color-low-severity-background: #ffffff; - --color-low-severity-icon: #72767b; - --color-low-severity-border: #72767b; - --color-low-severity-text: #151515; - --color-moderate-severity-background: #ffffff; - --color-moderate-severity-icon: #f0ab00; - --color-moderate-severity-border: #f0ab00; - --color-moderate-severity-text: #795600; - --color-important-severity-background: #ffffff; - --color-important-severity-icon: #df7409; - --color-important-severity-border: #df7409; - --color-important-severity-text: #8f4c09; - --color-critical-severity-background: #ffffff; - --color-critical-severity-icon: #c9190b; - --color-critical-severity-border: #c9190b; - --color-critical-severity-text: #7d1007; - - --color-cta-default: #0066cc; - --color-cta-default-hover: #004080; - --color-cta-primary: #ee0000; - --color-cta-primary-hover: #d40000; - --color-cta-secondary: #151515; - --color-cta-secondary-hover: #151515; - --color-cta-accent: #0066cc; - --color-cta-accent-hover: #0066cc; - - --color-button-text: #ffffff; - --color-button-text-dark: #151515; - --color-button-default: #151515; - --color-button-default-hover: #151515; - --color-button-primary: #0066cc; - --color-button-primary-hover: #004080; - --color-button-secondary: #0066cc; - --color-button-secondary-hover: #0066cc; - --color-button-disabled: #d2d2d2; - --color-button-disabled-text: #72767b; - - --color-border-lighter: #d2d2d2; - --color-border-default: #d2d2d2; - --color-border-darker: #d2d2d2; - - --color-potential-band-color: #f0f0f0; - --color-ui-hover-bg: #ededed; - --color-ui-alternate-row-bg: #ededed; - - --color-label: #151515; - --color-form-field-bottom-border: #8b8d8f; - --color-form-field-border: #0066cc; - --color-form-field-focus: #0066cc; - --color-form-field-bg: #ffffff; - --color-form-field-text: #151515; - --color-form-field-error-border: #a30000; - --color-form-field-error-bg: #ffffff; - --color-form-field-error-text: #a30000; - --color-form-field-active-border: #0066cc; - --color-select-dropdown-bottom-border: #8b8d8f; - --color-select-dropdown-bg: #ffffff; - --color-select-dropdown-arrow-color: #151515; - --color-select-dropdown-text-color: #151515; - - --color-breadcrumb-link: #0066cc; - --color-breadcrumb-link-hover: #004080; - --color-breadcrumb-text: #151515; - - --color-pagination-current-text: #393f44; - - --color-chips: #72767b; - --color-chips-secondary: #72767b; - --color-chips-hover: #72767b; - - --color-tab-link: #007bba; - --color-tab-text: #007bba; - --color-tab-indicator-color: #007bba; - --color-tab-bg: #ffffff; - --color-tab-border: #ededed; - --color-tab-selected-text: #007bba; - --color-tab-selected-indicator-color: #007bba; - --color-tab-selected-bg: #ffffff; - --color-tab-selected-border: #ededed; - - --color-tooltips-bg: #ffffff; - --color-tooltips-text: #151515; - - --color-modal-bg: #ffffff; - --color-modal-header-bg: #151515; - - --color-table-header-bg: #ffffff; - --color-table-header-text: #393f44; - --color-table-header-border: #ededed; - --color-table-header-border-bottom: #ededed; - --color-table-border: #ededed; - --color-table-border-bottom: #ededed; - --color-table-text: #393f44; -} - -/* Table headers should not generate a double border */ -.panel .table thead tr th { - border-bottom: none; -} - -/* Fix panel heading alignment & mobile layout */ -.panel-heading { - align-items: center; - background: #f5f5f5; - display: flex; - flex-wrap: wrap; - /* (28px small size widget height) + (0.5rem * 2) */ - min-height: calc(28px + 1rem); - /* Modified for Cockpit ZFS Manager - Original: padding: 0.5rem 0.5rem 0.5rem 1rem; */ - padding: 0.5rem 1rem 0.5rem 1rem; - position: relative; - z-index: 100; -} - -.panel-title { - font: inherit; - margin: 0; - padding: 0; -} - - .panel-title > a { - color: var(--color-link); - display: inline-block; - } - - .panel-title > a:hover, - .panel-title > a:focus { - color: var(--alert-info-text); - } - - /* Allow children in the title to wrap */ - .panel-title > h3, - .panel-title > a, - .panel-title > div, - .panel-title > span { - flex-shrink: 1; - word-break: break-all; - } - -.panel-heading > :last-child:not(:first-child), -.panel-heading > .pull-right, -.panel-heading > .panel-heading-actions { - flex: auto; - text-align: right; -} - -.panel-heading > .pull-right { - /* HACK: Pull right shouldn't be used to change document order. */ - /* This CSS _also_ changes document order to replicate the float. */ - /* Solution: Fix document order when pull-right is used. */ - order: 100; -} - - .panel-heading > .pull-right:first-child ~ :last-child { - /* Undo :last-child above for cases where pull-right is used before */ - text-align: left; - } - -@media screen and (max-width: 640px) { - /* Remove _most_ of the gaps on the sides of small screens */ - /* to maximize space, but still keep the boxy panel look */ - /* (container-fluid & page-ct adds 20px, so we remove 1/2 of that) */ - .page-ct > .panel, - .container-fluid > .panel, - .col-md-12 > .panel { - margin-left: -10px; - margin-right: -10px; - } - - .panel { - /* Background fade */ - --hi-color: #d1d1d1; - --hi-color2: var(--color-gray-2); - --bg-color: var(--color-bg); - --hi-width: 20px; - --hi-width3: calc(var(--hi-width) * 3); - --transparent: rgba(255,255,255,0); /* WebKit needs white transparent */ - max-width: 100vw; - overflow-x: auto; - position: relative; - background-image: - linear-gradient(to left, var(--bg-color) var(--hi-width), var(--transparent) var(--hi-width3)), - linear-gradient(to left, var(--hi-color) 1px, var(--transparent) 2px, var(--hi-color2) 4px, var(--bg-color) var(--hi-width)), - linear-gradient(to right, var(--bg-color) var(--hi-width), var(--transparent) var(--hi-width3)), - linear-gradient(to right, var(--hi-color) 1px, var(--transparent) 2px, var(--hi-color2) 4px, var(--bg-color) var(--hi-width)); - background-attachment: local, scroll, local, scroll; - background-position: right, right, left, left; - background-repeat: no-repeat; - background-size: var(--hi-width3) 100%; - } - - .panel > .panel-heading { - /* WebKit still needs -webkit- prefix for sticky */ - position: -webkit-sticky; - position: sticky; - left: 0; - top: 0; - } - - .panel .table thead th { - white-space: nowrap; - } - - .panel .table:not(:hover):not(:focus):not(:active) { - background: transparent; - } - - .panel .table thead:not(:hover):not(:focus):not(:active) { - background: transparent; - } -} - -/* Override the heavy patternfly headers */ -.table > thead { - background-image: none; - background-color: var(--color-bg); -} - -/* Make things line up */ -.table tbody tr > :first-child, -.table thead tr > :first-child { - padding-left: 1rem; -} - -.table tbody tr > :last-child, -.table thead tr > :last-child { - padding-right: 1rem; -} - -label.onoff-ct { - --switch-width: 40px; - --switch-height: 24px; - --switch-background: var(--color-gray-3); - --switch-border-color: transparent; - --switch-border-style: solid; - --switch-border-width: 1px; - --switch-text: inherit; - --switch-dot-size: 14px; - --switch-dot: var(--color-bg); - position: relative; - display: inline-flex; - align-items: center; - margin-bottom: 0; - padding: 1px 0; - /* Height is 24px; bump to 26px like other widgets */ - vertical-align: middle; - /* Focus ring */ - /* Don't show the focus ring for mouse clicks (when hovering) */ - /* Subtly darken the inner part of the switch on hover */ -} - - label.onoff-ct > .switch-on, - label.onoff-ct > .switch-off, - label.onoff-ct > input ~ .switch-toggle, - label.onoff-ct > input ~ .switch-toggle::after { - transition: all 300ms ease-in-out; - } - - label.onoff-ct > .switch-on, - label.onoff-ct > .switch-off { - color: var(--switch-text); - margin-left: 0.5em; - } - - label.onoff-ct > input { - opacity: 0; - position: absolute; - /* Base toggle graphic */ - /* Hide unused switch label */ - } - - label.onoff-ct > input ~ .switch-toggle { - --switch-dot-offset-x: calc(var(--switch-dot-size)/3 - var(--switch-border-width)); - --switch-dot-offset-y: calc(50% - 14px / 2); - /* Don't let the border draw over the background */ - background-clip: content-box; - background: var(--switch-background); - border-radius: var(--switch-height); - border: var(--switch-border-width) var(--switch-border-style) var(--switch-border-color); - box-shadow: inset 0 0 0 1px transparent; - width: var(--switch-width); - height: var(--switch-height); - display: inline-block; - position: relative; - margin: 0; - cursor: pointer; - /* Dot graphic */ - } - - label.onoff-ct > input ~ .switch-toggle::after { - background: var(--switch-dot); - box-shadow: 0 0 var(--switch-dot-offset-x) rgba(0, 0, 0, 0.2); - display: inline-block; - content: ""; - height: var(--switch-dot-size); - width: var(--switch-dot-size); - border-radius: 50%; - top: var(--switch-dot-offset-y); - left: var(--switch-dot-offset-x); - position: absolute; - pointer-events: none; - } - - label.onoff-ct > input ~ .switch-off { - --switch-text: var(--color-subtle-copy); - } - - label.onoff-ct > input:checked ~ .switch-toggle { - --switch-background: var(--color-link); - --switch-dot-offset-x: calc(100% - var(--switch-dot-size) * 1.333333 + var(--switch-border-width)); - /* Modified for Cockpit ZFS Manager - New */ - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10.583 6.35'%3E%3Cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-width='.529' d='M2.252 3.365l.756.758L4.48 2.65' opacity='.75'/%3E%3C/svg%3E"); - } - - label.onoff-ct > input:checked ~ .switch-toggle:last-child { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10.583 6.35'%3E%3Cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-width='.529' d='M2.252 3.365l.756.758L4.48 2.65' opacity='.75'/%3E%3C/svg%3E"); - } - - label.onoff-ct > input:disabled ~ .switch-toggle { - --switch-background: var(--color-subtle-copy); - --switch-dot: var(--color-gray-3); - } - - label.onoff-ct > input:disabled ~ * { - cursor: not-allowed; - } - - label.onoff-ct > input:checked ~ .switch-off, - label.onoff-ct > input:not(:checked) ~ .switch-on { - display: none; - } - - label.onoff-ct :disabled ~ .switch-on, - label.onoff-ct :disabled ~ .switch-off { - --switch-text: var(--color-subtle-copy); - } - - label.onoff-ct :focus ~ .switch-toggle::before { - /* Approximate Chrome's focus ring, for non-Firefox browsers */ - border: 2px solid rgba(0, 98, 220, 0.4); - border-radius: calc(var(--switch-width) - 10px); - position: absolute; - content: ''; - top: -4px; - bottom: -4px; - left: -4px; - width: calc(var(--switch-width) + 6px); - transition: all 300ms ease-in-out; - /* HACK: Keyboard has nothing to transition from, but hover does */ - /* (as it changes the ring to transparent and back). */ - /* So we delay the hover to not have the focus ring on hover out. */ - /* This makes the focus ring show up for keyboard users, but not on a mouse click. */ - transition-delay: 600s; - z-index: 1; - } - -@-moz-document url-prefix() { - label.onoff-ct :focus ~ .switch-toggle::before { - /* Approximate Firefox's focus ring, for Firefox only */ - border: 1px dotted rgba(0, 0, 0, 0.75); - } -} - -label.onoff-ct :focus:hover ~ .switch-toggle::before { - border-color: transparent; -} - -label.onoff-ct:hover :not(:disabled) ~ .switch-toggle { - box-shadow: inset 0 1px 5px 1px rgba(0, 0, 0, 0.15); -} - -h1 label.onoff-ct { - vertical-align: bottom; -} - -/* Form layout */ -:root { - --ct-form-columns: 2; -} - -.ct-form { - align-self: start; - display: grid; - grid-gap: 0.5rem 1.5rem; - grid-template-columns: repeat(var(--ct-form-columns), max-content 1fr); - justify-items: stretch; - align-content: baseline; -} - - .ct-form > .control-label { - text-align: right; - padding: 0; - margin: 0; - } - - .ct-form > :not(hr):not(p) { - line-height: 2.25rem; - } - - .ct-form > p { - margin: 0; - } - - .ct-form > :not(.control-label):not(hr):not(.ct-form-split):not(.ct-form-full) { - grid-column: 2 / -1; - } - - .ct-form > :not(.ct-form-relax):not(.spinner) { - width: auto; - } - - .ct-form > hr { - border: none; - grid-column: 1 / -1; - height: 0.5rem; - margin: 0; - padding: 0; - } - - .ct-form > input[size], - .ct-form > .ct-validation-wrapper > input[size] { - justify-self: start; - } - - .ct-form > .ct-validation-wrapper { - display: flex; - flex-direction: column; - } - - .ct-form input[type=number] { - -webkit-appearance: textarea; - } - - .ct-form > input, - .ct-form > .ct-validation-wrapper > input, - .ct-form > textarea, - .ct-form > .ct-validation-wrapper > textarea, - .ct-form > select, - .ct-form > .ct-validation-wrapper > select, - .ct-form > .bootstrap-select, - .ct-form > .ct-validation-wrapper > .bootstrap-select, - .ct-form > .ct-select, - .ct-form > .ct-validation-wrapper > .ct-select, - .ct-form > .dropdown, - .ct-form > .ct-validation-wrapper > .dropdown, - .ct-form > .combobox-container, - .ct-form > .ct-validation-wrapper > .combobox-container, - .ct-form > fieldset, - .ct-form > .ct-validation-wrapper > fieldset, - .ct-form > [role=group], - .ct-form > .ct-validation-wrapper > [role=group], - .ct-form > [data-field], - .ct-form > .ct-validation-wrapper > [data-field], - .ct-form > .form-group, - .ct-form > .ct-validation-wrapper > .form-group, - .ct-form > .btn-group, - .ct-form > .ct-validation-wrapper > .btn-group, - .ct-form > label.checkbox, - .ct-form > .ct-validation-wrapper > label.checkbox, - .ct-form > label.radio, - .ct-form > .ct-validation-wrapper > label.radio, - .ct-form > .checkbox-inline, - .ct-form > .ct-validation-wrapper > .checkbox-inline, - .ct-form > .radio-inline, - .ct-form > .ct-validation-wrapper > .radio-inline { - line-height: var(--pf-global--LineHeight--md); - } - - .ct-form > :not(.ct-form-relax):not(.spinner) { - width: auto !important; - } - - .ct-form > [role=group], - .ct-form > .ct-validation-wrapper > [role=group] { - align-self: start; - align-content: center; - display: grid; - grid-gap: 0.5rem; - min-height: 2.25rem; - justify-content: start; - grid-template-columns: repeat(2, auto); - } - - .ct-form > [role=group].ct-form-vertical > :not(.ct-form-split), - .ct-form > .ct-validation-wrapper > [role=group].ct-form-vertical > :not(.ct-form-split) { - grid-column: 1 / -1; - } - - .ct-form > [role=group] > .checkbox, - .ct-form > .ct-validation-wrapper > [role=group] > .checkbox, - .ct-form > [role=group] > .radio, - .ct-form > .ct-validation-wrapper > [role=group] > .radio { - margin: 0; - } - - .ct-form > [role=group] > .checkbox:first-child, - .ct-form > .ct-validation-wrapper > [role=group] > .checkbox:first-child, - .ct-form > [role=group] > .radio:first-child, - .ct-form > .ct-validation-wrapper > [role=group] > .radio:first-child { - margin-top: 0.5rem; - } - - .ct-form > [role=group]:not(.ct-form-relax) > .dropdown, - .ct-form > .ct-validation-wrapper > [role=group]:not(.ct-form-relax) > .dropdown, - .ct-form > .ct-validation-wrapper > [data-field]:not(.ct-form-relax) > .dropdown { - width: auto !important; - } - - .ct-form > [role=group]:not(.ct-form-relax) > .ct-select, - .ct-form > .ct-validation-wrapper > [role=group]:not(.ct-form-relax) > .ct-select, - .ct-form > .ct-validation-wrapper > [data-field]:not(.ct-form-relax) > .ct-select { - width: 100%; - } - - .ct-form label.checkbox, - .ct-form label.radio, - .ct-form .checkbox > label, - .ct-form .radio > label, - .ct-form .checkbox-inline, - .ct-form .radio-inline { - display: inline-flex; - padding-left: 0; - padding-right: 1.5rem; - align-items: center; - } - - .ct-form label.checkbox > input[type="checkbox"], - .ct-form label.radio > input[type="checkbox"], - .ct-form .checkbox > label > input[type="checkbox"], - .ct-form .radio > label > input[type="checkbox"], - .ct-form .checkbox-inline > input[type="checkbox"], - .ct-form .radio-inline > input[type="checkbox"], - .ct-form label.checkbox > input[type="radio"], - .ct-form label.radio > input[type="radio"], - .ct-form .checkbox > label > input[type="radio"], - .ct-form .radio > label > input[type="radio"], - .ct-form .checkbox-inline > input[type="radio"], - .ct-form .radio-inline > input[type="radio"] { - margin: 0 0.5em 0 0; - position: static; - } - - .ct-form fieldset > .checkbox:first-child, - .ct-form fieldset > .radio:first-child { - margin-top: 0; - } - - .ct-form fieldset > .checkbox:last-child, - .ct-form fieldset > .radio:last-child { - margin-bottom: 0; - } - - .ct-form .list-group { - margin-bottom: 0.5rem; - } - - .ct-form > .ct-form-split { - grid-column: auto / auto; - } - - .ct-form > .ct-form-full { - grid-column: 1 / -1; - } - - .ct-form > .help-block { - position: relative; - margin-top: -0.5rem; - } - - .ct-form .help-block { - --help-line-height: calc(var(--pf-global--LineHeight--md) * 1rem); - line-height: var(--help-line-height); - } - - .ct-form .help-block:empty { - display: none; - } - - .ct-form .help-block .spinner { - position: relative; - top: calc((var(--help-line-height) - 16px - 2px) / 2); - } - - .ct-form .ct-form-box { - background: var(--color-gray-1); - border-width: 1px; - border-style: solid; - border-color: var(--color-gray-5); - padding: 0.5rem; - padding-top: 1rem; - width: 100%; - } - -.ct-form-stretch { - justify-content: stretch !important; -} - -.ct-form-relax { - justify-self: start; -} - -.modal-dialog.modal-sm .ct-form > .ct-form-split { - grid-column: 2 / -1; -} - -@media (max-width: 640px) { - .listing-ct-body, - .modal { - --ct-form-columns: 1; - } -} - -.ct-form-minmax { - grid-template-columns: max-content min-content max-content 1fr; -} - -.ct-form-maxmin { - grid-template-columns: max-content 1fr max-content min-content; -} - -@media (max-width: 480px) { - .listing-ct-body .ct-form, - .modal .ct-form { - grid-template-columns: initial; - } - - .listing-ct-body .ct-form > *, - .modal .ct-form > * { - grid-column: auto; - max-width: 100%; - } - - .listing-ct-body .ct-form > .control-label, - .modal .ct-form > .control-label { - padding: 0; - text-align: left; - } - - .listing-ct-body .ct-form > .control-label:not(:first-child), - .modal .ct-form > .control-label:not(:first-child) { - margin: 6px 0 0; - } - - .listing-ct-body .ct-form > hr, - .modal .ct-form > hr { - height: 12px; - } -} - -/* Listing pattern */ -.ct-listing { - font-size: var(--font-size-s); - min-width: 65%; - clear: both; -} - - .ct-listing > header { - display: flex; - align-items: center; - justify-content: start; - flex-flow: wrap; - } - - .ct-listing > header > :only-child { - flex: auto; - } - - .ct-listing + .ct-listing { - margin-top: 1rem; - } - -.listing-ct-heading, -.listing-ct-actions { - margin: 0.5rem 0; -} - -.listing-ct-heading { - flex: auto; - padding: 0.25rem 1em 0.25rem 0; -} - -.ct-listing > table > thead h3 { - font-size: var(--pf-global--FontSize--2xl); - padding: 1rem 0; - font-weight: 400; - margin-top: 0; - position: relative; -} - - .ct-listing > table > thead h3 > .pull-right { - position: absolute; - top: 50%; - transform: translateY(-50%); - right: 0; - } - -.ct-listing > table > thead td { - padding-top: 1rem; -} - -.ct-listing > table > thead:first-child td { - padding-top: 0; -} - -.ct-listing > table > thead td > a { - line-height: 30px; - padding: 0.5rem 0 0.5rem; -} - -.ct-listing > table > thead th { - font-weight: normal; - padding: 0.5rem 1rem; - color: var(--color-subtle-copy); -} - - .ct-listing > table > thead th:first-child { - padding-left: 1rem; - } - - .ct-listing > table > thead th:last-child { - text-align: right; - } - -/* A listing item is a row in the table */ -tbody > tr.listing-ct-item { - border: 1px solid transparent; - border-top: 1px solid var(--color-ct-list-border); - border-bottom: 1px solid var(--color-ct-list-border); - cursor: pointer; -} - -.ct-listing > table > tbody:last-child { - border-bottom: 1px solid var(--color-ct-list-border); -} - -.ct-listing > table > tbody + thead { - border-top: 1px solid var(--color-ct-list-border); -} - -.ct-listing > table > tbody.open:last-child { - border-bottom: none; -} - -.ct-listing > table > tbody.open + thead { - border-top: none; -} - -tbody > tr.listing-ct-item.listing-ct-warning { - background-color: var(--color-ct-light-red-1); -} - -tbody.open > tr.listing-ct-item, -tbody.open > tr.listing-ct-panel { - background-color: var(--color-ct-list-active-bg); - border-bottom: none; - border-top: none; - border-left: 1px solid var(--color-light-gray); - border-right: 1px solid var(--color-light-gray); - transition: all 200ms; -} - - tbody.open > tr.listing-ct-item td, - tbody.open > tr.listing-ct-item th { - border-top: 1px solid var(--color-light-gray); - } - -tbody.open td div.listing-ct-head { - background-color: #fff; -} - -tbody.open > .listing-ct-panel > td > .listing-ct-body { - border: none; - /* Modified for Cockpit ZFS Manager - Original: overflow: auto; */ - /* Do not display scrollbars when actions menu is open */ - overflow: inherit; - /* Modified for Cockpit ZFS Manager - New */ - overflow-y: visible; -} - -tbody.open > tr.listing-ct-panel + tr.listing-ct-body { - border-top: none; -} - -tbody.open > tr.listing-ct-panel td div.listing-ct-head { - border: none; - border-bottom: 1px solid var(--color-light-gray); -} - -/* only highlight the row if navigation is available */ -tbody:not(.open) > tr.listing-ct-item:not(.listing-ct-nonavigate):hover { - background-color: var(--color-ct-list-hover-bg); -} - -/* if we can't navigate to a row but expand is available, highlight the caret */ -tbody:not(.open) > tr.listing-ct-item.listing-ct-nonavigate:hover td.listing-ct-toggle { - color: var(--color-ct-list-hover-icon); -} - -/* use hover color expanded rows even if navigation isn't available */ -tbody.open > tr.listing-ct-item:hover, -/* Modified for Cockpit ZFS Manager - Original: tr.listing-ct-item.listing-ct-nonavigate:hover */ -tr.listing-ct-item.listing-ct-nonavigate:not(.listing-ct-storagepoolsnotfound):hover { - background-color: var(--color-ct-list-hover-bg); -} - -tr.listing-ct-item .listing-ct-toggle:not(:empty) { - width: 35px; - color: #393f44; -} - -/* Highlight toggle color when hovered or if the row is open */ -.listing-ct-toggle:hover, -tbody.open .listing-ct-toggle { - color: var(--color-ct-list-active-bg); -} - -.listing-ct > thead > tr > .listing-ct-toggle + th, -.listing-ct-item > .listing-ct-toggle + td, -.listing-ct-item > .listing-ct-toggle + th { - padding-left: 0.25rem; - position: relative; -} - -td.listing-ct-toggle i { - font-size: 17px; -} - - td.listing-ct-toggle i:before { - position: relative; - content: "\F105"; - display: block; - } - -/* Modified for Cockpit ZFS Manager - Original: tbody.open > td.listing-ct-toggle i:before */ -tbody.open > tr.listing-ct-item td.listing-ct-toggle i:before, -/* Modified for Cockpit ZFS Manager - New */ -tbody.open > tr.listing-ct-item-snapshots .listing-ct-toggle-snapshots i:before { - content: "\F107"; - animation: listingCtToggleOpen 100ms ease-in-out; - top: 1px; -} - -@keyframes listingCtToggleOpen { - 0% { - transform-origin: 50% 50%; - transform: translate(0, -1px) rotate(-90deg); - } - - 100% { - transform: translate(0, 0) rotate(0); - } -} - -/* Listing items have decent padding ... */ -.listing-ct > thead > tr > th, -tr.listing-ct-item > th, -tr.listing-ct-item > td { - padding: 0.75rem; - vertical-align: text-top; - /* baseline doesn't support wrapped lines */ -} - - tr.listing-ct-item > td > .btn { - /* .btn has padding of 6px and 1px border */ - margin-top: -7px; - margin-bottom: -7px; - } - - tr.listing-ct-item > td > .btn-control-ct { - /* Adapt for Cockpit's modified button, which is larger by 8px */ - margin-top: -3px; - margin-bottom: -3px; - } - -/* Listing actions can be used directly as a cell */ -tr.listing-ct-item td.listing-ct-actions, -td.listing-ct-actions { - padding: 0.25rem 0.5rem; - text-align: right; - float: none; -} -/* if the entire row is selected, highlight */ -tr.listing-ct-item.listing-ct-selected { - background-color: #0088ce; - color: #fff; - border-color: #007ebf; -} - - tr.listing-ct-item.listing-ct-selected:hover { - background-color: #007ebf; - border-color: #007ebf; - } - - tr.listing-ct-item.listing-ct-selected .badge { - background-color: #00537e; - } - - tr.listing-ct-item.listing-ct-selected .badge:hover { - background-color: #003e5f; - } - -.listing-ct-head .listing-ct-actions { - margin-top: -7px; - order: -1; -} - -/* Modified for Cockpit ZFS Manager - Original: tr.listing-ct-item td:last-child */ -.ct-listing > table > tbody > tr > td:last-child:not(:first-child) { - text-align: right; -} - -div.listing-ct-panel { - box-shadow: 1px 1px 1px 1px #f5f5f5; - margin-bottom: 1rem; -} - -div.listing-ct-maybe { - border: 1px dashed var(--color-light-gray-3); - box-shadow: none; -} - -div.listing-ct-head { - padding: 0.5rem 0.5rem 0 0.5rem; - background-color: #f5f5f5; - border-color: var(--color-light-gray); - border-style: solid; - border-width: 1px 1px 0 1px; - overflow: hidden; - display: flex; - flex-flow: row-reverse wrap; - align-items: center; -} - - div.listing-ct-head:last-child { - padding-bottom: 0.5rem; - } - -div.listing-ct-maybe div.listing-ct-head, -div.listing-ct-maybe div.listing-ct-body { - background-color: #fff; - border: none; -} - -tbody.active .listing-ct-head { - border-top: 3px solid var(--color-link); -} - -.listing-ct-head h3 { - font-weight: normal; - font-size: 18px; - margin-top: 0px; - margin-left: 0.25rem; - margin-bottom: 0.5rem; -} - - .listing-ct-head h3 i { - float: left; - padding-right: 7px; - } - -.listing-ct-head .nav li a { - font-size: 13px; - /* Counteract listing-ct-head padding */ - margin-top: -0.5rem; - margin: 0; -} - -.listing-ct-head .nav-tabs { - border-bottom: none; -} - -.listing-ct-head .nav-tabs-pf { - /* Counteract listing-ct-head padding */ - margin: -0.5rem 0 0 -0.5rem; - flex: auto; -} - -/* To display info instead of tabs */ -.listing-ct-head dl { - display: inline-block; - height: 1.6em; - margin-bottom: 5px; - white-space: nowrap; - margin-right: 45px; - margin-left: 5px; -} - -.listing-ct-head dt { - font-weight: normal; - display: inline; - margin-right: 0.5em; - color: var(--color-subtle-copy); -} - -.listing-ct-head dd { - display: inline; - color: black; -} - -.listing-ct-body { - /* Modified for Cockpit ZFS Manager - Original: padding: 1rem 1.5rem; */ - padding: 0px; - border: 1px solid var(--color-light-gray); - background-color: #fff; -} - -.listing-ct-inline > td > .listing-ct-body { - border: none; - padding-top: 0px; - padding-left: 1rem; - padding-bottom: 0px; -} - -.listing-ct-inline > h3 { - border-top: 1px solid var(--color-light-gray); - padding-top: 20px; - margin-top: 30px; -} - - .listing-ct-inline > h3:first-child { - border-top: none; - padding-top: 0px; - margin-top: 20px; - } - -.listing-ct-actions { - float: right; - min-height: 26px; -} - -.listing-ct-status { - float: right; - clear: right; -} - -.listing-ct-error { - border-top: 1px solid var(--color-light-gray); - border-left: 1px solid var(--color-light-gray); - border-right: 1px solid var(--color-light-gray); -} - - .listing-ct-error.alert { - margin-bottom: 0; - } - -.listing-ct-body tt { - font-size: 12px; -} - -.listing-ct-body dl { - margin: 0; -} - - .listing-ct-body dl dd dl.inline-dl dt, - .listing-ct-body dt { - clear: left; - float: left; - width: 100px; - min-height: 26px; - white-space: nowrap; - text-overflow: ellipsis; - color: var(--color-subtle-copy); - font-weight: normal; - } - -.listing-ct-body dt { - text-align: right; -} - -.listing-ct-body dl dd dl dt { - text-align: left; -} - -.listing-ct-body dd { - margin-left: 110px; - min-height: 26px; - max-width: 1000px; - text-overflow: ellipsis; -} - -.listing-ct-body dl.full-width dt { - text-align: left; - min-width: none; - max-width: none; - float: none; - width: auto; -} - -.listing-ct-body dl.full-width dd { - margin-left: 0px; -} - -.ct-listing > table > tbody > tr > td:first-child { - position: relative; - transition: all 100ms ease-out; -} - - .ct-listing > table > tbody > tr > td:first-child::before, - .ct-listing > table > tbody > tr > td:first-child::after { - content: ""; - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - opacity: 0; - pointer-events: none; - transition: all 300ms; - } - - .ct-listing > table > tbody > tr > td:first-child::after { - right: auto; - width: 0; - background-color: var(--pf-global--active-color--100); - } - -.ct-listing > table > tbody > tr:not(:first-child) > td:first-child::after { - top: -1px; -} - -.ct-listing > table > tbody.open > tr > td:first-child { - transition: all 100ms ease-in; -} - - .ct-listing > table > tbody.open > tr > td:first-child::before, - .ct-listing > table > tbody.open > tr > td:first-child::after { - opacity: 1; - } - - .ct-listing > table > tbody.open > tr > td:first-child::after { - width: 3px; - } - -.ct-listing > table > tbody.open { - transition: all 100ms ease-in; - box-shadow: 0 0.3125rem 0.625rem -0.25rem rgba(3, 3, 3, 0.25); -} - -/* By default these are hidden */ -/* (HACK: Special-case the user auth dialog) */ -tbody:not(.ssh-key-body) > tr.listing-ct-head, -tbody > tr.listing-ct-panel, -tbody > tr.listing-ct-body { - display: none; -} - - tbody:not(.ssh-key-body) > tr.listing-ct-head > td, - tbody > tr.listing-ct-panel > td, - tbody > tr.listing-ct-body > td { - /* Compensate for the left-side blue highlight */ - padding-left: 3px; - } - -/* ... unless they are in the right state */ -tbody.open > tr.listing-ct-head, -tbody.open > tr.listing-ct-panel, -tbody.open > tr.listing-ct-body { - display: table-row; -} - -/* Animate the listing head & the last visible body */ -/* (Switching tabs will adds new listing-ct-bodys & toggle visibility) */ -tbody.open div.listing-ct-head, -tbody.open div.listing-ct-head + div.listing-ct-body:not([hidden]):last-child { - animation: listingCtShow 100ms ease-in-out; -} - -@keyframes listingCtShow { - 0% { - margin-bottom: 0; - margin-top: 0; - max-height: 0; - opacity: 0; - padding-bottom: 0; - padding-top: 0; - line-height: 0; - } - - 50% { - opacity: 0; - line-height: 1; - } - - 100% { - max-height: 100vh; - opacity: 1; - } -} - -/* Turn off animation if requested by the browser/OS (where supported) */ -@media (prefers-reduced-motion: reduce) { - tbody.open td.listing-ct-toggle i:before, - tbody.open div.listing-ct-head, - tbody.open div.listing-ct-body { - animation: none; - } -} - -tbody.open tr.listing-ct-head { - border-color: var(--color-light-gray); - border-style: solid; - border-width: 1px 1px 0 1px; - border-top: 3px solid var(--color-link); - background-color: #f5f5f5; -} - -tr.listing-ct-head + tr.listing-ct-head { - border-top: none; -} - - tr.listing-ct-head + tr.listing-ct-head td { - padding: 0px 0.5rem 0px 0.5rem; - } - -tr.listing-ct-body td { - padding: 1rem 1.5rem; - font-size: var(--font-size-s); -} - -.listing-ct-empty { - color: var(--color-subtle-copy); - text-align: center; - border-top: 1px solid var(--color-gray-2); - border-bottom: 1px solid var(--color-gray-2); -} - -/* Used at the end of a group of tbody to show an 'empty' message */ -thead.listing-ct-empty td, -.ct-listing > table > thead.listing-ct-empty td { - padding: 0.5rem; -} - -tbody + thead.listing-ct-empty { - display: none; -} - -/* Listing pattern defaults to using full width of parent */ -.listing-ct-wide { - width: 100%; -} - -/* Listing pattern mod to redce the padding */ -.listing-ct-compact > thead > tr > th, -.listing-ct-compact > tbody > tr > th, -.listing-ct-compact > tbody > tr > td { - padding: 0.25rem; -} - -.listing-ct-compact > tbody > tr > .listing-ct-toggle:not(:empty) + th, -.listing-ct-compact > tbody > tr > .listing-ct-toggle:not(:empty) + td { - padding-left: 0.25rem; -} - - .listing-ct-compact > tbody > tr > .listing-ct-toggle:not(:empty) + th::before, - .listing-ct-compact > tbody > tr > .listing-ct-toggle:not(:empty) + td::before { - top: 0.25rem; - } - -div.listing-ct-head { - overflow: visible; -} - -.listing-ct-head .btn-group, -.listing-ct-head button:not(.dropdown-toggle) { - margin-left: 0.3em; -} - -tbody tr.listing-ct-noexpand { - cursor: default; -} - -/* Fix up nav-tabs-pf to work properly */ -.nav-tabs-pf > li:first-child a { - margin-left: 0px !important; - padding-left: 1rem !important; -} - -.nav-tabs-pf > li a:before { - right: 0px !important; -} - -.nav-tabs-pf > li > a:active:before, -.nav-tabs-pf > li > a:focus:before, -.nav-tabs-pf > li > a:hover:before, -.nav-tabs-pf > li.active a:before { - height: 3px; - left: 0px; -} - -/* Force word-wraps when words are too long */ -.listing-ct-item td, -.listing-ct-item th, -.listing-ct-body { - overflow-wrap: break-word; - hyphens: auto; -} - -.listing-ct-item td, -.listing-ct-item th { - max-width: calc(100vw - 18rem); -} - -.listing-ct-body { - /* 42 = (20px padding + 1px border) * 2 */ - max-width: calc(100vw - 42px); -} - - - -/* - * This file is part of Cockpit. - * - * Copyright (C) 2015 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - - +} + +.select-ct-pool-row-identifier, +.select-ct-pool-row-physec { + font-size: var(--pf-global--FontSize--xs); + margin-left: 0px !important; +} + +.select-ct-filesystem-row { + align-items: center; + cursor: pointer; + display: flex; + word-break: break-all; +} + + .select-ct-filesystem-row :nth-child(1) { + margin-top: 0px; + } + + .select-ct-filesystem-row :nth-child(2) { + flex-grow: 1; + margin-left: 10px; + } + +.slider-pf { + margin: 0 0 0 8px; +} + + .slider-pf > .size-ct-text { + display: inline; + margin: 2px 2px 2px 8px; + text-align: right; + width: 5em; + } + + .slider-pf > .size-ct-text .disabled { + cursor: not-allowed !important; + pointer-events: inherit !important; + } + + .slider-pf > .dropdown { + flex: 1 0 80px; + } + + .slider-pf > .dropdown > .size-ct-unit > span { + padding-right: 0px; + } + + .slider-pf > span { + padding-left: 5px; + } + +.slider-selection { + background-color: var(--color-link); + background-image: linear-gradient(to bottom,var(--color-link) 0%,var(--color-link) 100%); +} + +.slider.slider-horizontal { + height: 16px; + margin: 0 8px 0 0; + width: 100%; +} + + .slider.slider-horizontal .slider-track { + height: 5px; + left: 0; + margin-top: -2px; + top: 50%; + width: 100%; + } + +.slider-handle { + background-color: var(--color-link) !important; + background-image: linear-gradient(to bottom,var(--color-link) 0%,var(--color-link) 100%) !important; + border: 0px; + border-radius: 9px; + cursor: pointer !important; + height: 18px; + margin: 0 0 0 -8px !important; + width: 18px; +} + + .slider-handle.disabled { + background-color: var(--color-subtle-copy) !important; + background-image: linear-gradient(to bottom,var(--color-subtle-copy) 0%,var(--color-subtle-copy) 100%) !important; + cursor: not-allowed !important; + } + +.slider-selection.disabled { + background-color: var(--color-subtle-copy); + background-image: linear-gradient(to bottom,var(--color-subtle-copy) 0%,var(--color-subtle-copy) 100%); +} + +.slider-track { + background-color: #ededed; + border: 0px; + box-shadow: none; +} + + .slider-track.disabled { + background-color: var(--color-subtle-copy); + border: 0px; + } + +.slider-track-high { + background-color: #ededed; +} + +.slider-track-low { + background-color: var(--color-link); + background-image: linear-gradient(to bottom,var(--color-link) 0%,var(--color-link) 100%); +} + + .slider-track-low.disabled { + background-color: var(--color-subtle-copy); + background-image: linear-gradient(to bottom,var(--color-subtle-copy) 0%,var(--color-subtle-copy) 100%); + } + +.table { + table-layout: fixed !important; +} + + .table > thead > tr > th, + .table > tbody > tr > td { + padding: 0.4rem; + vertical-align: middle; + } + + .table > tbody > tr > td.ct-spacing { + padding-bottom: 1.7rem; + } + + .table > tbody > tr > td.config-level-0-sub-hidden { + padding: 0px !important; + } + + .table > tbody > tr > td.config-level-1 { + padding-left: 3em !important; + } + + .table > tbody > tr > td.config-level-2 { + padding-left: 5em !important; + } + + .table > tbody > tr > td.config-level-3 { + padding-left: 7em !important; + } + + .table > tbody > tr > td.config-level-4 { + padding-left: 9em !important; + } + + .table > tbody > tr > td > span.config-count-danger { + color: var(--pf-global--danger-color--100); + } + + .table > tbody > tr > td > span.config-count-warning { + color: var(--pf-global--warning-color--100); + } + + .table[id^="table-storagepool-status-"] > thead, + .table[id^="table-storagepool-status-"] > thead > tr, + .table[id^="table-storagepool-status-"] > thead > tr > th { + border: 0 none !important; + height: 0 !important; + opacity: 0 !important; + padding: 0 !important; + } + + .table.table-ct-snapshots { + margin-bottom: 0px !important; + } + +tbody > tr.listing-ct-item.listing-ct-storagepoolsnotfound { + cursor: default !important; +} + + tbody > tr.listing-ct-item.listing-ct-storagepoolsnotfound > td:first-child { + padding-left: 50px; + } + +tbody > tr.listing-ct-item-snapshots { + border-bottom: 0px !important; +} + +.toast-notifications-list-pf { + top: 20px; +} + +.toast-pf > span > span.toast-ct-description { + word-break: break-all; +} + + .toast-pf > span > span.toast-ct-description.break-word { + word-break: break-word !important; + } + +/* Fix for flashing tooltip */ +.tooltip { + pointer-events: none !important; + position: fixed; +} + +.tooltip-inner { + overflow-wrap: break-word; +} + +@media screen and (max-width: 343px) { + .dropdown-menu-right { + left: auto; + right: auto; + } +} + +@media screen and (max-width: 480px) { + .dropdown-ct-status { + left: auto !important; + right: auto !important; + } + + .panel > .panel-heading > .panel-ct-actions { + text-align: left !important; + } + + .panel > .panel-heading > .panel-ct-heading, + .panel > .panel-heading > .panel-ct-heading > .panel-title { + min-height: 32px; + min-width: 100%; + } +} + +@media screen and (min-width: 401px) and (max-width: 525px) { + .dropdown-menu-right { + left: auto; + right: auto; + } +} + +@media screen and (min-width: 481px) and (max-width: 525px) { + .dropdown-ct-status { + left: auto !important; + right: 0 !important; + } +} + +@media screen and (max-width: 640px) { + .dialog-wait-ct { + margin-bottom: 0.5em; + } + + .listing-ct > thead > tr:first-child { + display: none; + } + + .listing-ct-actions > div > button.btn, + .listing-ct-actions > div > div.btn-group { + margin-bottom: 5px !important; + } + + .listing-ct-item > td { + padding: 0.5rem !important; + vertical-align: middle !important; + } + + .listing-ct-item > td.listing-ct-actionsmenu { + display: table-cell !important; + } + + .listing-ct-item > td:not(:first-child), + .listing-ct-item > th { + display: block; + max-width: 100% !important; + } + + .listing-ct-item > td > span.table-ct-head, + .table.table-ct-filesystems > tbody > tr > td > span.table-ct-head, + .table.table-ct-snapshots > tbody > tr > td > span.table-ct-head, + .table.table-ct-status-config > tbody > tr > td > span.table-ct-head { + color: var(--color-subtle-copy); + display: inherit !important; + float: left; + font-weight: normal; + padding-right: 0.5em; + } + + .listing-ct-item > td.listing-ct-icon > span.table-ct-text, + .table.table-ct-filesystems > tbody > tr > td > span.table-ct-text, + .table.table-ct-snapshots > tbody > tr > td > span.table-ct-text, + .table.table-ct-status-config > tbody > tr > td > span.table-ct-text { + display: inline-block !important; + padding-right: 0.5em; + } + + .listing-ct-item > td.listing-ct-icon, + .table.table-ct-filesystems > tbody > tr > td.listing-ct-icon, + .table.table-ct-snapshots > tbody > tr > td.listing-ct-icon, + .listing-ct .listing-ct-icon { + width: 100% !important; + } + + .listing-ct-wide { + table-layout: initial; + } + + .panel { + overflow-x: visible !important; + } + + .panel > .panel-heading { + position: inherit !important; + } + + .panel > .panel-heading > .panel-actions > button.btn { + margin-bottom: 5px !important; + } + + .table tbody tr > :first-child { + padding-left: 0.4rem !important; + } + + .table > tbody > tr > td.config-level-0-sub { + clear: both; + } + + .table > tbody > tr > td.config-level-0-sub::after, + .table > tbody > tr > td.config-level-1-sub::after, + .table > tbody > tr > td.config-level-2-sub::after, + .table > tbody > tr > td.config-level-3-sub::after, + .table > tbody > tr > td.config-level-4-sub::after { + content: "\00a0"; + } + + .table > tbody > tr > td.config-level-0-sub-hidden, + .table > tbody > tr > td.config-level-1-sub-hidden { + display: none !important; + } + + .table > tbody > tr > td.config-level-1, + .table > tbody > tr > td.config-level-1-sub { + padding-left: 1.5em !important; + } + + .table > tbody > tr > td.config-level-2, + .table > tbody > tr > td.config-level-2-sub { + padding-left: 3em !important; + } + + .table > tbody > tr > td.config-level-3, + .table > tbody > tr > td.config-level-3-sub { + padding-left: 4.5em !important; + } + + .table > tbody > tr > td.config-level-4, + .table > tbody > tr > td.config-level-4-sub { + padding-left: 6em !important; + } + + .table-ct-filesystems > thead, + .table-ct-snapshots > thead, + .table-ct-status-config > thead { + display: none; + } + + .table-ct-filesystems > tbody > tr > td:not(:last-child), + .table-ct-snapshots > tbody > tr > td:not(:last-child), + .table-ct-status-config > tbody > tr > td:not(:nth-last-child(-n+2)) { + display: block; + max-width: 100% !important; + } + + .table-ct-status-config > tbody > tr.table-ct-confighead { + display: none; + } + + .table-ct-status-config > tbody > tr > td.config-level-0-virtualdevice { + display: table-cell !important; + } +} + + + +/* + * This file is part of Cockpit. + * + * Copyright (C) 2015 Red Hat, Inc. + * + * Cockpit is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * Cockpit is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Cockpit; If not, see . + */ + + +.btn-group, .btn-group-vertical { + /* Fix button groups from wrapping in narrow widths */ + display: inline-flex; +} + +.dropdown-menu > li > a.disabled, +.dropdown-menu > li > a.disabled:hover, +.dropdown-menu > li > a.disabled:focus { + color: var(--color-subtle-copy); +} + + .dropdown-menu > li > a.disabled:hover, + .dropdown-menu > li > a.disabled:focus { + text-decoration: none; + background-color: transparent; + background-image: none; + border-color: transparent; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + cursor: default; + } + +/* Limit dropdown menus to 90% of the viewport size */ +.dropdown-menu { + height: auto; + overflow-y: auto; + max-height: 90vh; +} + +/* Allow kebab menus to have a ^ with overflowing */ +/* Note: This means kebab menus cannot be _too_ long */ +.dropdown-kebab-pf > .dropdown-menu { + overflow: visible; +} + +.dialog-list-ct { + max-height: 230px; + overflow-x: auto; + border: 1px solid var(--color-light-gray); + margin-bottom: 0px; +} + +:root { + /* Custom font aliases */ + --font-family: var(--pf-global--FontFamily--sans-serif); + --font-family-mono: var(--pf-global--FontFamily--monospace); + --font-size: var(--pf-global--FontSize--md); + --font-size-s: var(--pf-global--FontSize--sm); + --font-size-xs: var(--pf-global--FontSize--xs); + --font-size-l: var(--pf-global--FontSize--lg); + --font-size-xl: var(--pf-global--FontSize--xl); + --font-size-2xl: var(--pf-global--FontSize--2xl); + --font-size-3xl: var(--pf-global--FontSize--3xl); + + /* Cockpit custom colors */ + --color-ct-light-red-1: #f8cccc; + --color-ct-light-red-2: #f8acac; + --color-ct-light-red-3: #f98383; + --color-ct-brick-gold: #ffa763; + --color-ct-brick-red: #a53131; + + --color-ct-nav: #1b1b1b; + --color-ct-nav-sub: var(--pf-global--BackgroundColor--dark-300); + --color-ct-nav-text: var(--pf-global--BackgroundColor--light-300); + --color-ct-nav-active: var(--pf-global--BackgroundColor--dark-400); + --color-ct-nav-active-text: var(--pf-global--BackgroundColor--light-100); + --color-ct-nav-hover: var(--pf-global--BackgroundColor--dark-400); + --color-ct-nav-hover-text: var(--pf-global--BackgroundColor--light-100); + --color-ct-nav-border: var(--pf-global--BorderColor--100); + --color-ct-nav-cover-up: linear-gradient(to bottom, var(--color-ct-nav-sub), rgba(21,21,21, 0)); + --color-ct-nav-cover-down: linear-gradient(to top, var(--color-ct-nav-sub), rgba(21,21,21, 0)); + + --color-ct-nav-main: #1b1b1b; + --color-ct-nav-main-text: var(--color-ct-nav-text); + --color-ct-nav-main-border: var(--pf-global--BackgroundColor--dark-200); + --color-ct-nav-main-active: var(--color-ct-nav-sub); + --color-ct-nav-main-active-text: var(--color-ct-nav-active-text); + --color-ct-nav-main-hover: var(--color-ct-nav-hover); + --color-ct-nav-main-hover-text: var(--color-ct-nav-hover-text); + + --color-border: var(--pf-global--BorderColor--100); + + --color-ct-list-text: var(--color-text); + --color-ct-list-link: var(--color-link); + --color-ct-list-bg: var(--color-bg); + --color-ct-list-border: var(--color-border); + --color-ct-list-hover-text: var(--color-link); + --color-ct-list-hover-bg: var(--pf-global--BackgroundColor--150); + --color-ct-list-hover-border: var(--pf-global--BackgroundColor--150); + --color-ct-list-hover-icon: var(--color-blue); + --color-ct-list-selected-text: var(--color-link); + --color-ct-list-selected-bg: var(--pf-global--BackgroundColor--150); + --color-ct-list-selected-border: var(--pf-global--BackgroundColor--150); + --color-ct-list-active-text: var(--color-link-focus); + --color-ct-list-active-bg: var(--color-bg); + --color-ct-list-active-border: var(--color-ct-list-border); + --color-ct-list-critical-bg: var(--color-ct-light-red-1); + --color-ct-list-critical-border: var(--color-ct-light-red-2); + --color-ct-list-critical-bg-hover: var(--color-ct-light-red-2); + --color-ct-list-critical-border-hover: var(--color-ct-light-red-3); + + --color-link-hover-bg: var(--color-light-blue-2); + --color-link-hover-icon: var(--color-blue-5); + + /* Red Hat Digital Design System 2019 named colors */ + --color-red-hat-red: #ee0000; + --color-red-1: #cc0000; + --color-red-2: #a30000; + --color-red-3: #820000; + --color-dark-red-4: #5a0000; + --color-dark-red-5: #460000; + --color-dark-red-6: #320000; + --color-black: #000000; + --color-white: #ffffff; + --color-dark-blue: #004153; + --color-light-blue: #a3dbe8; + --color-dark-gray: #4c4c4c; + --color-light-gray: #dcdcdc; + --color-purple: #3b0083; + --color-gold: #f0ab00; + --color-teal: #007987; + --color-blue: #00b9e4; + --color-green: #92d400; + --color-storage: #ec7a08; + --color-infra: #0088ce; + --color-app-dev: #3f9c35; + --color-light-blue-1: #e8f6f9; + --color-light-blue-2: #d1edf4; + --color-light-blue-3: #b6e2ec; + --color-dark-blue-1: #80a0a9; + --color-dark-blue-2: #4e7a86; + --color-dark-blue-3: #1b5764; + --color-blue-1: #d9f5fb; + --color-blue-2: #c0edf7; + --color-blue-3: #9ae4f3; + --color-blue-4: #82ddf1; + --color-blue-5: #68d6ee; + --color-blue-6: #38c8e8; + --color-teal-1: #d9ebed; + --color-teal-2: #cbe4f1; + --color-teal-3: #b3d7db; + --color-teal-4: #9acacf; + --color-teal-5: #68afb6; + --color-teal-6: #36959e; + --color-green-1: #eaf5cd; + --color-green-2: #dff1b4; + --color-green-3: #d4ec9c; + --color-green-4: #cae883; + --color-green-5: #b5df56; + --color-green-6: #aadb40; + --color-gold-1: #fcedcd; + --color-gold-2: #fae5b4; + --color-gold-3: #f9dc9c; + --color-gold-4: #f8d384; + --color-gold-5: #f5c255; + --color-gold-6: #f2b22d; + --color-purple-1: #e2daec; + --color-purple-2: #cdc0df; + --color-purple-3: #b09bcc; + --color-purple-4: #9c82c0; + --color-purple-5: #8869b3; + --color-purple-6: #7551a6; + --color-gray-1: #f0f0f0; + --color-gray-2: #e6e6e6; + --color-gray-3: #d2d2d2; + --color-gray-4: #bebebe; + --color-gray-5: #aaaaaa; + --color-gray-6: #969696; + --color-gray-7: #828282; + --color-gray-8: #6e6e6e; + --color-gray-9: #5a5a5a; + --color-gray-10: #464646; + --color-gray-11: #323232; + --color-gray-12: #1e1e1e; + + /* Semantic colors */ + --color-fg: #151515; + --color-bg: #fff; + --color-text: var(--color-fg); + + --color-link: #0066cc; + --color-link-visited: #0066cc; + --color-link-hover: #004080; + --color-link-focus: #004080; + --color-link-dark: #73bcf7; + --color-link-visited-dark: #73bcf7; + --color-link-hover-dark: #2b9af3; + --color-link-focus-dark: #2b9af3; + + --color-heading: #151515; + --color-heading-dark: #ffffff; + --color-body-copy: #151515; + --color-body-copy-dark: #cccccc; + --color-body-copy-dark-color: rbga(255,255,255,0.8); + --color-subtle-copy: #72767b; + --color-subtle-text-dark: #cccccc; + + --color-alert-success-bg: #ffffff; + --color-alert-sucess-icon: #92d400; + --color-alert-sucess-border: #92d400; + --color-alert-success-text: #486b00; + --color-alert-info-bg: #ffffff; + --color-alert-info-icon: #39a5dc; + --color-alert-info-border: #39a5dc; + --color-alert-info-text: #004368; + --color-alert-warning-bg: #ffffff; + --color-alert-warning-icon: #f0ab00; + --color-alert-warning-border: #f0ab00; + --color-alert-warning-text: #795600; + --color-alert-danger-bg: #ffffff; + --color-alert-danger-icon: #c9190b; + --color-alert-danger-border: #c9190b; + --color-alert-danger-text: #7d1007; + + --color-low-severity-background: #ffffff; + --color-low-severity-icon: #72767b; + --color-low-severity-border: #72767b; + --color-low-severity-text: #151515; + --color-moderate-severity-background: #ffffff; + --color-moderate-severity-icon: #f0ab00; + --color-moderate-severity-border: #f0ab00; + --color-moderate-severity-text: #795600; + --color-important-severity-background: #ffffff; + --color-important-severity-icon: #df7409; + --color-important-severity-border: #df7409; + --color-important-severity-text: #8f4c09; + --color-critical-severity-background: #ffffff; + --color-critical-severity-icon: #c9190b; + --color-critical-severity-border: #c9190b; + --color-critical-severity-text: #7d1007; + + --color-cta-default: #0066cc; + --color-cta-default-hover: #004080; + --color-cta-primary: #ee0000; + --color-cta-primary-hover: #d40000; + --color-cta-secondary: #151515; + --color-cta-secondary-hover: #151515; + --color-cta-accent: #0066cc; + --color-cta-accent-hover: #0066cc; + + --color-button-text: #ffffff; + --color-button-text-dark: #151515; + --color-button-default: #151515; + --color-button-default-hover: #151515; + --color-button-primary: #0066cc; + --color-button-primary-hover: #004080; + --color-button-secondary: #0066cc; + --color-button-secondary-hover: #0066cc; + --color-button-disabled: #d2d2d2; + --color-button-disabled-text: #72767b; + + --color-border-lighter: #d2d2d2; + --color-border-default: #d2d2d2; + --color-border-darker: #d2d2d2; + + --color-potential-band-color: #f0f0f0; + --color-ui-hover-bg: #ededed; + --color-ui-alternate-row-bg: #ededed; + + --color-label: #151515; + --color-form-field-bottom-border: #8b8d8f; + --color-form-field-border: #0066cc; + --color-form-field-focus: #0066cc; + --color-form-field-bg: #ffffff; + --color-form-field-text: #151515; + --color-form-field-error-border: #a30000; + --color-form-field-error-bg: #ffffff; + --color-form-field-error-text: #a30000; + --color-form-field-active-border: #0066cc; + --color-select-dropdown-bottom-border: #8b8d8f; + --color-select-dropdown-bg: #ffffff; + --color-select-dropdown-arrow-color: #151515; + --color-select-dropdown-text-color: #151515; + + --color-breadcrumb-link: #0066cc; + --color-breadcrumb-link-hover: #004080; + --color-breadcrumb-text: #151515; + + --color-pagination-current-text: #393f44; + + --color-chips: #72767b; + --color-chips-secondary: #72767b; + --color-chips-hover: #72767b; + + --color-tab-link: #007bba; + --color-tab-text: #007bba; + --color-tab-indicator-color: #007bba; + --color-tab-bg: #ffffff; + --color-tab-border: #ededed; + --color-tab-selected-text: #007bba; + --color-tab-selected-indicator-color: #007bba; + --color-tab-selected-bg: #ffffff; + --color-tab-selected-border: #ededed; + + --color-tooltips-bg: #ffffff; + --color-tooltips-text: #151515; + + --color-modal-bg: #ffffff; + --color-modal-header-bg: #151515; + + --color-table-header-bg: #ffffff; + --color-table-header-text: #393f44; + --color-table-header-border: #ededed; + --color-table-header-border-bottom: #ededed; + --color-table-border: #ededed; + --color-table-border-bottom: #ededed; + --color-table-text: #393f44; +} + +/* Table headers should not generate a double border */ +.panel .table thead tr th { + border-bottom: none; +} + +/* Fix panel heading alignment & mobile layout */ +.panel-heading { + align-items: center; + background: #f5f5f5; + display: flex; + flex-wrap: wrap; + /* (28px small size widget height) + (0.5rem * 2) */ + min-height: calc(28px + 1rem); + /* Modified for Cockpit ZFS Manager - Original: padding: 0.5rem 0.5rem 0.5rem 1rem; */ + padding: 0.5rem 1rem 0.5rem 1rem; + position: relative; + z-index: 100; +} + +.panel-title { + font: inherit; + margin: 0; + padding: 0; +} + + .panel-title > a { + color: var(--color-link); + display: inline-block; + } + + .panel-title > a:hover, + .panel-title > a:focus { + color: var(--alert-info-text); + } + + /* Allow children in the title to wrap */ + .panel-title > h3, + .panel-title > a, + .panel-title > div, + .panel-title > span { + flex-shrink: 1; + word-break: break-all; + } + +.panel-heading > :last-child:not(:first-child), +.panel-heading > .pull-right, +.panel-heading > .panel-heading-actions { + flex: auto; + text-align: right; +} + +.panel-heading > .pull-right { + /* HACK: Pull right shouldn't be used to change document order. */ + /* This CSS _also_ changes document order to replicate the float. */ + /* Solution: Fix document order when pull-right is used. */ + order: 100; +} + + .panel-heading > .pull-right:first-child ~ :last-child { + /* Undo :last-child above for cases where pull-right is used before */ + text-align: left; + } + +@media screen and (max-width: 640px) { + /* Remove _most_ of the gaps on the sides of small screens */ + /* to maximize space, but still keep the boxy panel look */ + /* (container-fluid & page-ct adds 20px, so we remove 1/2 of that) */ + .page-ct > .panel, + .container-fluid > .panel, + .col-md-12 > .panel { + margin-left: -10px; + margin-right: -10px; + } + + .panel { + /* Background fade */ + --hi-color: #d1d1d1; + --hi-color2: var(--color-gray-2); + --bg-color: var(--color-bg); + --hi-width: 20px; + --hi-width3: calc(var(--hi-width) * 3); + --transparent: rgba(255,255,255,0); /* WebKit needs white transparent */ + max-width: 100vw; + overflow-x: auto; + position: relative; + background-image: + linear-gradient(to left, var(--bg-color) var(--hi-width), var(--transparent) var(--hi-width3)), + linear-gradient(to left, var(--hi-color) 1px, var(--transparent) 2px, var(--hi-color2) 4px, var(--bg-color) var(--hi-width)), + linear-gradient(to right, var(--bg-color) var(--hi-width), var(--transparent) var(--hi-width3)), + linear-gradient(to right, var(--hi-color) 1px, var(--transparent) 2px, var(--hi-color2) 4px, var(--bg-color) var(--hi-width)); + background-attachment: local, scroll, local, scroll; + background-position: right, right, left, left; + background-repeat: no-repeat; + background-size: var(--hi-width3) 100%; + } + + .panel > .panel-heading { + /* WebKit still needs -webkit- prefix for sticky */ + position: -webkit-sticky; + position: sticky; + left: 0; + top: 0; + } + + .panel .table thead th { + white-space: nowrap; + } + + .panel .table:not(:hover):not(:focus):not(:active) { + background: transparent; + } + + .panel .table thead:not(:hover):not(:focus):not(:active) { + background: transparent; + } +} + +/* Override the heavy patternfly headers */ +.table > thead { + background-image: none; + background-color: var(--color-bg); +} + +/* Make things line up */ +.table tbody tr > :first-child, +.table thead tr > :first-child { + padding-left: 1rem; +} + +.table tbody tr > :last-child, +.table thead tr > :last-child { + padding-right: 1rem; +} + +label.onoff-ct { + --switch-width: 40px; + --switch-height: 24px; + --switch-background: var(--color-gray-3); + --switch-border-color: transparent; + --switch-border-style: solid; + --switch-border-width: 1px; + --switch-text: inherit; + --switch-dot-size: 14px; + --switch-dot: var(--color-bg); + position: relative; + display: inline-flex; + align-items: center; + margin-bottom: 0; + padding: 1px 0; + /* Height is 24px; bump to 26px like other widgets */ + vertical-align: middle; + /* Focus ring */ + /* Don't show the focus ring for mouse clicks (when hovering) */ + /* Subtly darken the inner part of the switch on hover */ +} + + label.onoff-ct > .switch-on, + label.onoff-ct > .switch-off, + label.onoff-ct > input ~ .switch-toggle, + label.onoff-ct > input ~ .switch-toggle::after { + transition: all 300ms ease-in-out; + } + + label.onoff-ct > .switch-on, + label.onoff-ct > .switch-off { + color: var(--switch-text); + margin-left: 0.5em; + } + + label.onoff-ct > input { + opacity: 0; + position: absolute; + /* Base toggle graphic */ + /* Hide unused switch label */ + } + + label.onoff-ct > input ~ .switch-toggle { + --switch-dot-offset-x: calc(var(--switch-dot-size)/3 - var(--switch-border-width)); + --switch-dot-offset-y: calc(50% - 14px / 2); + /* Don't let the border draw over the background */ + background-clip: content-box; + background: var(--switch-background); + border-radius: var(--switch-height); + border: var(--switch-border-width) var(--switch-border-style) var(--switch-border-color); + box-shadow: inset 0 0 0 1px transparent; + width: var(--switch-width); + height: var(--switch-height); + display: inline-block; + position: relative; + margin: 0; + cursor: pointer; + /* Dot graphic */ + } + + label.onoff-ct > input ~ .switch-toggle::after { + background: var(--switch-dot); + box-shadow: 0 0 var(--switch-dot-offset-x) rgba(0, 0, 0, 0.2); + display: inline-block; + content: ""; + height: var(--switch-dot-size); + width: var(--switch-dot-size); + border-radius: 50%; + top: var(--switch-dot-offset-y); + left: var(--switch-dot-offset-x); + position: absolute; + pointer-events: none; + } + + label.onoff-ct > input ~ .switch-off { + --switch-text: var(--color-subtle-copy); + } + + label.onoff-ct > input:checked ~ .switch-toggle { + --switch-background: var(--color-link); + --switch-dot-offset-x: calc(100% - var(--switch-dot-size) * 1.333333 + var(--switch-border-width)); + /* Modified for Cockpit ZFS Manager - New */ + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10.583 6.35'%3E%3Cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-width='.529' d='M2.252 3.365l.756.758L4.48 2.65' opacity='.75'/%3E%3C/svg%3E"); + } + + label.onoff-ct > input:checked ~ .switch-toggle:last-child { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10.583 6.35'%3E%3Cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-width='.529' d='M2.252 3.365l.756.758L4.48 2.65' opacity='.75'/%3E%3C/svg%3E"); + } + + label.onoff-ct > input:disabled ~ .switch-toggle { + --switch-background: var(--color-subtle-copy); + --switch-dot: var(--color-gray-3); + } + + label.onoff-ct > input:disabled ~ * { + cursor: not-allowed; + } + + label.onoff-ct > input:checked ~ .switch-off, + label.onoff-ct > input:not(:checked) ~ .switch-on { + display: none; + } + + label.onoff-ct :disabled ~ .switch-on, + label.onoff-ct :disabled ~ .switch-off { + --switch-text: var(--color-subtle-copy); + } + + label.onoff-ct :focus ~ .switch-toggle::before { + /* Approximate Chrome's focus ring, for non-Firefox browsers */ + border: 2px solid rgba(0, 98, 220, 0.4); + border-radius: calc(var(--switch-width) - 10px); + position: absolute; + content: ''; + top: -4px; + bottom: -4px; + left: -4px; + width: calc(var(--switch-width) + 6px); + transition: all 300ms ease-in-out; + /* HACK: Keyboard has nothing to transition from, but hover does */ + /* (as it changes the ring to transparent and back). */ + /* So we delay the hover to not have the focus ring on hover out. */ + /* This makes the focus ring show up for keyboard users, but not on a mouse click. */ + transition-delay: 600s; + z-index: 1; + } + +@-moz-document url-prefix() { + label.onoff-ct :focus ~ .switch-toggle::before { + /* Approximate Firefox's focus ring, for Firefox only */ + border: 1px dotted rgba(0, 0, 0, 0.75); + } +} + +label.onoff-ct :focus:hover ~ .switch-toggle::before { + border-color: transparent; +} + +label.onoff-ct:hover :not(:disabled) ~ .switch-toggle { + box-shadow: inset 0 1px 5px 1px rgba(0, 0, 0, 0.15); +} + +h1 label.onoff-ct { + vertical-align: bottom; +} + +/* Form layout */ +:root { + --ct-form-columns: 2; +} + +.ct-form { + align-self: start; + display: grid; + grid-gap: 0.5rem 1.5rem; + grid-template-columns: repeat(var(--ct-form-columns), max-content 1fr); + justify-items: stretch; + align-content: baseline; +} + + .ct-form > .control-label { + text-align: right; + padding: 0; + margin: 0; + } + + .ct-form > :not(hr):not(p) { + line-height: 2.25rem; + } + + .ct-form > p { + margin: 0; + } + + .ct-form > :not(.control-label):not(hr):not(.ct-form-split):not(.ct-form-full) { + grid-column: 2 / -1; + } + + .ct-form > :not(.ct-form-relax):not(.spinner) { + width: auto; + } + + .ct-form > hr { + border: none; + grid-column: 1 / -1; + height: 0.5rem; + margin: 0; + padding: 0; + } + + .ct-form > input[size], + .ct-form > .ct-validation-wrapper > input[size] { + justify-self: start; + } + + .ct-form > .ct-validation-wrapper { + display: flex; + flex-direction: column; + } + + .ct-form input[type=number] { + -webkit-appearance: textarea; + } + + .ct-form > input, + .ct-form > .ct-validation-wrapper > input, + .ct-form > textarea, + .ct-form > .ct-validation-wrapper > textarea, + .ct-form > select, + .ct-form > .ct-validation-wrapper > select, + .ct-form > .bootstrap-select, + .ct-form > .ct-validation-wrapper > .bootstrap-select, + .ct-form > .ct-select, + .ct-form > .ct-validation-wrapper > .ct-select, + .ct-form > .dropdown, + .ct-form > .ct-validation-wrapper > .dropdown, + .ct-form > .combobox-container, + .ct-form > .ct-validation-wrapper > .combobox-container, + .ct-form > fieldset, + .ct-form > .ct-validation-wrapper > fieldset, + .ct-form > [role=group], + .ct-form > .ct-validation-wrapper > [role=group], + .ct-form > [data-field], + .ct-form > .ct-validation-wrapper > [data-field], + .ct-form > .form-group, + .ct-form > .ct-validation-wrapper > .form-group, + .ct-form > .btn-group, + .ct-form > .ct-validation-wrapper > .btn-group, + .ct-form > label.checkbox, + .ct-form > .ct-validation-wrapper > label.checkbox, + .ct-form > label.radio, + .ct-form > .ct-validation-wrapper > label.radio, + .ct-form > .checkbox-inline, + .ct-form > .ct-validation-wrapper > .checkbox-inline, + .ct-form > .radio-inline, + .ct-form > .ct-validation-wrapper > .radio-inline { + line-height: var(--pf-global--LineHeight--md); + } + + .ct-form > :not(.ct-form-relax):not(.spinner) { + width: auto !important; + } + + .ct-form > [role=group], + .ct-form > .ct-validation-wrapper > [role=group] { + align-self: start; + align-content: center; + display: grid; + grid-gap: 0.5rem; + min-height: 2.25rem; + justify-content: start; + grid-template-columns: repeat(2, auto); + } + + .ct-form > [role=group].ct-form-vertical > :not(.ct-form-split), + .ct-form > .ct-validation-wrapper > [role=group].ct-form-vertical > :not(.ct-form-split) { + grid-column: 1 / -1; + } + + .ct-form > [role=group] > .checkbox, + .ct-form > .ct-validation-wrapper > [role=group] > .checkbox, + .ct-form > [role=group] > .radio, + .ct-form > .ct-validation-wrapper > [role=group] > .radio { + margin: 0; + } + + .ct-form > [role=group] > .checkbox:first-child, + .ct-form > .ct-validation-wrapper > [role=group] > .checkbox:first-child, + .ct-form > [role=group] > .radio:first-child, + .ct-form > .ct-validation-wrapper > [role=group] > .radio:first-child { + margin-top: 0.5rem; + } + + .ct-form > [role=group]:not(.ct-form-relax) > .dropdown, + .ct-form > .ct-validation-wrapper > [role=group]:not(.ct-form-relax) > .dropdown, + .ct-form > .ct-validation-wrapper > [data-field]:not(.ct-form-relax) > .dropdown { + width: auto !important; + } + + .ct-form > [role=group]:not(.ct-form-relax) > .ct-select, + .ct-form > .ct-validation-wrapper > [role=group]:not(.ct-form-relax) > .ct-select, + .ct-form > .ct-validation-wrapper > [data-field]:not(.ct-form-relax) > .ct-select { + width: 100%; + } + + .ct-form label.checkbox, + .ct-form label.radio, + .ct-form .checkbox > label, + .ct-form .radio > label, + .ct-form .checkbox-inline, + .ct-form .radio-inline { + display: inline-flex; + padding-left: 0; + padding-right: 1.5rem; + align-items: center; + } + + .ct-form label.checkbox > input[type="checkbox"], + .ct-form label.radio > input[type="checkbox"], + .ct-form .checkbox > label > input[type="checkbox"], + .ct-form .radio > label > input[type="checkbox"], + .ct-form .checkbox-inline > input[type="checkbox"], + .ct-form .radio-inline > input[type="checkbox"], + .ct-form label.checkbox > input[type="radio"], + .ct-form label.radio > input[type="radio"], + .ct-form .checkbox > label > input[type="radio"], + .ct-form .radio > label > input[type="radio"], + .ct-form .checkbox-inline > input[type="radio"], + .ct-form .radio-inline > input[type="radio"] { + margin: 0 0.5em 0 0; + position: static; + } + + .ct-form fieldset > .checkbox:first-child, + .ct-form fieldset > .radio:first-child { + margin-top: 0; + } + + .ct-form fieldset > .checkbox:last-child, + .ct-form fieldset > .radio:last-child { + margin-bottom: 0; + } + + .ct-form .list-group { + margin-bottom: 0.5rem; + } + + .ct-form > .ct-form-split { + grid-column: auto / auto; + } + + .ct-form > .ct-form-full { + grid-column: 1 / -1; + } + + .ct-form > .help-block { + position: relative; + margin-top: -0.5rem; + } + + .ct-form .help-block { + --help-line-height: calc(var(--pf-global--LineHeight--md) * 1rem); + line-height: var(--help-line-height); + } + + .ct-form .help-block:empty { + display: none; + } + + .ct-form .help-block .spinner { + position: relative; + top: calc((var(--help-line-height) - 16px - 2px) / 2); + } + + .ct-form .ct-form-box { + background: var(--color-gray-1); + border-width: 1px; + border-style: solid; + border-color: var(--color-gray-5); + padding: 0.5rem; + padding-top: 1rem; + width: 100%; + } + +.ct-form-stretch { + justify-content: stretch !important; +} + +.ct-form-relax { + justify-self: start; +} + +.modal-dialog.modal-sm .ct-form > .ct-form-split { + grid-column: 2 / -1; +} + +@media (max-width: 640px) { + .listing-ct-body, + .modal { + --ct-form-columns: 1; + } +} + +.ct-form-minmax { + grid-template-columns: max-content min-content max-content 1fr; +} + +.ct-form-maxmin { + grid-template-columns: max-content 1fr max-content min-content; +} + +@media (max-width: 480px) { + .listing-ct-body .ct-form, + .modal .ct-form { + grid-template-columns: initial; + } + + .listing-ct-body .ct-form > *, + .modal .ct-form > * { + grid-column: auto; + max-width: 100%; + } + + .listing-ct-body .ct-form > .control-label, + .modal .ct-form > .control-label { + padding: 0; + text-align: left; + } + + .listing-ct-body .ct-form > .control-label:not(:first-child), + .modal .ct-form > .control-label:not(:first-child) { + margin: 6px 0 0; + } + + .listing-ct-body .ct-form > hr, + .modal .ct-form > hr { + height: 12px; + } +} + +/* Listing pattern */ +.ct-listing { + font-size: var(--font-size-s); + min-width: 65%; + clear: both; +} + + .ct-listing > header { + display: flex; + align-items: center; + justify-content: start; + flex-flow: wrap; + } + + .ct-listing > header > :only-child { + flex: auto; + } + + .ct-listing + .ct-listing { + margin-top: 1rem; + } + +.listing-ct-heading, +.listing-ct-actions { + margin: 0.5rem 0; +} + +.listing-ct-heading { + flex: auto; + padding: 0.25rem 1em 0.25rem 0; +} + +.ct-listing > table > thead h3 { + font-size: var(--pf-global--FontSize--2xl); + padding: 1rem 0; + font-weight: 400; + margin-top: 0; + position: relative; +} + + .ct-listing > table > thead h3 > .pull-right { + position: absolute; + top: 50%; + transform: translateY(-50%); + right: 0; + } + +.ct-listing > table > thead td { + padding-top: 1rem; +} + +.ct-listing > table > thead:first-child td { + padding-top: 0; +} + +.ct-listing > table > thead td > a { + line-height: 30px; + padding: 0.5rem 0 0.5rem; +} + +.ct-listing > table > thead th { + font-weight: normal; + padding: 0.5rem 1rem; + color: var(--color-subtle-copy); +} + + .ct-listing > table > thead th:first-child { + padding-left: 1rem; + } + + .ct-listing > table > thead th:last-child { + text-align: right; + } + +/* A listing item is a row in the table */ +tbody > tr.listing-ct-item { + border: 1px solid transparent; + border-top: 1px solid var(--color-ct-list-border); + border-bottom: 1px solid var(--color-ct-list-border); + cursor: pointer; +} + +.ct-listing > table > tbody:last-child { + border-bottom: 1px solid var(--color-ct-list-border); +} + +.ct-listing > table > tbody + thead { + border-top: 1px solid var(--color-ct-list-border); +} + +.ct-listing > table > tbody.open:last-child { + border-bottom: none; +} + +.ct-listing > table > tbody.open + thead { + border-top: none; +} + +tbody > tr.listing-ct-item.listing-ct-warning { + background-color: var(--color-ct-light-red-1); +} + +tbody.open > tr.listing-ct-item, +tbody.open > tr.listing-ct-panel { + background-color: var(--color-ct-list-active-bg); + border-bottom: none; + border-top: none; + border-left: 1px solid var(--color-light-gray); + border-right: 1px solid var(--color-light-gray); + transition: all 200ms; +} + + tbody.open > tr.listing-ct-item td, + tbody.open > tr.listing-ct-item th { + border-top: 1px solid var(--color-light-gray); + } + +tbody.open td div.listing-ct-head { + background-color: #fff; +} + +tbody.open > .listing-ct-panel > td > .listing-ct-body { + border: none; + /* Modified for Cockpit ZFS Manager - Original: overflow: auto; */ + /* Do not display scrollbars when actions menu is open */ + overflow: inherit; + /* Modified for Cockpit ZFS Manager - New */ + overflow-y: visible; +} + +tbody.open > tr.listing-ct-panel + tr.listing-ct-body { + border-top: none; +} + +tbody.open > tr.listing-ct-panel td div.listing-ct-head { + border: none; + border-bottom: 1px solid var(--color-light-gray); +} + +/* only highlight the row if navigation is available */ +tbody:not(.open) > tr.listing-ct-item:not(.listing-ct-nonavigate):hover { + background-color: var(--color-ct-list-hover-bg); +} + +/* if we can't navigate to a row but expand is available, highlight the caret */ +tbody:not(.open) > tr.listing-ct-item.listing-ct-nonavigate:hover td.listing-ct-toggle { + color: var(--color-ct-list-hover-icon); +} + +/* use hover color expanded rows even if navigation isn't available */ +tbody.open > tr.listing-ct-item:hover, +/* Modified for Cockpit ZFS Manager - Original: tr.listing-ct-item.listing-ct-nonavigate:hover */ +tr.listing-ct-item.listing-ct-nonavigate:not(.listing-ct-storagepoolsnotfound):hover { + background-color: var(--color-ct-list-hover-bg); +} + +tr.listing-ct-item .listing-ct-toggle:not(:empty) { + width: 35px; + color: #393f44; +} + +/* Highlight toggle color when hovered or if the row is open */ +.listing-ct-toggle:hover, +tbody.open .listing-ct-toggle { + color: var(--color-ct-list-active-bg); +} + +.listing-ct > thead > tr > .listing-ct-toggle + th, +.listing-ct-item > .listing-ct-toggle + td, +.listing-ct-item > .listing-ct-toggle + th { + padding-left: 0.25rem; + position: relative; +} + +td.listing-ct-toggle i { + font-size: 17px; +} + + td.listing-ct-toggle i:before { + position: relative; + content: "\F105"; + display: block; + } + +/* Modified for Cockpit ZFS Manager - Original: tbody.open > td.listing-ct-toggle i:before */ +tbody.open > tr.listing-ct-item td.listing-ct-toggle i:before, +/* Modified for Cockpit ZFS Manager - New */ +tbody.open > tr.listing-ct-item-snapshots .listing-ct-toggle-snapshots i:before { + content: "\F107"; + animation: listingCtToggleOpen 100ms ease-in-out; + top: 1px; +} + +@keyframes listingCtToggleOpen { + 0% { + transform-origin: 50% 50%; + transform: translate(0, -1px) rotate(-90deg); + } + + 100% { + transform: translate(0, 0) rotate(0); + } +} + +/* Listing items have decent padding ... */ +.listing-ct > thead > tr > th, +tr.listing-ct-item > th, +tr.listing-ct-item > td { + padding: 0.75rem; + vertical-align: text-top; + /* baseline doesn't support wrapped lines */ +} + + tr.listing-ct-item > td > .btn { + /* .btn has padding of 6px and 1px border */ + margin-top: -7px; + margin-bottom: -7px; + } + + tr.listing-ct-item > td > .btn-control-ct { + /* Adapt for Cockpit's modified button, which is larger by 8px */ + margin-top: -3px; + margin-bottom: -3px; + } + +/* Listing actions can be used directly as a cell */ +tr.listing-ct-item td.listing-ct-actions, +td.listing-ct-actions { + padding: 0.25rem 0.5rem; + text-align: right; + float: none; +} +/* if the entire row is selected, highlight */ +tr.listing-ct-item.listing-ct-selected { + background-color: #0088ce; + color: #fff; + border-color: #007ebf; +} + + tr.listing-ct-item.listing-ct-selected:hover { + background-color: #007ebf; + border-color: #007ebf; + } + + tr.listing-ct-item.listing-ct-selected .badge { + background-color: #00537e; + } + + tr.listing-ct-item.listing-ct-selected .badge:hover { + background-color: #003e5f; + } + +.listing-ct-head .listing-ct-actions { + margin-top: -7px; + order: -1; +} + +/* Modified for Cockpit ZFS Manager - Original: tr.listing-ct-item td:last-child */ +.ct-listing > table > tbody > tr > td:last-child:not(:first-child) { + text-align: right; +} + +div.listing-ct-panel { + box-shadow: 1px 1px 1px 1px #f5f5f5; + margin-bottom: 1rem; +} + +div.listing-ct-maybe { + border: 1px dashed var(--color-light-gray-3); + box-shadow: none; +} + +div.listing-ct-head { + padding: 0.5rem 0.5rem 0 0.5rem; + background-color: #f5f5f5; + border-color: var(--color-light-gray); + border-style: solid; + border-width: 1px 1px 0 1px; + overflow: hidden; + display: flex; + flex-flow: row-reverse wrap; + align-items: center; +} + + div.listing-ct-head:last-child { + padding-bottom: 0.5rem; + } + +div.listing-ct-maybe div.listing-ct-head, +div.listing-ct-maybe div.listing-ct-body { + background-color: #fff; + border: none; +} + +tbody.active .listing-ct-head { + border-top: 3px solid var(--color-link); +} + +.listing-ct-head h3 { + font-weight: normal; + font-size: 18px; + margin-top: 0px; + margin-left: 0.25rem; + margin-bottom: 0.5rem; +} + + .listing-ct-head h3 i { + float: left; + padding-right: 7px; + } + +.listing-ct-head .nav li a { + font-size: 13px; + /* Counteract listing-ct-head padding */ + margin-top: -0.5rem; + margin: 0; +} + +.listing-ct-head .nav-tabs { + border-bottom: none; +} + +.listing-ct-head .nav-tabs-pf { + /* Counteract listing-ct-head padding */ + margin: -0.5rem 0 0 -0.5rem; + flex: auto; +} + +/* To display info instead of tabs */ +.listing-ct-head dl { + display: inline-block; + height: 1.6em; + margin-bottom: 5px; + white-space: nowrap; + margin-right: 45px; + margin-left: 5px; +} + +.listing-ct-head dt { + font-weight: normal; + display: inline; + margin-right: 0.5em; + color: var(--color-subtle-copy); +} + +.listing-ct-head dd { + display: inline; + color: black; +} + +.listing-ct-body { + /* Modified for Cockpit ZFS Manager - Original: padding: 1rem 1.5rem; */ + padding: 0px; + border: 1px solid var(--color-light-gray); + background-color: #fff; +} + +.listing-ct-inline > td > .listing-ct-body { + border: none; + padding-top: 0px; + padding-left: 1rem; + padding-bottom: 0px; +} + +.listing-ct-inline > h3 { + border-top: 1px solid var(--color-light-gray); + padding-top: 20px; + margin-top: 30px; +} + + .listing-ct-inline > h3:first-child { + border-top: none; + padding-top: 0px; + margin-top: 20px; + } + +.listing-ct-actions { + float: right; + min-height: 26px; +} + +.listing-ct-status { + float: right; + clear: right; +} + +.listing-ct-error { + border-top: 1px solid var(--color-light-gray); + border-left: 1px solid var(--color-light-gray); + border-right: 1px solid var(--color-light-gray); +} + + .listing-ct-error.alert { + margin-bottom: 0; + } + +.listing-ct-body tt { + font-size: 12px; +} + +.listing-ct-body dl { + margin: 0; +} + + .listing-ct-body dl dd dl.inline-dl dt, + .listing-ct-body dt { + clear: left; + float: left; + width: 100px; + min-height: 26px; + white-space: nowrap; + text-overflow: ellipsis; + color: var(--color-subtle-copy); + font-weight: normal; + } + +.listing-ct-body dt { + text-align: right; +} + +.listing-ct-body dl dd dl dt { + text-align: left; +} + +.listing-ct-body dd { + margin-left: 110px; + min-height: 26px; + max-width: 1000px; + text-overflow: ellipsis; +} + +.listing-ct-body dl.full-width dt { + text-align: left; + min-width: none; + max-width: none; + float: none; + width: auto; +} + +.listing-ct-body dl.full-width dd { + margin-left: 0px; +} + +.ct-listing > table > tbody > tr > td:first-child { + position: relative; + transition: all 100ms ease-out; +} + + .ct-listing > table > tbody > tr > td:first-child::before, + .ct-listing > table > tbody > tr > td:first-child::after { + content: ""; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + opacity: 0; + pointer-events: none; + transition: all 300ms; + } + + .ct-listing > table > tbody > tr > td:first-child::after { + right: auto; + width: 0; + background-color: var(--pf-global--active-color--100); + } + +.ct-listing > table > tbody > tr:not(:first-child) > td:first-child::after { + top: -1px; +} + +.ct-listing > table > tbody.open > tr > td:first-child { + transition: all 100ms ease-in; +} + + .ct-listing > table > tbody.open > tr > td:first-child::before, + .ct-listing > table > tbody.open > tr > td:first-child::after { + opacity: 1; + } + + .ct-listing > table > tbody.open > tr > td:first-child::after { + width: 3px; + } + +.ct-listing > table > tbody.open { + transition: all 100ms ease-in; + box-shadow: 0 0.3125rem 0.625rem -0.25rem rgba(3, 3, 3, 0.25); +} + +/* By default these are hidden */ +/* (HACK: Special-case the user auth dialog) */ +tbody:not(.ssh-key-body) > tr.listing-ct-head, +tbody > tr.listing-ct-panel, +tbody > tr.listing-ct-body { + display: none; +} + + tbody:not(.ssh-key-body) > tr.listing-ct-head > td, + tbody > tr.listing-ct-panel > td, + tbody > tr.listing-ct-body > td { + /* Compensate for the left-side blue highlight */ + padding-left: 3px; + } + +/* ... unless they are in the right state */ +tbody.open > tr.listing-ct-head, +tbody.open > tr.listing-ct-panel, +tbody.open > tr.listing-ct-body { + display: table-row; +} + +/* Animate the listing head & the last visible body */ +/* (Switching tabs will adds new listing-ct-bodys & toggle visibility) */ +tbody.open div.listing-ct-head, +tbody.open div.listing-ct-head + div.listing-ct-body:not([hidden]):last-child { + animation: listingCtShow 100ms ease-in-out; +} + +@keyframes listingCtShow { + 0% { + margin-bottom: 0; + margin-top: 0; + max-height: 0; + opacity: 0; + padding-bottom: 0; + padding-top: 0; + line-height: 0; + } + + 50% { + opacity: 0; + line-height: 1; + } + + 100% { + max-height: 100vh; + opacity: 1; + } +} + +/* Turn off animation if requested by the browser/OS (where supported) */ +@media (prefers-reduced-motion: reduce) { + tbody.open td.listing-ct-toggle i:before, + tbody.open div.listing-ct-head, + tbody.open div.listing-ct-body { + animation: none; + } +} + +tbody.open tr.listing-ct-head { + border-color: var(--color-light-gray); + border-style: solid; + border-width: 1px 1px 0 1px; + border-top: 3px solid var(--color-link); + background-color: #f5f5f5; +} + +tr.listing-ct-head + tr.listing-ct-head { + border-top: none; +} + + tr.listing-ct-head + tr.listing-ct-head td { + padding: 0px 0.5rem 0px 0.5rem; + } + +tr.listing-ct-body td { + padding: 1rem 1.5rem; + font-size: var(--font-size-s); +} + +.listing-ct-empty { + color: var(--color-subtle-copy); + text-align: center; + border-top: 1px solid var(--color-gray-2); + border-bottom: 1px solid var(--color-gray-2); +} + +/* Used at the end of a group of tbody to show an 'empty' message */ +thead.listing-ct-empty td, +.ct-listing > table > thead.listing-ct-empty td { + padding: 0.5rem; +} + +tbody + thead.listing-ct-empty { + display: none; +} + +/* Listing pattern defaults to using full width of parent */ +.listing-ct-wide { + width: 100%; +} + +/* Listing pattern mod to redce the padding */ +.listing-ct-compact > thead > tr > th, +.listing-ct-compact > tbody > tr > th, +.listing-ct-compact > tbody > tr > td { + padding: 0.25rem; +} + +.listing-ct-compact > tbody > tr > .listing-ct-toggle:not(:empty) + th, +.listing-ct-compact > tbody > tr > .listing-ct-toggle:not(:empty) + td { + padding-left: 0.25rem; +} + + .listing-ct-compact > tbody > tr > .listing-ct-toggle:not(:empty) + th::before, + .listing-ct-compact > tbody > tr > .listing-ct-toggle:not(:empty) + td::before { + top: 0.25rem; + } + +div.listing-ct-head { + overflow: visible; +} + +.listing-ct-head .btn-group, +.listing-ct-head button:not(.dropdown-toggle) { + margin-left: 0.3em; +} + +tbody tr.listing-ct-noexpand { + cursor: default; +} + +/* Fix up nav-tabs-pf to work properly */ +.nav-tabs-pf > li:first-child a { + margin-left: 0px !important; + padding-left: 1rem !important; +} + +.nav-tabs-pf > li a:before { + right: 0px !important; +} + +.nav-tabs-pf > li > a:active:before, +.nav-tabs-pf > li > a:focus:before, +.nav-tabs-pf > li > a:hover:before, +.nav-tabs-pf > li.active a:before { + height: 3px; + left: 0px; +} + +/* Force word-wraps when words are too long */ +.listing-ct-item td, +.listing-ct-item th, +.listing-ct-body { + overflow-wrap: break-word; + hyphens: auto; +} + +.listing-ct-item td, +.listing-ct-item th { + max-width: calc(100vw - 18rem); +} + +.listing-ct-body { + /* 42 = (20px padding + 1px border) * 2 */ + max-width: calc(100vw - 42px); +} + + + +/* + * This file is part of Cockpit. + * + * Copyright (C) 2015 Red Hat, Inc. + * + * Cockpit is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * Cockpit is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Cockpit; If not, see . + */ + + pf-c-empty-state .pf-c-button.pf-m-primary.slim { margin: 0 } @@ -3336,113 +3341,113 @@ pf-c-empty-state .pf-c-button.pf-m-primary.slim { .pf-u-hidden-on-2xl { display: none !important } -} - -.pf-c-alert-group { - --pf-c-alert-group__item--MarginTop: var(--pf-global--spacer--sm); - /* Modified for Cockpit ZFS Manager - Original: var(--pf-global--spacer--2xl); */ - --pf-c-alert-group--m-toast--Top: var(--pf-global--spacer--xl); - --pf-c-alert-group--m-toast--Right: var(--pf-global--spacer--xl); - --pf-c-alert-group--m-toast--MaxWidth: 37.5rem; - /* Modified for Cockpit ZFS Manager - Original: var(--pf-global--ZIndex--2xl); */ - --pf-c-alert-group--m-toast--ZIndex: 1055; -} - - .pf-c-alert-group > * + * { - margin-top: var(--pf-c-alert-group__item--MarginTop) - } - - .pf-c-alert-group.pf-m-toast { - position: fixed; - top: var(--pf-c-alert-group--m-toast--Top); - right: var(--pf-c-alert-group--m-toast--Right); - z-index: var(--pf-c-alert-group--m-toast--ZIndex); - width: calc(100% - var(--pf-c-alert-group--m-toast--Right)*2); - max-width: var(--pf-c-alert-group--m-toast--MaxWidth) - } - -.modal-content .pf-c-alert { - text-align: left; - margin-bottom: 24px; -} - -.pf-c-alert { - --pf-global--Color--100: var(--pf-global--Color--dark-100); - --pf-global--Color--200: var(--pf-global--Color--dark-200); - --pf-global--BorderColor--100: var(--pf-global--BorderColor--dark-100); - --pf-global--primary-color--100: var(--pf-global--primary-color--dark-100); - --pf-global--link--Color: var(--pf-global--link--Color--dark); - --pf-global--link--Color--hover: var(--pf-global--link--Color--dark--hover); - --pf-global--BackgroundColor--100: var(--pf-global--BackgroundColor--light-100); - --pf-c-alert--BoxShadow: var(--pf-global--BoxShadow--lg); - --pf-c-alert--BackgroundColor: var(--pf-global--BackgroundColor--100); - --pf-c-alert--grid-template-columns: max-content 1fr max-content; - --pf-c-alert--grid-template-rows: 1fr auto; - --pf-c-alert__icon--Padding: var(--pf-global--spacer--md); - --pf-c-alert__icon--Color: var(--pf-global--default-color--300); - --pf-c-alert__icon--BackgroundColor: var(--pf-global--default-color--100); - --pf-c-alert__icon--FontSize: var(--pf-global--icon--FontSize--lg); - --pf-c-alert__title--FontSize: var(--pf-global--FontSize--md); - --pf-c-alert__title--Color: var(--pf-global--default-color--300); - --pf-c-alert__title--PaddingTop: var(--pf-global--spacer--md); - --pf-c-alert__title--PaddingRight: var(--pf-global--spacer--md); - --pf-c-alert__title--PaddingBottom: var(--pf-global--spacer--md); - --pf-c-alert__title--PaddingLeft: var(--pf-global--spacer--md); - --pf-c-alert__description--PaddingRight: var(--pf-global--spacer--md); - --pf-c-alert__description--PaddingBottom: var(--pf-global--spacer--md); - --pf-c-alert__description--PaddingLeft: var(--pf-global--spacer--md); - --pf-c-alert__description--MarginTop: calc(-1*var(--pf-global--spacer--sm)); - /* Modified for Cockpit ZFS Manager - Original: 0.6875rem; */ - --pf-c-alert__action--PaddingTop: 0.375rem; - --pf-c-alert__action--PaddingRight: var(--pf-global--spacer--xs); - --pf-c-alert--m-success__icon--Color: var(--pf-global--success-color--200); - --pf-c-alert--m-success__icon--BackgroundColor: var(--pf-global--success-color--100); - --pf-c-alert--m-success__title--Color: var(--pf-global--success-color--200); - --pf-c-alert--m-danger__icon--Color: var(--pf-global--danger-color--300); - --pf-c-alert--m-danger__icon--BackgroundColor: var(--pf-global--danger-color--100); - --pf-c-alert--m-danger__title--Color: var(--pf-global--danger-color--200); - --pf-c-alert--m-warning__icon--Color: var(--pf-global--warning-color--200); - --pf-c-alert--m-warning__icon--BackgroundColor: var(--pf-global--warning-color--100); - --pf-c-alert--m-warning__icon--FontSize: var(--pf-global--FontSize--xl); - --pf-c-alert--m-warning__title--Color: var(--pf-global--warning-color--200); - --pf-c-alert--m-info__icon--Color: var(--pf-global--info-color--200); - --pf-c-alert--m-info__icon--BackgroundColor: var(--pf-global--info-color--100); - --pf-c-alert--m-info__title--Color: var(--pf-global--info-color--200); - --pf-c-alert--m-inline--BoxShadow: none; - --pf-c-alert--m-inline--BorderColor: var(--pf-global--BorderColor--300); - --pf-c-alert--m-inline--BorderStyle: solid; - --pf-c-alert--m-inline--BorderTopWidth: var(--pf-global--BorderWidth--sm); - --pf-c-alert--m-inline--BorderRightWidth: var(--pf-global--BorderWidth--sm); - --pf-c-alert--m-inline--BorderBottomWidth: var(--pf-global--BorderWidth--sm); - --pf-c-alert--m-inline--BorderLeftWidth: 0; - --pf-c-alert--m-inline--before--Width: var(--pf-global--BorderWidth--lg); - --pf-c-alert--m-inline--before--Top: calc(-1*var(--pf-c-alert--m-inline--BorderTopWidth)); - --pf-c-alert--m-inline--before--Bottom: calc(-1*var(--pf-c-alert--m-inline--BorderBottomWidth)); - --pf-c-alert--m-inline--before--BackgroundColor: var(--pf-global--default-color--200); - --pf-c-alert--m-inline__icon--FontSize: var(--pf-global--icon--FontSize--md); - --pf-c-alert--m-inline__icon--Color: var(--pf-global--default-color--200); - --pf-c-alert--m-inline__icon--BackgroundColor: transparent; - --pf-c-alert--m-inline__icon--PaddingTop: calc(var(--pf-c-alert__icon--Padding) + (var(--pf-c-alert__icon--FontSize) - var(--pf-c-alert--m-inline__icon--FontSize))/2); - --pf-c-alert--m-inline__icon--PaddingRight: 0; - --pf-c-alert--m-inline__icon--PaddingBottom: var(--pf-global--spacer--md); - --pf-c-alert--m-inline__icon--PaddingLeft: var(--pf-global--spacer--md); - --pf-c-alert--m-inline--m-warning__icon--FontSize: 1.0625rem; - --pf-c-alert--m-inline--m-success__icon--Color: var(--pf-global--success-color--100); - --pf-c-alert--m-inline--m-success--before--BackgroundColor: var(--pf-global--success-color--100); - --pf-c-alert--m-inline--m-danger__icon--Color: var(--pf-global--danger-color--100); - --pf-c-alert--m-inline--m-danger--before--BackgroundColor: var(--pf-global--danger-color--100); - --pf-c-alert--m-inline--m-warning__icon--Color: var(--pf-global--warning-color--100); - --pf-c-alert--m-inline--m-warning--before--BackgroundColor: var(--pf-global--warning-color--100); - --pf-c-alert--m-inline--m-info__icon--Color: var(--pf-global--info-color--100); - --pf-c-alert--m-inline--m-info--before--BackgroundColor: var(--pf-global--info-color--100); - color: var(--pf-global--Color--100); - position: relative; - display: grid; - grid-template-columns: var(--pf-c-alert--grid-template-columns); - grid-template-rows: var(--pf-c-alert--grid-template-rows); - grid-template-areas: "icon title action" "icon content content"; - background-color: var(--pf-c-alert--BackgroundColor); - box-shadow: var(--pf-c-alert--BoxShadow) +} + +.pf-c-alert-group { + --pf-c-alert-group__item--MarginTop: var(--pf-global--spacer--sm); + /* Modified for Cockpit ZFS Manager - Original: var(--pf-global--spacer--2xl); */ + --pf-c-alert-group--m-toast--Top: var(--pf-global--spacer--xl); + --pf-c-alert-group--m-toast--Right: var(--pf-global--spacer--xl); + --pf-c-alert-group--m-toast--MaxWidth: 37.5rem; + /* Modified for Cockpit ZFS Manager - Original: var(--pf-global--ZIndex--2xl); */ + --pf-c-alert-group--m-toast--ZIndex: 1055; +} + + .pf-c-alert-group > * + * { + margin-top: var(--pf-c-alert-group__item--MarginTop) + } + + .pf-c-alert-group.pf-m-toast { + position: fixed; + top: var(--pf-c-alert-group--m-toast--Top); + right: var(--pf-c-alert-group--m-toast--Right); + z-index: var(--pf-c-alert-group--m-toast--ZIndex); + width: calc(100% - var(--pf-c-alert-group--m-toast--Right)*2); + max-width: var(--pf-c-alert-group--m-toast--MaxWidth) + } + +.modal-content .pf-c-alert { + text-align: left; + margin-bottom: 24px; +} + +.pf-c-alert { + --pf-global--Color--100: var(--pf-global--Color--dark-100); + --pf-global--Color--200: var(--pf-global--Color--dark-200); + --pf-global--BorderColor--100: var(--pf-global--BorderColor--dark-100); + --pf-global--primary-color--100: var(--pf-global--primary-color--dark-100); + --pf-global--link--Color: var(--pf-global--link--Color--dark); + --pf-global--link--Color--hover: var(--pf-global--link--Color--dark--hover); + --pf-global--BackgroundColor--100: var(--pf-global--BackgroundColor--light-100); + --pf-c-alert--BoxShadow: var(--pf-global--BoxShadow--lg); + --pf-c-alert--BackgroundColor: var(--pf-global--BackgroundColor--100); + --pf-c-alert--grid-template-columns: max-content 1fr max-content; + --pf-c-alert--grid-template-rows: 1fr auto; + --pf-c-alert__icon--Padding: var(--pf-global--spacer--md); + --pf-c-alert__icon--Color: var(--pf-global--default-color--300); + --pf-c-alert__icon--BackgroundColor: var(--pf-global--default-color--100); + --pf-c-alert__icon--FontSize: var(--pf-global--icon--FontSize--lg); + --pf-c-alert__title--FontSize: var(--pf-global--FontSize--md); + --pf-c-alert__title--Color: var(--pf-global--default-color--300); + --pf-c-alert__title--PaddingTop: var(--pf-global--spacer--md); + --pf-c-alert__title--PaddingRight: var(--pf-global--spacer--md); + --pf-c-alert__title--PaddingBottom: var(--pf-global--spacer--md); + --pf-c-alert__title--PaddingLeft: var(--pf-global--spacer--md); + --pf-c-alert__description--PaddingRight: var(--pf-global--spacer--md); + --pf-c-alert__description--PaddingBottom: var(--pf-global--spacer--md); + --pf-c-alert__description--PaddingLeft: var(--pf-global--spacer--md); + --pf-c-alert__description--MarginTop: calc(-1*var(--pf-global--spacer--sm)); + /* Modified for Cockpit ZFS Manager - Original: 0.6875rem; */ + --pf-c-alert__action--PaddingTop: 0.375rem; + --pf-c-alert__action--PaddingRight: var(--pf-global--spacer--xs); + --pf-c-alert--m-success__icon--Color: var(--pf-global--success-color--200); + --pf-c-alert--m-success__icon--BackgroundColor: var(--pf-global--success-color--100); + --pf-c-alert--m-success__title--Color: var(--pf-global--success-color--200); + --pf-c-alert--m-danger__icon--Color: var(--pf-global--danger-color--300); + --pf-c-alert--m-danger__icon--BackgroundColor: var(--pf-global--danger-color--100); + --pf-c-alert--m-danger__title--Color: var(--pf-global--danger-color--200); + --pf-c-alert--m-warning__icon--Color: var(--pf-global--warning-color--200); + --pf-c-alert--m-warning__icon--BackgroundColor: var(--pf-global--warning-color--100); + --pf-c-alert--m-warning__icon--FontSize: var(--pf-global--FontSize--xl); + --pf-c-alert--m-warning__title--Color: var(--pf-global--warning-color--200); + --pf-c-alert--m-info__icon--Color: var(--pf-global--info-color--200); + --pf-c-alert--m-info__icon--BackgroundColor: var(--pf-global--info-color--100); + --pf-c-alert--m-info__title--Color: var(--pf-global--info-color--200); + --pf-c-alert--m-inline--BoxShadow: none; + --pf-c-alert--m-inline--BorderColor: var(--pf-global--BorderColor--300); + --pf-c-alert--m-inline--BorderStyle: solid; + --pf-c-alert--m-inline--BorderTopWidth: var(--pf-global--BorderWidth--sm); + --pf-c-alert--m-inline--BorderRightWidth: var(--pf-global--BorderWidth--sm); + --pf-c-alert--m-inline--BorderBottomWidth: var(--pf-global--BorderWidth--sm); + --pf-c-alert--m-inline--BorderLeftWidth: 0; + --pf-c-alert--m-inline--before--Width: var(--pf-global--BorderWidth--lg); + --pf-c-alert--m-inline--before--Top: calc(-1*var(--pf-c-alert--m-inline--BorderTopWidth)); + --pf-c-alert--m-inline--before--Bottom: calc(-1*var(--pf-c-alert--m-inline--BorderBottomWidth)); + --pf-c-alert--m-inline--before--BackgroundColor: var(--pf-global--default-color--200); + --pf-c-alert--m-inline__icon--FontSize: var(--pf-global--icon--FontSize--md); + --pf-c-alert--m-inline__icon--Color: var(--pf-global--default-color--200); + --pf-c-alert--m-inline__icon--BackgroundColor: transparent; + --pf-c-alert--m-inline__icon--PaddingTop: calc(var(--pf-c-alert__icon--Padding) + (var(--pf-c-alert__icon--FontSize) - var(--pf-c-alert--m-inline__icon--FontSize))/2); + --pf-c-alert--m-inline__icon--PaddingRight: 0; + --pf-c-alert--m-inline__icon--PaddingBottom: var(--pf-global--spacer--md); + --pf-c-alert--m-inline__icon--PaddingLeft: var(--pf-global--spacer--md); + --pf-c-alert--m-inline--m-warning__icon--FontSize: 1.0625rem; + --pf-c-alert--m-inline--m-success__icon--Color: var(--pf-global--success-color--100); + --pf-c-alert--m-inline--m-success--before--BackgroundColor: var(--pf-global--success-color--100); + --pf-c-alert--m-inline--m-danger__icon--Color: var(--pf-global--danger-color--100); + --pf-c-alert--m-inline--m-danger--before--BackgroundColor: var(--pf-global--danger-color--100); + --pf-c-alert--m-inline--m-warning__icon--Color: var(--pf-global--warning-color--100); + --pf-c-alert--m-inline--m-warning--before--BackgroundColor: var(--pf-global--warning-color--100); + --pf-c-alert--m-inline--m-info__icon--Color: var(--pf-global--info-color--100); + --pf-c-alert--m-inline--m-info--before--BackgroundColor: var(--pf-global--info-color--100); + color: var(--pf-global--Color--100); + position: relative; + display: grid; + grid-template-columns: var(--pf-c-alert--grid-template-columns); + grid-template-rows: var(--pf-c-alert--grid-template-rows); + grid-template-areas: "icon title action" "icon content content"; + background-color: var(--pf-c-alert--BackgroundColor); + box-shadow: var(--pf-c-alert--BoxShadow) } .pf-c-alert.pf-m-success { @@ -7115,48 +7120,48 @@ pf-c-empty-state .pf-c-button.pf-m-primary.slim { .pf-c-inline-edit__label.pf-m-bold { font-weight: var(--pf-c-inline-edit__label--m-bold--FontWeight) -} - -.pf-c-badge { - --pf-c-badge--BorderRadius: var(--pf-global--BorderRadius--lg); - --pf-c-badge--FontSize: var(--pf-global--FontSize--xs); - --pf-c-badge--FontWeight: var(--pf-global--FontWeight--bold); - --pf-c-badge--PaddingRight: var(--pf-global--spacer--sm); - --pf-c-badge--PaddingLeft: var(--pf-global--spacer--sm); - --pf-c-badge--Color: var(--pf-global--Color--dark-100); - --pf-c-badge--MinWidth: var(--pf-global--spacer--xl); - --pf-c-badge--m-read--BackgroundColor: var(--pf-global--BackgroundColor--300); - --pf-c-badge--m-read--Color: var(--pf-global--Color--dark-100); - --pf-c-badge--m-unread--BackgroundColor: var(--pf-global--primary-color--100); - --pf-c-badge--m-unread--Color: var(--pf-global--Color--light-100); - display: inline-block; - min-width: var(--pf-c-badge--MinWidth); - padding-right: var(--pf-c-badge--PaddingRight); - padding-left: var(--pf-c-badge--PaddingLeft); - font-size: var(--pf-c-badge--FontSize); - font-weight: var(--pf-c-badge--FontWeight); - color: var(--pf-c-badge--Color); - text-align: center; - background-color: var(--pf-c-badge--BackgroundColor); - border-radius: var(--pf-c-badge--BorderRadius) -} - -.pf-c-badge.pf-m-read { - --pf-c-badge--Color: var(--pf-c-badge--m-read--Color); - --pf-c-badge--BackgroundColor: var(--pf-c-badge--m-read--BackgroundColor) -} - -.pf-c-badge.pf-m-unread { - --pf-c-badge--Color: var(--pf-c-badge--m-unread--Color); - --pf-c-badge--BackgroundColor: var(--pf-c-badge--m-unread--BackgroundColor) -} - -.pf-l-bullseye { - --pf-l-bullseye--Padding: 0; - display: flex; - align-items: center; - justify-content: center; - height: 100%; - padding: var(--pf-l-bullseye--Padding); - margin: 0 +} + +.pf-c-badge { + --pf-c-badge--BorderRadius: var(--pf-global--BorderRadius--lg); + --pf-c-badge--FontSize: var(--pf-global--FontSize--xs); + --pf-c-badge--FontWeight: var(--pf-global--FontWeight--bold); + --pf-c-badge--PaddingRight: var(--pf-global--spacer--sm); + --pf-c-badge--PaddingLeft: var(--pf-global--spacer--sm); + --pf-c-badge--Color: var(--pf-global--Color--dark-100); + --pf-c-badge--MinWidth: var(--pf-global--spacer--xl); + --pf-c-badge--m-read--BackgroundColor: var(--pf-global--BackgroundColor--300); + --pf-c-badge--m-read--Color: var(--pf-global--Color--dark-100); + --pf-c-badge--m-unread--BackgroundColor: var(--pf-global--primary-color--100); + --pf-c-badge--m-unread--Color: var(--pf-global--Color--light-100); + display: inline-block; + min-width: var(--pf-c-badge--MinWidth); + padding-right: var(--pf-c-badge--PaddingRight); + padding-left: var(--pf-c-badge--PaddingLeft); + font-size: var(--pf-c-badge--FontSize); + font-weight: var(--pf-c-badge--FontWeight); + color: var(--pf-c-badge--Color); + text-align: center; + background-color: var(--pf-c-badge--BackgroundColor); + border-radius: var(--pf-c-badge--BorderRadius) +} + +.pf-c-badge.pf-m-read { + --pf-c-badge--Color: var(--pf-c-badge--m-read--Color); + --pf-c-badge--BackgroundColor: var(--pf-c-badge--m-read--BackgroundColor) +} + +.pf-c-badge.pf-m-unread { + --pf-c-badge--Color: var(--pf-c-badge--m-unread--Color); + --pf-c-badge--BackgroundColor: var(--pf-c-badge--m-unread--BackgroundColor) +} + +.pf-l-bullseye { + --pf-l-bullseye--Padding: 0; + display: flex; + align-items: center; + justify-content: center; + height: 100%; + padding: var(--pf-l-bullseye--Padding); + margin: 0 } \ No newline at end of file diff --git a/zfs/zfs.js b/zfs/zfs.js index bb8a773..68f3d4c 100644 --- a/zfs/zfs.js +++ b/zfs/zfs.js @@ -1,20910 +1,20910 @@ -/* - * This file is part of Cockpit ZFS Manager. - * - * Copyright (C) 2019-2020 OPTIMANS Pty Ltd. - * - * Cockpit ZFS Manager is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 3 of the License, or (at your option) - * any later version. - * - * Cockpit ZFS Manager is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for - * more details. - * - * You should have received a copy of the GNU Lesser General Public License along - * with Cockpit ZFS Manager; If not, see . - */ - - -//#region Configuration - Edit With Configure ZFS Manager Modal - -let zfsmanager = { - cockpit: { - datelocale: (navigator.languages && navigator.languages.length ? navigator.languages[0] : (navigator.userLanguage || navigator.language || navigator.browserLanguage || cockpit.language)), - legacy: false, - permission: null - }, - configuration: { - cockpit: { - manage: false //Remove packages that cause problems for ZFS - }, - disks: { - base2: false //Use Base-2 calculation for disk sizes - }, - loglevel: 2, //Console logging. 1=Minimal Logging, 2=Enhanced Logging, 3=Enhanced Logging and Process Commands, 4=Verbose - samba: { - manage: false, //Manage Samba shares - windowscompatibility: true //Disable special characters in share name that don't work with Microsoft Windows - }, - updates: { - check: true //Check for updates on launch - }, - zfs: { - filesystem: { - cloneorigin: false, //Display clone origin in tooltip - quotarestrict: true, //Restrict quota maximum to size of storage pool - readonlylockdown: false, //Prevent changes to read only file systems and clone file systems - snapshotactions: true, //Display snapshot actions in file system actions menu - }, - snapshot: { +/* + * This file is part of Cockpit ZFS Manager. + * + * Copyright (C) 2019-2020 OPTIMANS Pty Ltd. + * + * Cockpit ZFS Manager is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 3 of the License, or (at your option) + * any later version. + * + * Cockpit ZFS Manager is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with Cockpit ZFS Manager; If not, see . + */ + + +//#region Configuration - Edit With Configure ZFS Manager Modal + +let zfsmanager = { + cockpit: { + datelocale: (navigator.languages && navigator.languages.length ? navigator.languages[0] : (navigator.userLanguage || navigator.language || navigator.browserLanguage || cockpit.language)), + legacy: false, + permission: null + }, + configuration: { + cockpit: { + manage: false //Remove packages that cause problems for ZFS + }, + disks: { + base2: false //Use Base-2 calculation for disk sizes + }, + loglevel: 2, //Console logging. 1=Minimal Logging, 2=Enhanced Logging, 3=Enhanced Logging and Process Commands, 4=Verbose + samba: { + manage: false, //Manage Samba shares + windowscompatibility: true //Disable special characters in share name that don't work with Microsoft Windows + }, + updates: { + check: true //Check for updates on launch + }, + zfs: { + filesystem: { + cloneorigin: false, //Display clone origin in tooltip + quotarestrict: true, //Restrict quota maximum to size of storage pool + readonlylockdown: false, //Prevent changes to read only file systems and clone file systems + snapshotactions: true, //Display snapshot actions in file system actions menu + }, + snapshot: { filesystemlist: true //Display snapshots in lists by file system - }, - status: { - errorcolors: true, //Display warning and danger colors for error counts - trimunsupported: false //Display TRIM unsupported message - }, - storagepool: { - activetab: 1, //Default active tab for storage pool. 1=File Systems, 2=Snapshots, 3=Status - boot: true, //Display boot storage pool - bootlockdown: true, //Prevent changes to boot storage pool. Changes may cause an unbootable system - count: true, //Display file systems and snapshots count - refreshall: false, //Refresh all components - root: true //Display root storage pool - } - } - }, - system: { - operatingsystem: "" - }, - user: { - admin: true, - configuration: false, - name: "" - }, - version: "0.3.0.299", - zfs: { - storagepool: { - boot: "", - root: "", - refreshid: [] - }, - warnings: { + }, + status: { + errorcolors: true, //Display warning and danger colors for error counts + trimunsupported: false //Display TRIM unsupported message + }, + storagepool: { + activetab: 1, //Default active tab for storage pool. 1=File Systems, 2=Snapshots, 3=Status + boot: true, //Display boot storage pool + bootlockdown: true, //Prevent changes to boot storage pool. Changes may cause an unbootable system + count: true, //Display file systems and snapshots count + refreshall: false, //Refresh all components + root: true //Display root storage pool + } + } + }, + system: { + operatingsystem: "" + }, + user: { + admin: true, + configuration: false, + name: "" + }, + version: "0.3.1.301", + zfs: { + storagepool: { + boot: "", + root: "", + refreshid: [] + }, + warnings: { nvmevdev: false - }, - version: null - } -}; - -//#endregion - -//#region Document Ready - -$(document).ready(function () { - FnConsoleInitialize(); - - FnConsole.log[1]("Cockpit ZFS Manager, Version: " + zfsmanager.version); - - FnConfigurationGet() - .always(function () { - Requirements({ zfs: false }); - }); - - $("body").tooltip({ - html: "true", - selector: `[data-toggle="tooltip"]` - }); - - $(cockpit.info).on("changed", function () { - zfsmanager.cockpit.legacy = (cockpit.info["version"] < 207 ? true : false); - }); -}); - -//#endregion - -//#region Requirements - -function Requirements(skip = { zfs: false }) { - if (!skip.zfs) { - FnZfsVersionGet() - .done(function () { - if ($("#alerts-requirements").hasClass("hidden")) { - if (zfsmanager.configuration.samba.manage) { - FnSambaVersionGet() - .done(function () { - FnFirstSteps(); - }); - } else { - FnFirstSteps(); - } - } - }); - } else { - if (zfsmanager.configuration.samba.manage) { - FnSambaVersionGet() - .done(function () { - FnFirstSteps(); - }); - } else { - FnFirstSteps(); - } - } -} - -//#endregion - -//#region First Steps - -function FnFirstSteps() { - FnSystemOperatingSystemGet(); - FnCockpitPermissionsGet(); - - FnModalsRegister(); - FnStoragePoolsGet(); - - FnVersionWarning(); - FnZfsVersionWarnings() -} - -function FnFirstStepsPrivileged() { - //Execute functions when user is an administrator - - FnConfigurationDirectoryCreate(); - FnConfigurationDirectoryRuntimeCreate(); - - if (!zfsmanager.user.configuration) { - FnConfigurationLegacyGet(); - } else { - if (zfsmanager.configuration.cockpit.manage) { - FnCockpitManage(); - } - if (zfsmanager.configuration.samba.manage) { - FnSambaManage(); - } - FnSambaUsersharesDirectoryCreate(); - if (zfsmanager.configuration.updates.check) { - FnUpdatesCheck({ alert: true }); - } - } -} - -//#endregion - -//#region Fixed Content Click Actions - -$(document).on("click", "#btn-alerts-requirements-samba-refresh", function () { - Requirements({ zfs: true }); -}); - -$(document).on("click", "#btn-alerts-requirements-zfs-refresh", function () { - Requirements({ zfs: false }); -}); - -$(document).on("click", "#btn-storagepools-refresh", function () { - FnStoragePoolsGet(); -}); - -$(document).on("click", "#table-storagepools > tbody > tr.listing-ct-item", function (element) { - if (!$(this).hasClass("listing-ct-storagepoolsnotfound") && !$(element.target).is("a, button, .fa.fa-ellipsis-v, input")) { - if (!$(this).parent().hasClass("open")) { - $(this).parent().addClass("open"); - - $(this).attr("data-pool-refresh-filesystems", "false"); - $(this).attr("data-pool-refresh-snapshots", "false"); - $(this).attr("data-pool-refresh-status", "false"); - - FnStoragePoolRefresh({ name: $(this).attr("data-pool-name"), id: $(this).attr("data-pool-id") }, { storagepool: true, filesystems: true, snapshots: true, status: true }); - } else { - if (!$("#spinner-storagepool-" + $(this).attr("data-pool-id")).hasClass("hidden")) { - //Disable click action while information is still loading - } else { - $(this).parent().removeClass("open"); - - $(this).attr("data-pool-refresh-filesystems", "false"); - $(this).attr("data-pool-refresh-snapshots", "false"); - $(this).attr("data-pool-refresh-status", "false"); - - $("#spinner-storagepool-" + $(this).attr("data-pool-id")).removeClass("hidden"); - $("#listingcthead-storagepool-" + $(this).attr("data-pool-id")).addClass("hidden"); - $("#listingctbody-storagepool-" + $(this).attr("data-pool-id")).addClass("hidden"); - - FnStoragePoolRefreshAutoDisable({ name: $(this).attr("data-pool-name"), id: $(this).attr("data-pool-id") }); - } - } - } -}); - -//#endregion - -//#region Helper Functions - -String.prototype.format = function () { - let args = arguments; - - return this.replace(/\{(\d+)\}/g, function (m, n) { - return args[n]; - }); -} - -function FnAppendLeadingZeroes(data = { value }) { - if (data.value < 10) { - return "0" + data.value; - } - - return data.value; -} - -function FnFormatBytes(data = { base2: true, decimals: 0, value }) { - if (data.value == 0) { - return "0 B"; - } - - data.bytes = (data.base2 ? 1024 : 1000); - data.sizes = (data.base2 ? ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB"] : ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB"]); - data.integer = Math.floor(Math.log(data.value) / Math.log(data.bytes)); - data.decimals = (data.decimals <= 0 ? 0 : data.decimals); - - data.sizefriendly = parseFloat((data.value / Math.pow(data.bytes, data.integer)).toFixed(data.decimals)).toString() + " " + data.sizes[data.integer]; - - if (data.sizefriendly == "NaN undefined") { - data.sizefriendly = "-"; - } - - return data.sizefriendly; -} - -function FnGenerateId(character = { at: false, colon: false, forwardslash: false, period: false, underscore: false, whitespace: false }, data = { name, attribute: true }) { - let replacement = { - character: (data.attribute ? "\u22C5" : "_"), - regexp: [] - }; - - if (character.underscore) { - replacement.regexp.push({ pattern: /[_]/g, replacement: (data.attribute ? replacement.character + "u" + replacement.character : replacement.character) }) - } - if (character.at) { - replacement.regexp.push({ pattern: /[@]/g, replacement: (data.attribute ? replacement.character + "a" + replacement.character : replacement.character) }) - } - if (character.colon) { - replacement.regexp.push({ pattern: /[:]/g, replacement: (data.attribute ? replacement.character + "c" + replacement.character : replacement.character) }) - } - if (character.forwardslash) { - replacement.regexp.push({ pattern: /[/]/g, replacement: (data.attribute ? replacement.character + "f" + replacement.character : replacement.character) }) - } - if (character.period) { - replacement.regexp.push({ pattern: /[.]/g, replacement: (data.attribute ? replacement.character + "p" + replacement.character : replacement.character) }) - } - if (character.whitespace) { - replacement.regexp.push({ pattern: /[ ]/g, replacement: (data.attribute ? replacement.character + "w" + replacement.character : replacement.character) }) - } - - return replacement.regexp.reduce((n, r) => n.replace(r.pattern, r.replacement), data.name); -} - -function FnGenerateShareFileName(data = { name }) { - replacement = { - character: "_", - regexp: [] - }; - - replacement.regexp.push({ pattern: /[/]/g, replacement: replacement.character }); - - return replacement.regexp.reduce((n, r) => n.replace(r.pattern, r.replacement), data.name); -} - -function FnGenerateShareName(character = { at: false, colon: false, period: false, whitespace: false }, data = { name }) { - let replacement = { - character: "_", - regexp: [] - }; - - replacement.regexp.push({ pattern: /[/]/g, replacement: replacement.character }); - - if (character.at) { - replacement.regexp.push({ pattern: /[@]/g, replacement: replacement.character }) - } - if (character.colon || zfsmanager.configuration.samba.windowscompatibility) { - replacement.regexp.push({ pattern: /[:]/g, replacement: replacement.character }) - } - if (character.period) { - replacement.regexp.push({ pattern: /[.]/g, replacement: replacement.character }) - } else if (zfsmanager.configuration.samba.windowscompatibility) { - replacement.regexp.push({ pattern: /[.]$/g, replacement: replacement.character }) - } - if (character.whitespace) { - replacement.regexp.push({ pattern: /[ ]/g, replacement: replacement.character }) - } - - return replacement.regexp.reduce((n, r) => n.replace(r.pattern, r.replacement), data.name); -} - -function FnRound(data = { decimals: 0, value }) { - data.multiplier = Math.pow(10, data.decimals); - - return Math.round(data.value * data.multiplier) / data.multiplier; -} - -//#endregion - -//#region Date/Time - -function FnDateTime() { - return (new Date).toLocaleString(zfsmanager.cockpit.datelocale, { day: "numeric", month: "numeric", year: "numeric", hour: "numeric", minute: "numeric", second: "numeric", hour12: true }); -} - -function FnDateTimeEpoch(data = { date }) { - return (new Date(data.date * 1000)).toLocaleString(zfsmanager.cockpit.datelocale, { hour12: true }); -} - -function FnDateTimeSnapshot(data = { date }) { - if (!data.date) { - data.date = new Date(); - } - - return data.date.getFullYear() + "." + FnAppendLeadingZeroes({ value: data.date.getMonth() + 1 }) + "." + FnAppendLeadingZeroes({ value: data.date.getDate() }) + "-" + FnAppendLeadingZeroes({ value: data.date.getHours() }) + "." + FnAppendLeadingZeroes({ value: data.date.getMinutes() }) + "." + FnAppendLeadingZeroes({ value: data.date.getSeconds() }); -} - -//#endregion - -//#region Display Alert - -function FnDisplayAlert(notification = { status, title, description, breakword: false }, toast = { name, id, timeout: 4 }) { - if (zfsmanager.cockpit.legacy) { //Dirty way of handling alerts for PF3 and PF4 - FnDisplayAlertLegacy({ status: notification.status, title: notification.title, description: notification.description, breakword: notification.breakword }, { name: toast.name, id: toast.id, timeout: toast.timeout }); - - return; - } - - toast.timeout = ($.isNumeric(toast.timeout) ? toast.timeout : 4); - toast.uniqueid = (new Date).getTime() + "-" + Math.round(Math.random() * 20); - - switch (notification.status) { - case "danger": - toast.icon = "fa fa-exclamation-circle"; - toast.statusaria = "Danger"; - break; - case "info": - toast.icon = "fa fa-info-circle"; - toast.statusaria = "Information"; - break; - case "success": - toast.icon = "fa fa-check-circle"; - toast.statusaria = "Success"; - break; - case "warning": - toast.icon = "fa fa-exclamation-triangle"; - toast.statusaria = "Warning"; - break; - default: - notification.status = ""; - toast.icon = "fa fa-bell"; - toast.statusaria = "Default"; - break; - } - - notification.output = ` -
  • -
    -
    - -
    -

    ` + toast.statusaria + ` alert:` + notification.title + `

    - ` + (notification.description ? `

    ` + notification.description + `

    ` : ``) + ` -
    - -
    -
    - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#alert-` + toast.name + (toast.id ? `-` + toast.id : ``) + `-` + toast.uniqueid + ` .pf-c-alert__action").on("click",".pf-c-button",function(){ - $("#alert-` + toast.name + (toast.id ? `-` + toast.id : ``) + `-` + toast.uniqueid + `").fadeTo(150, 0).slideUp(150, function () { - $(this).remove(); - }); - }); - - setTimeout(function () { - $("#alert-` + toast.name + (toast.id ? `-` + toast.id : ``) + `-` + toast.uniqueid + `").fadeTo(500, 0).slideUp(500, function () { - $(this).remove(); - }); - }, ` + toast.timeout + `000); - \x3C/script> -
  • - `; - - $("#alerts-notifications").append(notification.output); -} - -function FnDisplayAlertLegacy(notification = { status, title, description, breakword: false }, toast = { name, id, timeout: 4 }) { - toast.timeout = ($.isNumeric(toast.timeout) ? toast.timeout : 4); - toast.uniqueid = (new Date).getTime() + "-" + Math.round(Math.random() * 20); - - switch (notification.status) { - case "danger": - toast.icon = "pficon pficon-error-circle-o"; - break; - case "success": - toast.icon = "pficon pficon-ok"; - break; - case "warning": - toast.icon = "pficon pficon-warning-triangle-o"; - break; - default: - notification.status = "info"; - toast.icon = "pficon pficon-info"; - break; - } - - notification.output = ` -
    - - - ` + notification.title + (notification.description ? `:` : ``) + ` ` + (notification.description ? notification.description : ``) + ` - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - setTimeout(function () { - $("#toast-` + toast.name + (toast.id ? `-` + toast.id : ``) + `-` + toast.uniqueid + `").fadeTo(500, 0).slideUp(500, function () { - $(this).remove(); - }); - }, ` + toast.timeout + `000); - \x3C/script> -
    - `; - - $("#alerts-notifications-legacy").append(notification.output); -} - -function FnDisplayInlineAlert(notification = { status, title, description }, inline = { name, id, hidden: false }) { - if (zfsmanager.cockpit.legacy) { //Dirty way of handling alerts for PF3 and PF4 - return FnDisplayInlineAlertLegacy({ status: notification.status, title: notification.title, description: notification.description }, { name: inline.name, id: inline.id, hidden: inline.hidden }); - } - - switch (notification.status) { - case "danger": - inline.icon = "fa fa-exclamation-circle"; - inline.statusaria = "Danger"; - break; - case "info": - inline.icon = "fa fa-info-circle"; - inline.statusaria = "Information"; - break; - case "success": - inline.icon = "fa fa-check-circle"; - inline.statusaria = "Success"; - break; - case "warning": - inline.icon = "fa fa-exclamation-triangle"; - inline.statusaria = "Warning"; - break; - default: - notification.status = ""; - inline.icon = "fa fa-bell"; - inline.statusaria = "Default"; - break; - } - - notification.output = ` -
    -
    - -
    -

    ` + inline.statusaria + ` inline alert:` + notification.title + `

    - ` + (notification.description ? `

    ` + notification.description + `

    ` : ``) + ` -
    - `; - - return notification.output; -} - -function FnDisplayInlineAlertLegacy(notification = { status, title, description }, inline = { name, id, hidden: false }) { - switch (notification.status) { - case "danger": - inline.icon = "pficon pficon-error-circle-o"; - break; - case "success": - inline.icon = "pficon pficon-ok"; - break; - case "warning": - inline.icon = "pficon pficon-warning-triangle-o"; - break; - default: - notification.status = "info"; - inline.icon = "pficon pficon-info"; - break; - } - - notification.output = ` -
    ` + notification.title + (notification.description ? `: ` + notification.description : ``) + `
    - `; - - return notification.output; -} - -//#endregion - -//#region Console Logging - -let FnConsole = () => { }; - -function FnConsoleCommand(process = { command: [] }) { - return JSON.stringify(process.command.join(" ")); -} - -function FnConsoleInitialize() { - FnConsole = (() => { - let time = () => { }; - - time.toString = () => { - return (new Date).toLocaleString(zfsmanager.cockpit.datelocale, { hour: "numeric", minute: "numeric", second: "numeric", hour12: true }) + ":"; - }; - - return { - error: console.error.bind(console, "%s", time), - log: { - 1: (zfsmanager.configuration.loglevel >= 1 ? console.log.bind(console, "%s", time) : FnConsoleNull), - 2: (zfsmanager.configuration.loglevel >= 2 ? console.log.bind(console, "%s", time) : FnConsoleNull), - 3: (zfsmanager.configuration.loglevel >= 3 ? console.log.bind(console, "%c%s Command: %s", "color: #0066CC", time) : FnConsoleNull), - 4: (zfsmanager.configuration.loglevel == 4 ? console.log.bind(console, "%c%s %s", "color: #486B00", time) : FnConsoleNull) - }, - warn: console.warn.bind(console, "%s", time) - } - })(); -} - -function FnConsoleNull() { - //Do not display console message -} - -function FnConsoleVerbose(process = { data, message }) { - return process.message + " Verbose\n" + process.data; -} - -//#endregion - -//#region Cockpit ZFS Manager - -function FnConfigurationGet() { - FnConsole.log[2]("Cockpit ZFS Manager, Configuration, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: [`cockpit.file("/etc/cockpit/zfs/config.json").read()`] })); - - return cockpit.file("/etc/cockpit/zfs/config.json").read() - .done(function (user) { - FnConsole.log[4](FnConsoleVerbose({ data: user, message: "Cockpit ZFS Manager, Configuration, Get:" })); - - try { - user = JSON.parse(user, (key, value) => { - if (/^#[0-9]/.test(key) == false) { - return value; - } - }); - - user.cockpit = (user.cockpit === undefined ? zfsmanager.configuration.cockpit : user.cockpit); - user.cockpit.manage = (user.cockpit.manage === undefined ? zfsmanager.configuration.cockpit.manage : user.cockpit.manage); - - user.disks = (user.disks === undefined ? zfsmanager.configuration.disks : user.disks); - user.disks.base2 = (user.disks.base2 === undefined ? zfsmanager.configuration.disks.base2 : user.disks.base2); - - user.loglevel = (user.loglevel === undefined ? zfsmanager.configuration.loglevel : user.loglevel); - - user.samba = (user.samba === undefined ? zfsmanager.configuration.samba : user.samba); - user.samba.manage = (user.samba.manage === undefined ? zfsmanager.configuration.samba.manage : user.samba.manage); - user.samba.windowscompatibility = (user.samba.windowscompatibility === undefined ? zfsmanager.configuration.samba.windowscompatibility : user.samba.windowscompatibility); - - user.updates = (user.updates === undefined ? zfsmanager.configuration.updates : user.updates); - user.updates.check = (user.updates.check === undefined ? zfsmanager.configuration.updates.check : user.updates.check); - - user.zfs = (user.zfs === undefined ? zfsmanager.configuration.zfs : user.zfs); - user.zfs.filesystem = (user.zfs.filesystem === undefined ? zfsmanager.configuration.zfs.filesystem : user.zfs.filesystem); - user.zfs.filesystem.snapshotactions = (user.zfs.filesystem.snapshotactions === undefined ? zfsmanager.configuration.zfs.filesystem.snapshotactions : user.zfs.filesystem.snapshotactions); - user.zfs.filesystem.cloneorigin = (user.zfs.filesystem.cloneorigin === undefined ? zfsmanager.configuration.zfs.filesystem.cloneorigin : user.zfs.filesystem.cloneorigin); - user.zfs.filesystem.quotarestrict = (user.zfs.filesystem.quotarestrict === undefined ? zfsmanager.configuration.zfs.filesystem.quotarestrict : user.zfs.filesystem.quotarestrict); - user.zfs.filesystem.readonlylockdown = (user.zfs.filesystem.readonlylockdown === undefined ? zfsmanager.configuration.zfs.filesystem.readonlylockdown : user.zfs.filesystem.readonlylockdown); - user.zfs.snapshot = (user.zfs.snapshot === undefined ? zfsmanager.configuration.zfs.snapshot : user.zfs.snapshot); - user.zfs.snapshot.filesystemlist = (user.zfs.snapshot.filesystemlist === undefined ? zfsmanager.configuration.zfs.snapshot.filesystemlist : user.zfs.snapshot.filesystemlist); - user.zfs.status = (user.zfs.status === undefined ? zfsmanager.configuration.zfs.status : user.zfs.status); - user.zfs.status.errorcolors = (user.zfs.status.errorcolors === undefined ? zfsmanager.configuration.zfs.status.errorcolors : user.zfs.status.errorcolors); - user.zfs.status.trimunsupported = (user.zfs.status.trimunsupported === undefined ? zfsmanager.configuration.zfs.status.trimunsupported : user.zfs.status.trimunsupported); - user.zfs.storagepool = (user.zfs.storagepool === undefined ? zfsmanager.configuration.zfs.storagepool : user.zfs.storagepool); - user.zfs.storagepool.activetab = (user.zfs.storagepool.activetab === undefined ? zfsmanager.configuration.zfs.storagepool.activetab : user.zfs.storagepool.activetab); - user.zfs.storagepool.count = (user.zfs.storagepool.count === undefined ? zfsmanager.configuration.zfs.storagepool.count : user.zfs.storagepool.count); - user.zfs.storagepool.boot = (user.zfs.storagepool.boot === undefined ? zfsmanager.configuration.zfs.storagepool.boot : user.zfs.storagepool.boot); - user.zfs.storagepool.bootlockdown = (user.zfs.storagepool.bootlockdown === undefined ? zfsmanager.configuration.zfs.storagepool.bootlockdown : user.zfs.storagepool.bootlockdown); - user.zfs.storagepool.root = (user.zfs.storagepool.root === undefined ? zfsmanager.configuration.zfs.storagepool.root : user.zfs.storagepool.root); - user.zfs.storagepool.refreshall = (user.zfs.storagepool.refreshall === undefined ? zfsmanager.configuration.zfs.storagepool.refreshall : user.zfs.storagepool.refreshall); - - zfsmanager.configuration = user; - zfsmanager.user.configuration = true; - - FnConsole.log[1]("Cockpit ZFS Manager, Configuration, Get: Success"); - - FnConsoleInitialize(); - } - catch (error) { - FnConsole.warn("Cockpit ZFS Manager, Configuration, Get: Failed, Message: Configuration does not exist. Using defaults."); - }; - }) - .fail(function (message) { - FnConsole.warn("Cockpit ZFS Manager, Configuration, Get: Failed, Message: Configuration does not exist. Using defaults."); - }); -}; - -function FnConfigure(user = { cockpit: { manage: true }, disks: { base2: false }, loglevel: 1, samba: { manage: true, windowscompatibility: true }, updates: { check: true }, zfs: { filesystem: { cloneorigin: false, quotarestrict: true, readonlylockdown: true, snapshotactions: true }, snapshot: { filesystemlist: true }, status: { errorcolors: true, trimunsupported: false }, storagepool: { activetab: 1, boot: true, bootlockdown: true, count: true, refreshall: false, root: true } } }, modal = { name, welcome: false }) { - let process = { - command: ["/bin/sh", "-c", "echo '" + JSON.stringify(user, null, " ").replace(/^\{\n/, `{\n "#1": "COCKPIT ZFS MANAGER",\n "#2": "WARNING: DO NOT EDIT, AUTO-GENERATED CONFIGURATION",\n`) + "' > /etc/cockpit/zfs/config.json"] - }; - - FnConsole.log[2]("Cockpit ZFS Manager, Configure: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-" + modal.name + " span").text("Saving configuration..."); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function (data) { - FnDisplayAlert({ status: "success", title: "Configuration successfully updated", description: null, breakword: false }, { name: modal.name, id: null, timeout: 4 }); - - FnConsole.log[1]("Cockpit ZFS Manager, Configure: Success"); - }) - .fail(function (message, data) { - FnDisplayAlert({ status: "danger", title: "Configuration could not be updated", description: null, breakword: false }, { name: modal.name, id: null, timeout: 4 }); - - FnConsole.warn("Cockpit ZFS Manager, Configure: Failed, Message: " + (data ? data : message)); - }) - .finally(function () { - if ((modal.welcome || !modal.welcome && zfsmanager.configuration.samba.manage) && !user.samba.manage) { - FnSambaSharesDestroyAll({ restart: false }, { silent: true }, { name: modal.name }) - .finally(function () { - FnConfigureFinally({ name: modal.name, welcome: modal.welcome }); - }); - } else if ((modal.welcome || !modal.welcome && !zfsmanager.configuration.samba.manage) && user.samba.manage) { - FnSambaSharesEnableAll({ restart: false }, { silent: false }, { name: modal.name }) - .finally(function () { - FnConfigureFinally({ name: modal.name, welcome: modal.welcome }); - }); - } else { - FnConfigureFinally({ name: modal.name, welcome: modal.welcome }); - } - }); -} - -function FnConfigureFinally(modal = { name, welcome: false }) { - $("#spinner-" + modal.name + " span").text("Reloading Cockpit ZFS Manager..."); - - setTimeout(function () { - location.reload(true); - }, 2000); -} - -function FnConfigurationDirectoryCreate() { - let process = { - command: ["/bin/sh", "-c", `[ ! -d /etc/cockpit/zfs ] || [ ! -d /etc/cockpit/zfs/shares ] || [ ! -d /etc/cockpit/zfs/snapshots ] && /bin/mkdir -p /etc/cockpit/zfs/shares /etc/cockpit/zfs/snapshots || printf "Skipped"`] - }; - - FnConsole.log[2]("Cockpit ZFS Manager, Configuration Directory, Create: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Cockpit ZFS Manager, Configuration Directory, Create:" })); - - if (data == "Skipped") { - FnConsole.log[2]("Cockpit ZFS Manager, Configuration Directory, Create: Skipped"); - } else { - FnConsole.log[1]("Cockpit ZFS Manager, Configuration Directory, Create: Success"); - } - }) - .fail(function (message, data) { - FnConsole.warn("Cockpit ZFS Manager, Configuration Directory, Create: Failed, Message: " + (data ? data : message)); - }); -} - -function FnConfigurationDirectoryRuntimeCreate() { - let process = { - command: ["/bin/sh", "-c", `[ ! -d /run/cockpit/zfs/shares ] && /bin/mkdir -p /run/cockpit/zfs/shares || printf "Skipped"`] - }; - - FnConsole.log[2]("Cockpit ZFS Manager, Runtime Configuration Directory, Create: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Cockpit ZFS Manager, Runtime Configuration Directory, Create:" })); - - if (data == "Skipped") { - FnConsole.log[2]("Cockpit ZFS Manager, Runtime Configuration Directory, Create: Skipped"); - } else { - FnConsole.log[1]("Cockpit ZFS Manager, Runtime Configuration Directory, Create: Success"); - } - }) - .fail(function (message, data) { - FnConsole.warn("Cockpit ZFS Manager, Runtime Configuration Directory, Create: Failed, Message: " + (data ? data : message)); - }); -} - -function FnConfigurationLegacyGet() { - let process = { - command: ["/bin/sh", "-c"] - }; - - FnCockpitPackagePathGet({ sosreport: false }) - .done(function (data) { - let path = data.replace(/\s +/g, "\u22C5").replace(/\/$/, "").replace(/\n/, "").split("\u22C5")[2]; - - if (!path || /\/cockpit\/zfs/.test(path) == false) { - path = "/usr/share/cockpit/zfs" - } - - process.command.push(`[ -e '` + path + `/config.json' ] && printf "true" || printf "false"`); - - FnConsole.log[2]("Cockpit ZFS Manager, Configuration, Legacy, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - cockpit.spawn(process.command, { err: "out" }) - .done(function (_data) { - FnConsole.log[4](FnConsoleVerbose({ data: _data, message: "Cockpit ZFS Manager, Configuration, Legacy, Get:" })); - - if (_data == "true") { - FnConsole.log[1]("Cockpit ZFS Manager, Configuration, Legacy, Get: Success"); - - FnModalUpdateContent({ id: $("#modal-update") }); - - $("#modal-update").modal("show"); - $("#spinner-update span").text("Relocating configuration file..."); - - FnConfigurationLegacyRelocate({ path: path }) - .done(function () { - $("#spinner-update span").text("Reloading Cockpit ZFS Manager..."); - - setTimeout(function () { - location.reload(true); - }, 2000); - }) - .fail(function () { - FnModalWelcomeContent({ id: $("#modal-welcome") }); - - $("#modal-update").modal("hide"); - $("#modal-welcome").modal("show"); - }); - } else { - FnConsole.log[2]("Cockpit ZFS Manager, Configuration, Legacy, Get: " + (_data == "false" ? "Skipped" : "Failed")); - - FnModalWelcomeContent({ id: $("#modal-welcome") }); - - $("#modal-welcome").modal("show"); - } - }) - .fail(function (_message, _data) { - FnConsole.warn("Cockpit ZFS Manager, Configuration, Legacy, Get: Failed, Message: " + (_data ? _data : _message)); - - FnModalWelcomeContent({ id: $("#modal-welcome") }); - - $("#modal-welcome").modal("show"); - }); - }) - .fail(function () { - FnModalWelcomeContent({ id: $("#modal-welcome") }); - - $("#modal-welcome").modal("show"); - }); -} - -function FnConfigurationLegacyRelocate(legacy = { path }) { - let process = { - command: ["/bin/sh", "-c", `/bin/mv -f ` + legacy.path + `/config.json /etc/cockpit/zfs/config.json`] - }; - - FnConsole.log[2]("Cockpit ZFS Manager, Configuration, Legacy, Relocate: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Cockpit ZFS Manager, Configuration, Legacy, Relocate:" })); - - FnConsole.log[1]("Cockpit ZFS Manager, Configuration, Legacy, Relocate: Success"); - }) - .fail(function (message, data) { - FnConsole.warn("Cockpit ZFS Manager, Configuration, Legacy, Relocate: Failed, Message: " + (data ? data : message)); - }); -} - -function FnUpdatesCheck(display = { alert: true }) { - FnConsole.log[2]("Cockpit ZFS Manager, Updates, Check: In Progress"); - - $.ajax({ url: "https://api.github.com/repos/optimans/cockpit-zfs-manager/releases", dataType: "json", cache: false }) - .done(function (data) { - if (data[0].name) { - if (FnUpdatesVersionCompare({ installed: zfsmanager.version, latest: data[0].name }) < 0) { - setTimeout(function () { - $("#alert-about-update").removeClass("hidden"); - $("#span-about-update-version").html(`` + data[0].name + ` ` + (data[0].prerelease === true ? `(Pre-release)` : `(Release)`) + ``); - - if (display.alert) { - FnDisplayAlert({ status: "info", title: "A new version of Cockpit ZFS Manager is now available", description: ` ` + data[0].name + ` ` + (data[0].prerelease === true ? `(Pre-release)` : `(Release)`) + ``, breakword: true }, { name: "update", id: null, timeout: 30 }); - } - }, 500); - } - - FnConsole.log[2]("Cockpit ZFS Manager, Updates, Check: Success"); - } else { - FnConsole.warn("Cockpit ZFS Manager, Updates, Check: Failed, Message: Unable to retrieve release information."); - } - }) - .fail(function (message) { - FnConsole.warn("Cockpit ZFS Manager, Updates, Check: Failed, Message: " + message); - }); -} - -function FnUpdatesVersionCompare(version = { installed, latest }) { - version.installed = version.installed.replace(/[^0-9.-]/g, "").replace(/\s+/g, "").replace(/-/g, ".").split("."); - version.latest = version.latest.replace(/[^0-9.-]/g, "").replace(/\s+/g, "").replace(/-/g, ".").split("."); - - let min = Math.min(version.installed.length, version.latest.length); - - for (let i = 0; i < min; ++i) { - version.installed[i] = parseInt(version.installed[i], 10); - version.latest[i] = parseInt(version.latest[i], 10); - - if (version.installed[i] > version.latest[i]) { - return 1; - } - if (version.installed[i] < version.latest[i]) { - return -1; - } - } - - return version.installed.length == (version.latest.length ? 0 : (version.installed.length < version.latest.length ? -1 : 1)); -} - -function FnVersionWarning() { - if (/alpha|beta|dev|internal|pre|rc/gi.test(zfsmanager.version)) { - FnDisplayAlert({ status: "warning", title: "Pre-release version of Cockpit ZFS Manager is installed", description: zfsmanager.version + ` is an unstable build and features may not work as intended`, breakword: true }, { name: "version-warning", id: null, timeout: 60 }); + }, + version: null } -} - -//#endregion - -//#region Cockpit - -function FnCockpitElementsDisable() { - let message = `The user ` + zfsmanager.user.name + ` is not permitted to`; - - //Disable buttons - $("#btn-configure").addClass("disabled"); - $("#btn-storagepools-filesystems-unlock").addClass("disabled"); - $("#btn-storagepools-create").prop("title", message + " create a storage pool").attr("data-placement", "auto bottom").attr("data-toggle", "tooltip").addClass("disabled"); - $("#btn-storagepools-import").prop("title", message + " import a storage pool").attr("data-placement", "auto bottom").attr("data-toggle", "tooltip").addClass("disabled"); - $("[id^=btn-storagepool-filesystems-create-]").prop("title", message + " create a file system").attr("data-placement", "auto top").attr("data-toggle", "tooltip").addClass("disabled"); - $("[id^=btn-storagepool-snapshots-create-]").prop("title", message + " create a snapshot").attr("data-placement", "auto top").attr("data-toggle", "tooltip").addClass("disabled"); - $("[id^=btn-storagepool-snapshot-dropdown-]").prop("title", message + " manage this snapshot").attr("data-placement", "auto left").attr("data-toggle", "tooltip").addClass("disabled"); - $("[id^=btn-storagepool-status-dropdown-]").prop("title", message + " manage this storage pool").attr("data-placement", "auto left").attr("data-toggle", "tooltip").addClass("disabled"); - - //Disable privileged items - $(".privileged").addClass("disabled"); - - //Disable privileged modal items - $(".privileged-modal").prop("disabled", true); - $(".privileged-modal button").prop("disabled", true); - $(".privileged-modal input").prop("disabled", true); - - //Disable sliders - $("#validationwrapper-storagepools-create-refreservation .slider-pf .slider *").addClass("disabled"); - $("#slider-storagepools-create-refreservation").slider("disable"); - $("[id^=validationwrapper-storagepool-filesystems-create-quota-] .slider-pf .slider *").addClass("disabled"); - $("[id^=slider-storagepool-filesystems-create-quota-]").slider("disable"); - $("[id^=validationwrapper-storagepool-filesystem-configure-quota-] .slider-pf .slider *").addClass("disabled"); - $("[id^=slider-storagepool-filesystem-configure-quota-]").slider("disable"); - $("[id^=validationwrapper-storagepool-filesystem-configure-refreservation-] .slider-pf .slider *").addClass("disabled"); - $("[id^=slider-storagepool-filesystem-configure-refreservation-]").slider("disable"); - - //Remove primary color from unlock file system menu item - $("[id^=btn-storagepool-filesystem-unlock-] > strong").removeClass("text-ct-locked"); - $("[id^=btn-storagepool-filesystem-unlock-icon-]").removeClass("pficon-ct-locked"); -} - -function FnCockpitElementsUpdate() { - if (!zfsmanager.user.admin) { - FnCockpitElementsDisable(); - } -} - -function FnCockpitManage() { - if (zfsmanager.user.admin) { - FnCockpitPackageSosReportDelete(); //SOS Report package will cause ZFS storage drives to appear offline when performing a diagnostic report - } -} - -function FnCockpitPackagePathGet(package = { sosreport: false }) { - let process = { - command: ["/bin/sh", "-c", `cockpit-bridge --packages | /bin/grep -m1 '/cockpit/` + (package.sosreport ? `sosreport` : `zfs`) + `$' || printf "false"`] //printf fix for Debian - }; - - FnConsole.log[2]("Cockpit, " + (package.sosreport ? "SOS Report" : "Cockpit ZFS Manager") + " Package Path, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Cockpit, " + (package.sosreport ? "SOS Report" : "Cockpit ZFS Manager") + " Package Path, Get:" })); - - let path = data.replace(/\s +/g, "\u22C5").replace(/\/$/, "").replace(/\n/, "").split("\u22C5")[2]; - - FnConsole.log[1]("Cockpit, " + (package.sosreport ? "SOS Report" : "Cockpit ZFS Manager") + " Package Path, Get: " + (path ? "Success" : "Failed")); - }) - .fail(function (message, data) { - FnConsole.warn("Cockpit, " + (package.sosreport ? "SOS Report" : "Cockpit ZFS Manager") + " Package Path, Get: Failed, Message: " + (data ? data : message)); - }); -} - -function FnCockpitPackageSosReportDelete() { - let process = { - command: ["/bin/sh", "-c"] - }; - - FnCockpitPackagePathGet({ sosreport: true }) - .done(function (data) { - let path = data.replace(/\s +/g, "\u22C5").replace(/\/$/, "").replace(/\n/, "").split("\u22C5")[2]; - - if (!path || /\/cockpit\/sosreport$/.test(path) == false) { - path = "/usr/share/cockpit/sosreport" - } - - process.command.push(`[ -e '` + path + `' ] && /bin/rm -rf ` + path + ` || printf "Skipped"`); - - FnConsole.log[2]("Cockpit, Package, SOS Report, Delete: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function (_data) { - FnConsole.log[4](FnConsoleVerbose({ data: _data, message: "Cockpit, Package, SOS Report, Delete:" })); - - if (_data == "Skipped") { - FnConsole.log[2]("Cockpit, Package, SOS Report, Delete: Skipped"); - } else { - FnConsole.log[1]("Cockpit, Package, SOS Report, Delete: Success"); - } - }) - .fail(function (_message, _data) { - FnConsole.warn("Cockpit, Package, SOS Report, Delete: Failed, Message: " + (_data ? _data : _message)); - }); - }); -} - -function FnCockpitPermissionsGet() { - FnConsole.log[2]("Cockpit, Permissions, Get: In Progress"); - - zfsmanager.cockpit.permission = cockpit.permission({ admin: true }); - - $(zfsmanager.cockpit.permission).on("changed", function () { - zfsmanager.user.admin = zfsmanager.cockpit.permission.allowed; - zfsmanager.user.name = (zfsmanager.cockpit.permission.user ? zfsmanager.cockpit.permission.user.name : ""); - - if (zfsmanager.user.admin) { - FnConsole.log[2]("Cockpit, Permissions, Get: Success"); - - FnFirstStepsPrivileged(); - } else { - FnConsole.warn("Cockpit, Permissions, Get: Warning, Message: " + zfsmanager.user.name + " does not have administrator permissions"); - - FnCockpitElementsDisable(); - } - }); -} - -//#endregion - -//#region ZFS - -function FnZfsVersionCompare(version = { installed, threshold }) { - version.installed = version.installed.replace(/[^0-9.-]/g, "").replace(/\s+/g, "").replace(/-/g, ".").split("."); - version.threshold = version.threshold.replace(/\s+/g, "").replace(/-/g, ".").split("."); - - if (!version.installed[0]) { - return -1; - } - - let min = Math.min(version.installed.length, version.threshold.length); - - for (let i = 0; i < min; ++i) { - version.installed[i] = parseInt(version.installed[i], 10); - version.threshold[i] = parseInt(version.threshold[i], 10); - - if (version.installed[i] > version.threshold[i]) { - return 1; - } - if (version.installed[i] < version.threshold[i]) { - return -1; - } - } - - return version.installed.length == (version.threshold.length ? 0 : (version.installed.length < version.threshold.length ? -1 : 1)); -} - -function FnZfsVersionGet() { - let process = { - command: ["/bin/cat", "/sys/module/zfs/version"] - }; - let zfs = { - success: false, - threshold: "0.8" - }; - - FnConsole.log[2]("ZFS, Version, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data, message) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "ZFS, Version, Get:" })); - - if (data) { - zfsmanager.zfs.version = data.replace(/\s+/g, ""); - } - - if (!data || FnZfsVersionCompare({ installed: zfsmanager.zfs.version, threshold: zfs.threshold }) < 0) { - FnConsole.error("ZFS, Version, Get: Failed, Message: Version " + (zfsmanager.zfs.version ? zfsmanager.zfs.version : "0") + " < " + zfs.threshold); - } else { - zfs.success = true; - - FnConsole.log[1]("ZFS, Version, Get: Success, Version: " + (data ? data : message)); - } - }) - .fail(function (message, data) { - FnConsole.error("ZFS, Version, Get: Failed, Message: " + (data ? data : message)); - }) - .finally(function () { - if (!zfs.success) { - zfs.message = ` -
    - -
    -

    This package requires ZFS version ` + zfs.threshold + ` or later

    -

    If ZFS is installed, check the module is loaded into the kernel.

    -
    - -
    - `; - - $("#alerts-requirements").removeClass("hidden").html(zfs.message); - $("#container").addClass("hidden"); - } else { - if (!zfsmanager.configuration.samba.manage) { - $("#alerts-requirements").empty().addClass("hidden"); - $("#container").removeClass("hidden"); - } - } - }); -} - -function FnZfsVersionWarnings() { - zfsmanager.zfs.warnings.nvmevdev = (FnZfsVersionCompare({ installed: zfsmanager.zfs.version, threshold: "0.8.3" }) < 0 ? true : false); //GitHub Issue #9730 -} - -//#endregion - -//#region Storage Pools - -function FnStoragePoolsGet() { - let process = { - command: ["/sbin/zpool", "list", "-H", "-o", "name,guid,health,size,alloc,free,fragmentation,readonly,altroot,autotrim,version,feature@allocation_classes,feature@async_destroy,feature@bookmark_v2,feature@bookmarks,feature@device_removal,feature@edonr,feature@embedded_data,feature@empty_bpobj,feature@enabled_txg,feature@encryption,feature@extensible_dataset,feature@filesystem_limits,feature@hole_birth,feature@large_blocks,feature@large_dnode,feature@lz4_compress,feature@multi_vdev_crash_dump,feature@obsolete_counts,feature@project_quota,feature@resilver_defer,feature@sha512,feature@skein,feature@spacemap_histogram,feature@spacemap_v2,feature@userobj_accounting,feature@zpool_checkpoint", "-p"] - }; - let pools = { - empty: true - }; - - //Disable storage pool status auto refresh - zfsmanager.zfs.storagepool.refreshid.forEach((_value, _index) => { - clearInterval(_value); - }); - zfsmanager.zfs.storagepool.refreshid = []; - - $("#btn-storagepools-refresh").prop("disabled", true); - $("#table-storagepools > tbody").remove(); - $("[id^=modals-storagepool-]").remove(); - $("[id^=dynamics-storagepool-]").remove(); - $("#spinner-storagepools").removeClass("hidden"); - - FnConsole.log[2]("Storage Pools, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - FnStoragePoolsSystemReservedGet() - .finally(function () { - cockpit.spawn(process.command, { err: "out" }) - .done((data, message) => { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Storage Pools, Get:" })); - - if (data) { - pools.empty = false; - - FnStoragePoolsGetCommand({ data: data, message: message }); - } - - FnConsole.log[1]("Storage Pools, Get: Success"); - }) - .fail((message, data) => { - FnConsole.warn("Storage Pools, Get: Failed, Message: " + (data ? data : message)); - }) - .finally(function () { - if ($("#table-storagepools > tbody").length == 0) { - pools.empty = true; - } - - if (pools.empty) { - $("#table-storagepools").append(`No storage pools found.`); - } - - setTimeout(function () { - $("#spinner-storagepools").addClass("hidden"); - $("#table-storagepools > tbody").removeClass("hidden"); - }, 200); - - $("#btn-storagepools-refresh").prop("disabled", false); - - FnCockpitElementsUpdate(); - }); - }); -} - -function FnStoragePoolsGetCommand(process = { data, message }) { - let pools = { - id: [] - }; - - pools.id = process.data.split(/\n/g).filter(v => { - if (!zfsmanager.configuration.zfs.storagepool.boot && zfsmanager.zfs.storagepool.boot && new RegExp("^" + zfsmanager.zfs.storagepool.boot + "\t").test(v)) { - //Do not display boot - } else if (!zfsmanager.configuration.zfs.storagepool.root && zfsmanager.zfs.storagepool.root && new RegExp("^" + zfsmanager.zfs.storagepool.root + "\t").test(v)) { - //Do not display root - } else { - return v; - } - }); - - pools.id.forEach((_value, _index) => { - let pool = { - properties: _value.split(/\t/g).filter(v => v), - actionsmenu: { - register: {} - } - }; - - //0=name, 1=guid, 2=health, 3=size, 4=alloc, 5=free, 6=fragmentation, 7=readonly, 8=altroot, 9=autotrim, 10=version, 11=feature@allocation_classes, 12=feature@async_destroy, 13=feature@bookmark_v2, 14=feature@bookmarks, 15=feature@device_removal, 16=feature@edonr, 17=feature@embedded_data, 18=feature@empty_bpobj, 19=feature@enabled_txg, 20=feature@encryption, 21=feature@extensible_dataset, 22=feature@filesystem_limits, 23=feature@hole_birth, 24=feature@large_blocks, 25=feature@large_dnode, 26=feature@lz4_compress, 27=feature@multi_vdev_crash_dump, 28=feature@obsolete_counts, 29=feature@project_quota, 30=feature@resilver_defer, 31=feature@sha512, 32=feature@skein, 33=feature@spacemap_histogram, 34=feature@spacemap_v2, 35=feature@userobj_accounting, 36=feature@zpool_checkpoint - - pool.activetab = "filesystems"; - pool.allocated = FnFormatBytes({ base2: true, decimals: 2, value: pool.properties[4] }); - pool.allocatedpercent = FnRound({ decimals: 2, value: (pool.properties[4] / pool.properties[3]) * 100 }); - pool.altroot = (pool.properties[8] && pool.properties[8] != "-" ? true : false); - pool.autotrim = (pool.properties[9].toLowerCase() == "on" ? true : false); - pool.boot = (zfsmanager.zfs.storagepool.boot && pool.properties[0] == zfsmanager.zfs.storagepool.boot ? true : false); - pool.feature = { - allocation_classes: (/active|enabled/gi.test(pool.properties[11]) ? true : false), - async_destroy: (/active|enabled/gi.test(pool.properties[12]) ? true : false), - bookmark_v2: (/active|enabled/gi.test(pool.properties[13]) ? true : false), - bookmarks: (/active|enabled/gi.test(pool.properties[14]) ? true : false), - device_removal: (/active|enabled/gi.test(pool.properties[15]) ? true : false), - edonr: (/active|enabled/gi.test(pool.properties[16]) ? true : false), - embedded_data: (/active|enabled/gi.test(pool.properties[17]) ? true : false), - empty_bpobj: (/active|enabled/gi.test(pool.properties[18]) ? true : false), - enabled_txg: (/active|enabled/gi.test(pool.properties[19]) ? true : false), - encryption: (/active|enabled/gi.test(pool.properties[20]) ? true : false), - extensible_dataset: (/active|enabled/gi.test(pool.properties[21]) ? true : false), - filesystem_limits: (/active|enabled/gi.test(pool.properties[22]) ? true : false), - hole_birth: (/active|enabled/gi.test(pool.properties[23]) ? true : false), - large_blocks: (/active|enabled/gi.test(pool.properties[24]) ? true : false), - large_dnode: (/active|enabled/gi.test(pool.properties[25]) ? true : false), - lz4_compress: (/active|enabled/gi.test(pool.properties[26]) ? true : false), - multi_vdev_crash_dump: (/active|enabled/gi.test(pool.properties[27]) ? true : false), - obsolete_counts: (/active|enabled/gi.test(pool.properties[28]) ? true : false), - project_quota: (/active|enabled/gi.test(pool.properties[29]) ? true : false), - resilver_defer: (/active|enabled/gi.test(pool.properties[30]) ? true : false), - sha512: (/active|enabled/gi.test(pool.properties[31]) ? true : false), - skein: (/active|enabled/gi.test(pool.properties[32]) ? true : false), - spacemap_histogram: (/active|enabled/gi.test(pool.properties[33]) ? true : false), - spacemap_v2: (/active|enabled/gi.test(pool.properties[34]) ? true : false), - userobj_accounting: (/active|enabled/gi.test(pool.properties[35]) ? true : false), - zpool_checkpoint: (/active|enabled/gi.test(pool.properties[36]) ? true : false) - }; - pool.fragmentation = (pool.properties[6] == "-" ? 0 : pool.properties[6]); - pool.free = FnFormatBytes({ base2: true, decimals: 2, value: pool.properties[5] }); - pool.freepercent = FnRound({ decimals: 2, value: (pool.properties[5] / pool.properties[3]) * 100 }); - pool.guid = pool.properties[1]; - pool.health = pool.properties[2]; - pool.healthicon = FnStoragePoolHealthIcon({ health: pool.properties[2] }); - pool.id = FnGenerateId({ at: false, colon: true, forwardslash: false, period: true, underscore: true, whitespace: true }, { name: pool.properties[0], attribute: true }); - pool.name = pool.properties[0]; - pool.readonly = ((pool.properties[7].toLowerCase() == "on" || pool.boot && zfsmanager.configuration.zfs.storagepool.bootlockdown) ? true : false); - pool.size = FnFormatBytes({ base2: true, decimals: 2, value: pool.properties[3] }); - pool.root = (zfsmanager.zfs.storagepool.root && pool.properties[0] == zfsmanager.zfs.storagepool.root ? true : false); - pool.upgrade = ($.isNumeric(pool.properties[8] && !pool.boot) ? true : false); - pool.version = pool.properties[10]; - - //Upgrade available if a requested feature flag returns false - if (!pool.boot) { - for (var x in pool.feature) { - if (!pool.feature[x] && !pool.upgrade) { - pool.upgrade = true; - } - } - } - - $("#modals-storagepool-" + pool.id).remove(); - $("#modals").append(`
    `); - - pool.output = ` - - - - Name:` + pool.name + (pool.readonly ? ` ` : (pool.altroot ? ` ` : ``)) + ` - - Health:
    ` + pool.health + `
    - - - Size:
    ` + pool.size + `
    - - - Allocated:
    ` + pool.allocated + `
    - - - Free:
    ` + pool.free + `
    - - - Fragmentation:
    ` + pool.fragmentation + ` %
    - - - Usage: -
    -
    - ` + pool.allocatedpercent + `% Allocated -
    -
    - ` + pool.freepercent + `% Free -
    -
    - - - Upgrade Available: - ` + (pool.upgrade ? `Yes` : `No`) + ` - - - `; - - //Actions menu - pool.actionsmenu.items = { - itemconfigure: [], - itemconfiguredivider: function () { - if (this.itemconfigure.length > 0 && (this.itemconfigurefeatures.length > 0 || this.item.length > 0)) { - this.itemconfigure.push(this.divider); - } - }, - itemconfigurefeatures: [], - itemconfigurefeaturesdivider: function () { - if (this.itemconfigurefeatures.length > 0 && this.item.length > 0) { - this.itemconfigurefeatures.push(this.divider); - } - }, - item: [], - divider: `` - }; - pool.actionsmenu.display = function () { - if ((this.items.itemconfigure.length + this.items.itemconfigurefeatures.length + this.items.item.length) > 0) { - this.items.itemconfiguredivider(); - this.items.itemconfigurefeaturesdivider(); - - return this.header + this.items.itemconfigure.join("\n") + this.items.itemconfigurefeatures.join("\n") + this.items.item.join("\n") + this.footer; - } else { - return ""; - } - }; - pool.actionsmenu.header = ` - - `; - - //Configure Storage Pool - pool.actionsmenu.items.itemconfigure.push(`
  • Configure Storage Pool
  • `); - - //Configure Storage Pool Features - pool.actionsmenu.items.itemconfigurefeatures.push(`
  • Configure Storage Pool Features
  • `); - - //Export Storage Pool - if (!pool.boot && !pool.root) { - pool.actionsmenu.items.item.push(`
  • Export Storage Pool
  • `); - - pool.actionsmenu.register.export = true; - } - - //Destroy Storage Pool - if (!pool.readonly && !pool.boot && !pool.root) { - pool.actionsmenu.items.item.push(`
  • Destroy Storage Pool
  • `); - - pool.actionsmenu.register.destroy = true; - } - - pool.output += `` + pool.actionsmenu.display() + ``; - - if (zfsmanager.configuration.zfs.storagepool.activetab == 2) { - pool.activetab = "snapshots"; - } else if (zfsmanager.configuration.zfs.storagepool.activetab == 3) { - pool.activetab = "status"; - } - - pool.output += ` - - - - - -
    -
    -
    - - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - //Set active tab - $("#tab-storagepool-` + pool.activetab + `-` + pool.id + `").tab("show"); - - $("#btn-storagepool-filesystems-refresh-` + pool.id + `").on("click", function () { - $("#btn-storagepool-filesystems-create-` + pool.id + `").prop("disabled", true); - $("#btn-storagepool-filesystems-refresh-` + pool.id + `").prop("disabled", true); - - $("[id^=btn-storagepool-filesystem-dropdown-` + pool.id + `]").addClass("disabled"); - $("#paneltitle-storagepool-filesystems-` + pool.id + `").addClass("hidden"); - $("#spinner-storagepool-filesystems-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolRefresh({ name: "` + pool.name + `", id: "` + pool.id + `" }, { storagepool: true, filesystems: true, snapshots: false, status: false }); - }); - - $("#btn-storagepool-snapshots-refresh-` + pool.id + `").on("click", function () { - $("#btn-storagepool-snapshots-create-` + pool.id + `").prop("disabled", true); - $("#btn-storagepool-snapshots-refresh-` + pool.id + `").prop("disabled", true); - - $("[id^=btn-storagepool-snapshot-dropdown-` + pool.id + `]").addClass("disabled"); - $("#paneltitle-storagepool-snapshots-` + pool.id + `").addClass("hidden"); - $("#spinner-storagepool-snapshots-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolRefresh({ name: "` + pool.name + `", id: "` + pool.id + `" }, { storagepool: true, filesystems: false, snapshots: true, status: false }); - }); - - $("#btn-storagepool-status-refresh-` + pool.id + `").on("click", function () { - FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); - - $(this).text("Refresh").prop("disabled", true); - $("#btn-storagepool-status-refresh-auto-` + pool.id + `").prop("disabled", true).parent().removeClass("open");; - - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#paneltitle-storagepool-status-` + pool.id + `").addClass("hidden"); - $("#spinner-storagepool-status-` + pool.id + `").removeClass("hidden"); - $("#spinner-storagepool-status-0-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolRefresh({ name: "` + pool.name + `", id: "` + pool.id + `" }, { storagepool: true, filesystems: false, snapshots: false, status: true }); - }); - - $("#dropdown-storagepool-status-refresh-` + pool.id + `").on("click", "li a", function () { - FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); - $("#btn-storagepool-status-refresh-` + pool.id + `").click(); - - if ($(this).attr("data-pool-refresh-interval") > 0) { - let statusrefreshtimer` + _index + ` = setInterval(function () { - $("#btn-storagepool-status-refresh-` + pool.id + `").prop("disabled", true); - $("#btn-storagepool-status-refresh-auto-` + pool.id + `").prop("disabled", true).parent().removeClass("open"); - - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#paneltitle-storagepool-status-` + pool.id + `").addClass("hidden"); - $("#spinner-storagepool-status-` + pool.id + `").removeClass("hidden"); - $("#spinner-storagepool-status-0-` + pool.id + `").removeClass("hidden"); - - setTimeout(function() { - FnStoragePoolRefresh({ name: "` + pool.name + `", id: "` + pool.id + `" }, { storagepool: true, filesystems: false, snapshots: false, status: true }); - }, 200); - }, ($(this).attr("data-pool-refresh-interval") + "000")); - - zfsmanager.zfs.storagepool.refreshid.push(statusrefreshtimer` + _index + `); - - $("#tr-storagepool-` + pool.id + `").attr("data-pool-refresh-id", statusrefreshtimer` + _index + `); - $("#btn-storagepool-status-refresh-` + pool.id + `").text("Refresh: " + $(this).attr("data-pool-refresh-interval") + "s"); - - FnConsole.log[2]("Storage Pools, Refresh, Auto: Enabled, Pool: ` + pool.name + `"); - } - }); - \x3C/script> - - `; - - $("#table-storagepools").append(pool.output); - - $("#progressbar-storagepool-allocated-" + pool.id).css("width", pool.allocatedpercent + "%"); - $("#progressbar-storagepool-free-" + pool.id).css("width", pool.freepercent + "%"); - - //Register storage pool modals - FnModalStoragePoolConfigure({ name: pool.name, id: pool.id, boot: pool.boot, guid: pool.guid, readonly: false, root: pool.root }); - FnModalStoragePoolConfigureFeatures({ name: pool.name, id: pool.id, boot: pool.boot, readonly: false }); - if (pool.actionsmenu.register.destroy) { - FnModalStoragePoolDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot }); - } - if (pool.actionsmenu.register.export) { - FnModalStoragePoolExport({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }); - } - }); - - $("#btn-storagepools-refresh").prop("disabled", false); - - FnCockpitElementsUpdate(); -} - -function FnStoragePoolsImportableBlockDeviceGet(pools = { destroyed: false }) { - let process = { - command: ["/bin/sh", "-c", "/sbin/zpool import -d /dev" + (pools.destroyed ? " -D" : "") + " 2> /dev/null | /bin/grep -E 'pool:\| id:\|state:' | tr '\\\n' ','"] - }; - - FnConsole.log[2]("Storage Pools, Importable, Block Device, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnConsole.log[1]("Storage Pools, Importable, Block Device, Get: Success"); - }) - .fail(function (message, data) { - FnConsole.warn("Storage Pools, Importable, Block Device, Get: Failed, Message: " + (data ? data : message)); - }); -} - -function FnStoragePoolsImportableDiskGet(pools = { destroyed: false }) { - let process = { - command: ["/bin/sh", "-c", "/sbin/zpool import -d /dev/disk/by-id" + (pools.destroyed ? " -D" : "") + " 2> /dev/null | /bin/grep -E 'pool:\| id:\|state:' | tr '\\\n' ','"] - }; - - FnConsole.log[2]("Storage Pools, Importable, Disk / WWN, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnConsole.log[1]("Storage Pools, Importable, Disk / WWN, Get: Success"); - }) - .fail(function (message, data) { - FnConsole.warn("Storage Pools, Importable, Disk / WWN, Get: Failed, Message: " + (data ? data : message)); - }); -} - -function FnStoragePoolsImportableGet(pools = { destroyed: false }) { - let replacement = { - regexp: [ - { pattern: /^(?: )+pool\:/gi, replacement: "pool\:" }, - { pattern: /,(?: )+pool\:/gi, replacement: "\npool\:" }, - { pattern: /,$/g, replacement: "" }, - { pattern: /pool\: /gi, replacement: "" }, - { pattern: /id\: /gi, replacement: "" }, - { pattern: /state\: /gi, replacement: "" }, - { pattern: /,(?: )+/g, replacement: "," } - ] - }; - - pools.importable = { - blockdevice: [], - disk: [], - path: [], - vdev: [] - }; - - $("#listgroup-storagepools-import-storagepools").empty().append(`
  • `); - - FnConsole.log[2]("Storage Pools, Importable, Get: In Progress"); - - FnStoragePoolsImportableDiskGet({ destroyed: pools.destroyed }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Storage Pools, Importable, Disk / WWN, Get:" })); - - if (/no pools available to import/gi.test(data) == false) { - pools.importable.disk = replacement.regexp.reduce((d, r) => d.replace(r.pattern, r.replacement), data).split(/\n/g).filter(v => v); - } - - FnStoragePoolsImportableHardwarePathGet({ destroyed: pools.destroyed }) - .done(function (_data) { - FnConsole.log[4](FnConsoleVerbose({ data: _data, message: "Storage Pools, Importable, Hardware Path, Get:" })); - - if (/no pools available to import/gi.test(_data) == false) { - pools.importable.path = replacement.regexp.reduce((d, r) => d.replace(r.pattern, r.replacement), _data).split(/\n/g).filter(v => v); - } - - FnStoragePoolsImportableVirtualDeviceMappingGet({ destroyed: pools.destroyed }) - .done(function (__data) { - FnConsole.log[4](FnConsoleVerbose({ data: __data, message: "Storage Pools, Importable, Virtual Device Mapping, Get:" })); - - if (/no pools available to import/gi.test(__data) == false) { - pools.importable.vdev = replacement.regexp.reduce((d, r) => d.replace(r.pattern, r.replacement), __data).split(/\n/g).filter(v => v); - } - - FnStoragePoolsImportableBlockDeviceGet({ destroyed: pools.destroyed }) - .done(function (___data) { - FnConsole.log[4](FnConsoleVerbose({ data: ___data, message: "Storage Pools, Importable, Block Device, Get:" })); - - if (/no pools available to import/gi.test(___data) == false) { - pools.importable.blockdevice = replacement.regexp.reduce((d, r) => d.replace(r.pattern, r.replacement), ___data).split(/\n/g).filter(v => v); - - pools.importable.blockdevice.sort().forEach((_value, _index) => { - let pool = { - healthstatus: "", - properties: [], - id: { - blockdevice: true, - disk: false, - path: false, - vdev: false, - }, - idtext: ["Block Device"] - }; - - pool.properties = _value.split(/,/g).filter(v => v); - pool.name = pool.properties[0].trim(); - pool.guid = pool.properties[1].trim(); - pool.health = pool.properties[2].trim(); - - pools.importable.disk.filter(v => { if (v.match(pool.name) && !pool.id.disk) { pool.id.disk = true; pool.idtext.push("Disk / WWN"); } }); - pools.importable.path.filter(v => { if (v.match(pool.name) && !pool.id.path) { pool.id.path = true; pool.idtext.push("Hardware Path"); } }); - pools.importable.vdev.filter(v => { if (v.match(pool.name) && !pool.id.vdev) { pool.id.vdev = true; pool.idtext.push("Virtual Device Mapping"); } }); - - - if (/ONLINE/g.test(pool.health) == false) { - pool.healthstatus = ` `; - - $("#helpblock-storagepools-import-storagepools-warning").html("One or more storage pools are in an unhealthy state." + pool.healthstatus); - } - - pool.output = ` - - `; - - $("#listgroup-storagepools-import-storagepools").append(pool.output); - }); - } - - setTimeout(function () { - $("#spinner-storagepools-import-storagepools").remove(); - $("#listgroup-storagepools-import-storagepools > li").removeClass("hidden"); - if ($("#helpblock-storagepools-import-storagepools-warning").text()) { - $("#helpblock-storagepools-import-storagepools-warning").removeClass("hidden"); - } - - if ($("#listgroup-storagepools-import-storagepools > li").length == 0) { - pools.output = ` -
  • - -
  • - `; - - $("#listgroup-storagepools-import-storagepools").append(pools.output); - } - }, 200); - - FnConsole.log[1]("Storage Pools, Importable, Get: Success"); - }) - .fail(function (___message, ___data) { - if (/no pools available to import/gi.test(___data) == false) { - FnConsole.warn("Storage Pools, Importable, Get: Failed, Message: " + (___data ? ___data : ___message)); - } - - FnStoragePoolsImportableGetFail({ destroyed: pools.destroyed }); - }); - }) - .fail(function (__message, __data) { - if (/no pools available to import/gi.test(__data) == false) { - FnConsole.warn("Storage Pools, Importable, Get: Failed, Message: " + (__data ? __data : __message)); - } - - FnStoragePoolsImportableGetFail({ destroyed: pools.destroyed }); - }); - }) - .fail(function (_message, _data) { - if (/no pools available to import/gi.test(_data) == false) { - FnConsole.warn("Storage Pools, Importable, Get: Failed, Message: " + (_data ? _data : _message)); - } - - FnStoragePoolsImportableGetFail({ destroyed: pools.destroyed }); - }); - }) - .fail(function (message, data) { - if (/no pools available to import/gi.test(data) == false) { - FnConsole.warn("Storage Pools, Importable, Get: Failed, Message: " + (data ? data : message)); - } - - FnStoragePoolsImportableGetFail({ destroyed: pools.destroyed }); - }); -} - -function FnStoragePoolsImportableGetFail(pools = { destroyed: false }) { - setTimeout(function () { - $("#spinner-storagepools-import-storagepools").remove(); - $("#listgroup-storagepools-import-storagepools > li").removeClass("hidden"); - - if ($("#listgroup-storagepools-import-storagepools > li").length == 0) { - pools.output = ` -
  • - -
  • - `; - - $("#listgroup-storagepools-import-storagepools").append(pools.output); - } - }, 200); -} - -function FnStoragePoolsImportableHardwarePathGet(pools = { destroyed: false }) { - let process = { - command: ["/bin/sh", "-c", "/sbin/zpool import -d /dev/disk/by-path" + (pools.destroyed ? " -D" : "") + " 2> /dev/null | /bin/grep -E 'pool:\| id:\|state:' | tr '\\\n' ','"] - }; - - FnConsole.log[2]("Storage Pools, Importable, Hardware Path, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnConsole.log[1]("Storage Pools, Importable, Hardware Path, Get: Success"); - }) - .fail(function (message, data) { - FnConsole.warn("Storage Pools, Importable, Hardware Path, Get: Failed, Message: " + (data ? data : message)); - }); -} - -function FnStoragePoolsImportableVirtualDeviceMappingGet(pools = { destroyed: false }) { - let process = { - command: ["/bin/sh", "-c", "/sbin/zpool import -d /dev/disk/by-vdev" + (pools.destroyed ? " -D" : "") + " 2> /dev/null | /bin/grep -E 'pool:\| id:\|state:' | tr '\\\n' ','"] - }; - - FnConsole.log[2]("Storage Pools, Importable, Virtual Device Mapping, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnConsole.log[1]("Storage Pools, Importable, Virtual Device Mapping, Get: Success"); - }) - .fail(function (message, data) { - FnConsole.warn("Storage Pools, Importable, Virtual Device Mapping, Get: Failed, Message: " + (data ? data : message)); - }); -} - -function FnStoragePoolsSystemReservedGet() { - let filesystems = { - id: [] - }; - let process = { - command: ["/sbin/zfs", "list", "-H", "-o", "name,mountpoint", "-d", "3"] - }; - - FnConsole.log[2]("Storage Pools, System Reserved, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done((data) => { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Storage Pools, System Reserved, Get:" })); - - filesystems.id = data.split(/\n/g).filter(v => v); - - filesystems.id.forEach((_value, _index) => { - let filesystem = { - properties: _value.split(/\t/g).filter(v => v) - }; - - filesystem.name = filesystem.properties[0]; - filesystem.mountpoint = filesystem.properties[1].trim(); - - if (filesystem.mountpoint == "/boot" && !zfsmanager.zfs.storagepool.boot) { - zfsmanager.zfs.storagepool.boot = filesystem.name.split("/")[0]; - } else if (filesystem.mountpoint == "/" && !zfsmanager.zfs.storagepool.root) { - zfsmanager.zfs.storagepool.root = filesystem.name.split("/")[0]; - } - }); - - FnConsole.log[1]("Storage Pools, System Reserved, Get: Success"); - }) - .fail((message, data) => { - FnConsole.warn("Storage Pools, System Reserved, Get: Failed, Message: " + (data ? data : message)); - }); -} - -function FnStoragePoolsTemporaryGet() { - let process = { - command: ["/sbin/zpool", "list", "-H", "-o", "name,readonly,altroot"] - }; - - FnConsole.log[2]("Storage Pools, Temporary, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function () { - FnConsole.log[1]("Storage Pools, Temporary, Get: Success"); - }) - .fail(function (message, data) { - FnConsole.warn("Storage Pools, Temporary, Get: Failed, Message: " + (data ? data : message)); - }); -} - -//#endregion - -//#region Storage Pool - -function FnStoragePoolAlternativeRootGet(pool = { name, id }, modal = { name, id }) { - let process = { - command: ["/sbin/zpool", "list", "-H", "-o", "altroot", pool.name] - }; - - FnConsole.log[2]("Storage Pools, Alternative Root, Get: In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Storage Pools, Alternative Root, Get:" })); - - data = data.replace(/\n+/g, ""); - - $("#input-" + modal.name + "-mountpoint-" + modal.id).attr("data-field-altroot", data); - - FnConsole.log[1]("Storage Pools, Alternative Root, Get: Success, Pool: " + pool.name); - }) - .fail(function (message, data) { - FnConsole.warn("Storage Pools, Alternative Root, Get: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); - }); -} - -function FnStoragePoolClear(pool = { name, id }, modal = { name, id }) { - let process = { - command: ["/sbin/zpool", "clear", pool.name] - }; - - FnConsole.log[2]("Storage Pools, Clear Errors: In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-" + modal.name + "-" + modal.id + " span").text("Clearing storage pool errors..."); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "Storage Pool errors successfully cleared", description: pool.name, breakword: false }, { name: "storagepool-clear", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, Clear Errors: Success, Pool: " + pool.name); - }) - .fail(function (message, data) { - FnDisplayAlert({ status: "danger", title: "Storage Pool errors could not be cleared", description: pool.name, breakword: false }, { name: "storagepool-clear", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, Clear Errors: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); - }) - .finally(function () { - $("#modal-" + modal.name + "-" + modal.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); - }, 200); - }); -} - -function FnStoragePoolConfigurationFeaturesDisabledGet(pool = { name, id }, modal = { name, id }) { - let process = { - command: ["/sbin/zpool", "get", "feature@allocation_classes,feature@async_destroy,feature@bookmark_v2,feature@bookmarks,feature@device_removal,feature@edonr,feature@embedded_data,feature@empty_bpobj,feature@enabled_txg,feature@encryption,feature@extensible_dataset,feature@filesystem_limits,feature@hole_birth,feature@large_blocks,feature@large_dnode,feature@lz4_compress,feature@multi_vdev_crash_dump,feature@obsolete_counts,feature@project_quota,feature@resilver_defer,feature@sha512,feature@skein,feature@spacemap_histogram,feature@spacemap_v2,feature@userobj_accounting,feature@zpool_checkpoint", "-H", "-o", "property,value", pool.name] - }; - - FnConsole.log[2]("Storage Pools, Configuration, Features, Disabled, Get: In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Storage Pools, Configuration, Features, Disabled, Get:" })); - - pool.configuration = data.replace(/\t+/g, "\u22C5").split(/\n/g).filter(v => v); - pool.disabled = []; - - pool.configuration.forEach((_value, _index) => { - _value = _value.split("\u22C5"); - - pool.properties = { - property: _value[0].toLowerCase(), - value: _value[1].toLowerCase() - }; - - switch (pool.properties.property) { - case "feature@allocation_classes": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("Allocation Classes"); - } - break; - case "feature@async_destroy": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("Asynchronous Destroy"); - } - break; - case "feature@bookmark_v2": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("Bookmarks Version 2"); - } - break; - case "feature@bookmarks": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("Bookmarks"); - } - break; - case "feature@device_removal": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("Device Removal"); - } - break; - case "feature@edonr": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("Edon-R"); - } - break; - case "feature@embedded_data": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("Embedded Data"); - } - break; - case "feature@empty_bpobj": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("Empty Block Pointer Objects"); - } - break; - case "feature@enabled_txg": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("Transaction Group Accounting"); - } - break; - case "feature@encryption": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("Encryption"); - } - break; - case "feature@extensible_dataset": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("Extensible Dataset"); - } - break; - case "feature@filesystem_limits": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("File System Limits"); - } - break; - case "feature@hole_birth": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("Hole Birth"); - } - break; - case "feature@large_blocks": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("Large Blocks"); - } - break; - case "feature@large_dnode": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("Large DNode"); - } - break; - case "feature@lz4_compress": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("LZ4 Compression"); - } - break; - case "feature@multi_vdev_crash_dump": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("Multi Virtual Device Crash Dump"); - } - break; - case "feature@obsolete_counts": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("Obsolete Counts"); - } - break; - case "feature@project_quota": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("Project Quota"); - } - break; - case "feature@resilver_defer": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("Resilver Defer"); - } - break; - case "feature@sha512": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("SHA-512"); - } - break; - case "feature@skein": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("Skein"); - } - break; - case "feature@spacemap_histogram": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("Space Map Histogram"); - } - break; - case "feature@spacemap_v2": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("Space Map Version 2"); - } - break; - case "feature@userobj_accounting": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("User Object Accounting"); - } - break; - case "feature@zpool_checkpoint": - if (/disabled/gi.test(pool.properties.value)) { - pool.disabled.push("Checkpoint"); - } - break; - } - }); - - $("#ul-" + modal.name + "-features-" + modal.id).append(`
  • ` + pool.disabled.sort().join(`
  • \n
  • `) + `
  • `); - - FnConsole.log[1]("Storage Pools, Configuration, Features, Disabled, Get: Success, Pool: " + pool.name); - - }) - .fail(function (message, data) { - FnConsole.warn("Storage Pools, Configuration, Features, Disabled, Get: In Progress, Pool: " + pool.name + " , Message: " + (data ? data : message)); - }); -} - -function FnStoragePoolConfigurationFeaturesGet(pool = { name, id, boot: false }, modal = { name, id }) { - let process = { - command: ["/sbin/zpool", "get", "readonly,feature@allocation_classes,feature@async_destroy,feature@bookmark_v2,feature@bookmarks,feature@device_removal,feature@edonr,feature@embedded_data,feature@empty_bpobj,feature@enabled_txg,feature@encryption,feature@extensible_dataset,feature@filesystem_limits,feature@hole_birth,feature@large_blocks,feature@large_dnode,feature@lz4_compress,feature@multi_vdev_crash_dump,feature@obsolete_counts,feature@project_quota,feature@resilver_defer,feature@sha512,feature@skein,feature@spacemap_histogram,feature@spacemap_v2,feature@userobj_accounting,feature@zpool_checkpoint", "-H", "-o", "property,value", pool.name] - }; - - pool.readonly = false; - - FnConsole.log[2]("Storage Pools, Configuration, Features, Get: In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Storage Pools, Configuration, Features, Get:" })); - - pool.configuration = data.replace(/\t+/g, "\u22C5").split(/\n/g).filter(v => v); - - pool.configuration.forEach((_value, _index) => { - _value = _value.split("\u22C5"); - - pool.properties = { - property: _value[0].toLowerCase(), - value: _value[1].toLowerCase() - }; - - switch (pool.properties.property) { - case "feature@allocation_classes": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-allocation_classes-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-allocation_classes-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-allocation_classes-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-allocation_classes-" + modal.id + " input").prop("disabled", true); - } - break; - case "feature@async_destroy": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-async_destroy-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-async_destroy-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-async_destroy-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-async_destroy-" + modal.id + " input").prop("disabled", true); - } - break; - case "feature@bookmark_v2": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-bookmark_v2-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-bookmark_v2-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-bookmark_v2-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-bookmark_v2-" + modal.id + " input").prop("disabled", true); - } - break; - case "feature@bookmarks": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-bookmarks-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-bookmarks-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-bookmarks-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-bookmarks-" + modal.id + " input").prop("disabled", true); - } - break; - case "feature@device_removal": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-device_removal-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-device_removal-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-device_removal-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-device_removal-" + modal.id + " input").prop("disabled", true); - } - break; - case "feature@edonr": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-edonr-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-edonr-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-edonr-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-edonr-" + modal.id + " input").prop("disabled", true); - } - break; - case "feature@embedded_data": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-embedded_data-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-embedded_data-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-embedded_data-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-embedded_data-" + modal.id + " input").prop("disabled", true); - } - break; - case "feature@empty_bpobj": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-empty_bpobj-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-empty_bpobj-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-empty_bpobj-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-empty_bpobj-" + modal.id + " input").prop("disabled", true); - } - break; - case "feature@enabled_txg": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-enabled_txg-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-enabled_txg-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-enabled_txg-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-enabled_txg-" + modal.id + " input").prop("disabled", true); - } - break; - case "feature@encryption": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-encryption-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-encryption-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-encryption-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-encryption-" + modal.id + " input").prop("disabled", true); - } - break; - case "feature@extensible_dataset": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-extensible_dataset-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-extensible_dataset-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-extensible_dataset-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-extensible_dataset-" + modal.id + " input").prop("disabled", true); - } - break; - case "feature@filesystem_limits": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-filesystem_limits-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-filesystem_limits-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-filesystem_limits-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-filesystem_limits-" + modal.id + " input").prop("disabled", true); - } - break; - case "feature@hole_birth": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-hole_birth-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-hole_birth-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-hole_birth-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-hole_birth-" + modal.id + " input").prop("disabled", true); - } - break; - case "feature@large_blocks": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-large_blocks-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-large_blocks-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-large_blocks-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-large_blocks-" + modal.id + " input").prop("disabled", true); - } - break; - case "feature@large_dnode": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-large_dnode-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-large_dnode-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-large_dnode-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-large_dnode-" + modal.id + " input").prop("disabled", true); - } - break; - case "feature@lz4_compress": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-lz4_compress-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-lz4_compress-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-lz4_compress-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-lz4_compress-" + modal.id + " input").prop("disabled", true); - } - break; - case "feature@multi_vdev_crash_dump": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-multi_vdev_crash_dump-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-multi_vdev_crash_dump-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-multi_vdev_crash_dump-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-multi_vdev_crash_dump-" + modal.id + " input").prop("disabled", true); - } - break; - case "feature@obsolete_counts": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-obsolete_counts-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-obsolete_counts-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-obsolete_counts-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-obsolete_counts-" + modal.id + " input").prop("disabled", true); - } - break; - case "feature@project_quota": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-project_quota-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-project_quota-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-project_quota-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-project_quota-" + modal.id + " input").prop("disabled", true); - } - break; - case "feature@resilver_defer": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-resilver_defer-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-resilver_defer-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-resilver_defer-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-resilver_defer-" + modal.id + " input").prop("disabled", true); - } - break; - case "feature@sha512": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-sha512-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-sha512-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-sha512-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-sha512-" + modal.id + " input").prop("disabled", true); - } - break; - case "feature@skein": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-skein-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-skein-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-skein-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-skein-" + modal.id + " input").prop("disabled", true); - } - break; - case "feature@spacemap_histogram": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-spacemap_histogram-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-spacemap_histogram-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-spacemap_histogram-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-spacemap_histogram-" + modal.id + " input").prop("disabled", true); - } - break; - case "feature@spacemap_v2": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-spacemap_v2-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-spacemap_v2-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-spacemap_v2-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-spacemap_v2-" + modal.id + " input").prop("disabled", true); - } - break; - case "feature@userobj_accounting": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-userobj_accounting-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-userobj_accounting-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-userobj_accounting-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-userobj_accounting-" + modal.id + " input").prop("disabled", true); - } - break; - case "feature@zpool_checkpoint": - if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-zpool_checkpoint-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-zpool_checkpoint-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-zpool_checkpoint-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { - $("#switch-" + modal.name + "-zpool_checkpoint-" + modal.id + " input").prop("disabled", true); - } - break; - case "readonly": //Default is off - if (pool.properties.value == "on" || pool.boot && zfsmanager.configuration.zfs.storagepool.bootlockdown || !zfsmanager.user.admin) { - pool.readonly = true; - } - break; - } - }); - - if (pool.readonly) { - $("#btn-" + modal.name + "-apply-" + modal.id).prop("disabled", true); - } - - FnConsole.log[1]("Storage Pools, Configuration, Features, Get: Success, Pool: " + pool.name); - }) - .fail(function (message, data) { - FnConsole.warn("Storage Pools, Configuration, Features, Get: Failed, Pool: " + pool.name + " , Message: " + (data ? data : message)); - }); -} - -function FnStoragePoolConfigurationGet(pool = { name, id, boot: false, root: false }, modal = { name, id }) { - let process = { - command: ["/sbin/zpool", "get", "readonly,altroot,ashift,autoexpand,autoreplace,autotrim,bootfs,cachefile,comment,delegation,failmode,guid,listsnapshots,multihost,version", "-H", "-o", "property,value", pool.name] - }; - - pool.readonly = false; - - FnConsole.log[2]("Storage Pools, Configuration, Get: In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Storage Pools, Configuration, Get:" })); - - pool.configuration = data.replace(/\t+/g, "\u22C5").split(/\n/g).filter(v => v); - - pool.configuration.forEach((_value, _index) => { - _value = _value.split("\u22C5"); - - pool.properties = { - property: _value[0].toLowerCase(), - value: _value[1].toLowerCase(), - valueraw: _value[1], - }; - - switch (pool.properties.property) { - case "altroot": //Default is empty (-) - if (pool.properties.valueraw && pool.properties.valueraw == "-") { - pool.properties.valueraw = ""; - } - - if (pool.properties.valueraw) { - $("#controllabel-" + modal.name + "-altroot-" + modal.id).removeClass("hidden"); - $("#div-" + modal.name + "-altroot-" + modal.id).removeClass("hidden").text(pool.properties.valueraw); - } - break; - case "ashift": //Default is 0 - pool.property = { - value: "Auto Detect", - }; - - switch (pool.properties.value) { - case "0": - pool.property.value = "Auto Detect"; - break; - case "9": - pool.property.value = "512 B"; - break; - case "12": - pool.property.value = "4 KiB"; - break; - case "13": - pool.property.value = "8 KiB"; - break; - case "14": - pool.property.value = "16 KiB"; - break; - case "15": - pool.property.value = "32 KiB"; - break; - case "16": - pool.property.value = "64 KiB"; - break; - default: - pool.property.value = "Auto Detect"; - break; - } - - $("#btnspan-" + modal.name + "-ashift-" + modal.id).text(pool.property.value).attr("data-field-value", pool.properties.value); - $("#dropdown-" + modal.name + "-ashift-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-ashift-" + modal.id + " li[value='" + pool.properties.valueraw + "']").addClass("active"); - - if (pool.readonly) { - $("#div-" + modal.name + "-ashift-dropdown-" + modal.id + " button").prop("disabled", true); - } - break; - case "autoexpand": //Default is off - if (pool.properties.value == "on" && !$("#switch-" + modal.name + "-autoexpand-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-autoexpand-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-autoexpand-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly) { - $("#switch-" + modal.name + "-autoexpand-" + modal.id + " input").prop("disabled", true); - } - break; - case "autoreplace": //Default is off - if (pool.properties.value == "on" && !$("#switch-" + modal.name + "-autoreplace-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-autoreplace-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-autoreplace-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly) { - $("#switch-" + modal.name + "-autoreplace-" + modal.id + " input").prop("disabled", true); - } - break; - case "autotrim": //Default is off - if (pool.properties.value == "on" && !$("#switch-" + modal.name + "-autotrim-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-autotrim-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-autotrim-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly) { - $("#switch-" + modal.name + "-autotrim-" + modal.id + " input").prop("disabled", true); - } - break; - case "comment": //Default is empty (-) - if (pool.properties.valueraw && pool.properties.valueraw == "-") { - pool.properties.valueraw = ""; - } - - $("#input-" + modal.name + "-comment-" + modal.id).val(pool.properties.valueraw); - $("#input-" + modal.name + "-comment-" + modal.id).attr("data-field-value", pool.properties.valueraw); - - if (pool.readonly) { - $("#input-" + modal.name + "-comment-" + modal.id).prop("disabled", true); - } - - break; - case "delegation": //Default is on - if (pool.properties.value == "off" && $("#switch-" + modal.name + "-delegation-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-delegation-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-delegation-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly) { - $("#switch-" + modal.name + "-delegation-" + modal.id + " input").prop("disabled", true); - } - break; - case "failmode": //Default is wait - pool.property = { - value: pool.properties.value.charAt(0).toUpperCase() + pool.properties.value.slice(1), - }; - - $("#btnspan-" + modal.name + "-failmode-" + modal.id).text(pool.property.value).attr("data-field-value", pool.properties.value); - $("#dropdown-" + modal.name + "-failmode-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-failmode-" + modal.id + " li[value='" + pool.properties.valueraw + "']").addClass("active"); - - if (pool.readonly) { - $("#div-" + modal.name + "-failmode-dropdown-" + modal.id + " button").prop("disabled", true); - } - break; - case "guid": - $("#div-" + modal.name + "-guid-" + modal.id).html(pool.properties.value); - break; - case "listsnapshots": //Default is off - if (pool.properties.value == "on" && !$("#switch-" + modal.name + "-listsnapshots-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-listsnapshots-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-listsnapshots-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly) { - $("#switch-" + modal.name + "-listsnapshots-" + modal.id + " input").prop("disabled", true); - } - break; - case "multihost": //Default is off - if (pool.properties.value == "on" && !$("#switch-" + modal.name + "-multihost-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-multihost-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-multihost-" + modal.id).attr("data-field-value", pool.properties.value); - - if (pool.readonly || pool.boot || pool.root) { - $("#switch-" + modal.name + "-multihost-" + modal.id + " input").prop("disabled", true); - } - break; - case "readonly": //Default is off - if (pool.properties.value == "on" || pool.boot && zfsmanager.configuration.zfs.storagepool.bootlockdown || !zfsmanager.user.admin) { - pool.readonly = true; - } - - $("#div-" + modal.name + "-readonly-" + modal.id).html((pool.properties.value == "on" ? "Yes" : "No")); - break; - } - }); - - if (pool.readonly) { - $("#btn-" + modal.name + "-apply-" + modal.id).prop("disabled", true); - } - - FnConsole.log[1]("Storage Pools, Configuration, Get: Success, Pool: " + pool.name); - }) - .fail(function (message, data) { - FnConsole.warn("Storage Pools, Configuration, Get: Failed, Pool: " + pool.name + " , Message: " + (data ? data : message)); - }); -} - -function FnStoragePoolConfigure(pool = { name, id, ashift, autoexpand, autoreplace, autotrim, comment, delegation, failmode, listsnapshots, multihost, readonly: false }, system = { hostid }, modal = { id }) { - pool.properties = { - new: [] - }; - - if (pool.ashift) { - pool.properties.new.push("ashift=" + pool.ashift); - } - if (pool.autoexpand) { - pool.properties.new.push("autoexpand=" + pool.autoexpand); - } - if (pool.autoreplace) { - pool.properties.new.push("autoreplace=" + pool.autoreplace); - } - if (pool.autotrim) { - pool.properties.new.push("autotrim=" + pool.autotrim); - } - if (pool.comment) { - if (pool.comment == "$empty") { - pool.comment = ""; - } - - pool.properties.new.push("comment=" + pool.comment); - } - if (pool.delegation) { - pool.properties.new.push("delegation=" + pool.delegation); - } - if (pool.failmode) { - pool.properties.new.push("failmode=" + pool.failmode); - } - if (pool.listsnapshots) { - pool.properties.new.push("listsnapshots=" + pool.listsnapshots); - } - if (pool.multihost) { - pool.properties.new.push("multihost=" + pool.multihost); - } - - if (system.hostid) { - FnSystemHostIdSet({ hostid: (system.hostid == "random" ? null : "\$\(hostid\)") }) - .finally(function () { - if (pool.properties.new.length > 0 && !pool.readonly) { - FnConsole.log[2]("Storage Pools, Configure: In Progress, Pool: " + pool.name); - - $("#spinner-storagepool-configure-" + pool.id + " span").text("Configuring storage pool..."); - - FnStoragePoolConfigureCommand({ name: pool.name, id: pool.id, properties: { new: pool.properties.new } }, { id: modal.id }); - } else { - modal.id.modal("hide"); - } - }); - } else { - if (pool.properties.new.length > 0 && !pool.readonly) { - FnConsole.log[2]("Storage Pools, Configure: In Progress, Pool: " + pool.name); - - $("#spinner-storagepool-configure-" + pool.id + " span").text("Configuring storage pool..."); - - FnStoragePoolConfigureCommand({ name: pool.name, id: pool.id, properties: { new: pool.properties.new } }, { id: modal.id }); - } else { - modal.id.modal("hide"); - } - } -} - -function FnStoragePoolConfigureCommand(pool = { name, id, properties: { new: [] } }, modal = { id }) { - let promise = Promise.resolve(); - - pool.properties.errorcount = 0; - - pool.properties.new.forEach((_value, _index) => { - promise = promise.then(_ => new Promise(resolve => - setTimeout(function () { - let process = { - command: ["/sbin/zpool", "set", _value, pool.name] - }; - - FnConsole.log[2]("Storage Pools, Configure: In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - if (_index == (pool.properties.new.length - 1)) { - if (pool.properties.errorcount == 0) { - FnDisplayAlert({ status: "success", title: "Storge Pool successfully configured", description: pool.name, breakword: false }, { name: "storagepool-configure", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, Configure: Success, Pool: " + pool.name); - } else { - FnStoragePoolConfigureFail({ name: pool.name, id: pool.id }); - } - - modal.id.modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: false, status: false }); - }, 200); - } - }) - .fail(function (message, data) { - pool.properties.errorcount++; - - FnConsole.warn("Storage Pools, Property, Set: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); - - if (_index == (pool.properties.new.length - 1)) { - FnStoragePoolConfigureFail({ name: pool.name, id: pool.id }); - - modal.id.modal("hide"); - } - }); - - resolve(); - }, 500) - )); - }); -} - -function FnStoragePoolConfigureFail(pool = { name, id }) { - FnDisplayAlert({ status: "danger", title: "Storge Pool could not be configured", description: pool.name, breakword: false }, { name: "storagepool-configure", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, Configure: Failed, Pool: " + pool.name); -} - -function FnStoragePoolConfigureFeatures(pool = { name, id, feature: { allocation_classes, async_destroy, bookmark_v2, bookmarks, device_removal, edonr, embedded_data, empty_bpobj, enabled_txg, encryption, extensible_dataset, filesystem_limits, hole_birth, large_blocks, large_dnode, lz4_compress, multi_vdev_crash_dump, obsolete_counts, project_quota, resilver_defer, sha512, skein, spacemap_histogram, spacemap_v2, userobj_accounting, zpool_checkpoint }, readonly: false }, modal = { id }) { - pool.features = { - new: [] - }; - - if (pool.feature.allocation_classes) { - pool.features.new.push("feature@allocation_classes=" + pool.feature.allocation_classes); - } - if (pool.feature.async_destroy) { - pool.features.new.push("feature@async_destroy=" + pool.feature.async_destroy); - } - if (pool.feature.bookmark_v2) { - pool.features.new.push("feature@bookmark_v2=" + pool.feature.bookmark_v2); - } - if (pool.feature.bookmarks) { - pool.features.new.push("feature@bookmarks=" + pool.feature.bookmarks); - } - if (pool.feature.device_removal) { - pool.features.new.push("feature@device_removal=" + pool.feature.device_removal); - } - if (pool.feature.edonr) { - pool.features.new.push("feature@edonr=" + pool.feature.edonr); - } - if (pool.feature.embedded_data) { - pool.features.new.push("feature@embedded_data=" + pool.feature.embedded_data); - } - if (pool.feature.empty_bpobj) { - pool.features.new.push("feature@empty_bpobj=" + pool.feature.empty_bpobj); - } - if (pool.feature.enabled_txg) { - pool.features.new.push("feature@enabled_txg=" + pool.feature.enabled_txg); - } - if (pool.feature.encryption) { - pool.features.new.push("feature@encryption=" + pool.feature.encryption); - } - if (pool.feature.extensible_dataset) { - pool.features.new.push("feature@extensible_dataset=" + pool.feature.extensible_dataset); - } - if (pool.feature.filesystem_limits) { - pool.features.new.push("feature@filesystem_limits=" + pool.feature.filesystem_limits); - } - if (pool.feature.hole_birth) { - pool.features.new.push("feature@hole_birth=" + pool.feature.hole_birth); - } - if (pool.feature.large_blocks) { - pool.features.new.push("feature@large_blocks=" + pool.feature.large_blocks); - } - if (pool.feature.large_dnode) { - pool.features.new.push("feature@large_dnode=" + pool.feature.large_dnode); - } - if (pool.feature.lz4_compress) { - pool.features.new.push("feature@lz4_compress=" + pool.feature.lz4_compress); - } - if (pool.feature.multi_vdev_crash_dump) { - pool.features.new.push("feature@multi_vdev_crash_dump=" + pool.feature.multi_vdev_crash_dump); - } - if (pool.feature.obsolete_counts) { - pool.features.new.push("feature@obsolete_counts=" + pool.feature.obsolete_counts); - } - if (pool.feature.project_quota) { - pool.features.new.push("feature@project_quota=" + pool.feature.project_quota); - } - if (pool.feature.resilver_defer) { - pool.features.new.push("feature@resilver_defer=" + pool.feature.resilver_defer); - } - if (pool.feature.sha512) { - pool.features.new.push("feature@sha512=" + pool.feature.sha512); - } - if (pool.feature.skein) { - pool.features.new.push("feature@skein=" + pool.feature.skein); - } - if (pool.feature.spacemap_histogram) { - pool.features.new.push("feature@spacemap_histogram=" + pool.feature.spacemap_histogram); - } - if (pool.feature.spacemap_v2) { - pool.features.new.push("feature@spacemap_v2=" + pool.feature.spacemap_v2); - } - if (pool.feature.userobj_accounting) { - pool.features.new.push("feature@userobj_accounting=" + pool.feature.userobj_accounting); - } - if (pool.feature.zpool_checkpoint) { - pool.features.new.push("feature@zpool_checkpoint=" + pool.feature.zpool_checkpoint); - } - - if (pool.features.new.length > 0 && !pool.readonly) { - FnConsole.log[2]("Storage Pools, Configure, Features: In Progress, Pool: " + pool.name); - - $("#spinner-storagepool-configure-features-" + pool.id + " span").text("Configuring storage pool features..."); - - FnStoragePoolConfigureFeaturesCommand({ name: pool.name, id: pool.id, features: { new: pool.features.new } }, { id: modal.id }); - } else { - modal.id.modal("hide"); - } -} - -function FnStoragePoolConfigureFeaturesCommand(pool = { name, id, features: { new: [] } }, modal = { id }) { - let promise = Promise.resolve(); - - pool.features.errorcount = 0; - - pool.features.new.forEach((_value, _index) => { - promise = promise.then(_ => new Promise(resolve => - setTimeout(function () { - let process = { - command: ["/sbin/zpool", "set", _value, pool.name] - }; - - FnConsole.log[2]("Storage Pools, Configure, Features: In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - if (_index == (pool.features.new.length - 1)) { - if (pool.features.errorcount == 0) { - FnDisplayAlert({ status: "success", title: "Storge Pool features successfully configured", description: pool.name, breakword: false }, { name: "storagepool-configure-features", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, Configure, Features: Success, Pool: " + pool.name); - } else { - FnStoragePoolConfigureFeaturesFail({ name: pool.name, id: pool.id }); - } - - modal.id.modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: true }); - }, 200); - } - }) - .fail(function (message, data) { - pool.features.errorcount++; - - FnConsole.warn("Storage Pools, Feature, Set: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); - - if (_index == (pool.features.new.length - 1)) { - FnStoragePoolConfigureFeaturesFail({ name: pool.name, id: pool.id }); - - modal.id.modal("hide"); - } - }); - - resolve(); - }, 500) - )); - }); -} - -function FnStoragePoolConfigureFeaturesFail(pool = { name, id }) { - FnDisplayAlert({ status: "danger", title: "Storge Pool features could not be configured", description: pool.name, breakword: false }, { name: "storagepool-configure-features", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, Configure, Features: Failed, Pool: " + pool.name); -} - -function FnStoragePoolCreate(pool = { name, ashift, autoexpand, autoreplace, autotrim, force, virtualdevice }, filesystem = { compression, dedup, recordsize, refreservationpercent, selinux }, disks = { id: [] }) { - let process = { - command: ["/sbin/zpool", "create", "-o", "ashift=" + pool.ashift, "-o", "autoexpand=" + pool.autoexpand, "-o", "autoreplace=" + pool.autoreplace, "-o", "autotrim=" + pool.autotrim, "-O", "aclinherit=passthrough", "-O", "acltype=posixacl", "-O", "casesensitivity=sensitive", "-O", "compression=" + filesystem.compression, "-O", "normalization=formD", "-O", "recordsize=" + filesystem.recordsize, "-O", "sharenfs=off", "-O", "sharesmb=off", "-O", "utf8only=on", "-O", "xattr=sa", pool.name] - }; - let modal = { - hide: true - }; - - if (filesystem.selinux) { - process.command.splice((process.command.length - 1), 0, "-O"); - process.command.splice((process.command.length - 1), 0, "context=system_u:object_r:samba_share_t:s0"); - process.command.splice((process.command.length - 1), 0, "-O"); - process.command.splice((process.command.length - 1), 0, "fscontext=system_u:object_r:samba_share_t:s0"); - process.command.splice((process.command.length - 1), 0, "-O"); - process.command.splice((process.command.length - 1), 0, "defcontext=system_u:object_r:samba_share_t:s0"); - process.command.splice((process.command.length - 1), 0, "-O"); - process.command.splice((process.command.length - 1), 0, "rootcontext=system_u:object_r:samba_share_t:s0"); - } - if (filesystem.dedup) { - process.command.splice((process.command.length - 1), 0, "-O"); - process.command.splice((process.command.length - 1), 0, "dedup=" + filesystem.dedup); - } - if (pool.force) { - process.command.splice(2, 0, "-f"); - } - if (pool.virtualdevice) { - process.command.push(pool.virtualdevice); - } - - disks.id.forEach(_value => _value && process.command.push(_value)); - - pool.id = FnGenerateId({ at: false, colon: true, forwardslash: false, period: true, underscore: true, whitespace: true }, { name: pool.name, attribute: true }); - - FnConsole.log[1]("Storage Pools, Create: In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-storagepools-create span").text("Creating storage pool..."); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "Storage Pool successfully created", description: pool.name, breakword: false }, { name: "storagepool-create", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, Create: Success, Pool: " + pool.name); - - if (filesystem.refreservationpercent > 0) { - FnStoragePoolSizeGet({ name: pool.name, id: null }) - .done(function (_data) { - FnConsole.log[4](FnConsoleVerbose({ data: _data, message: "Storage Pools, Size, Get:" })); - - if (_data) { - _data = _data.replace(/\n+/g, ""); - - filesystem.refreservation = ((_data / 100) * filesystem.refreservationpercent); - - FnStoragePoolRefreservationSet({ name: pool.name, id: null }, { refreservation: filesystem.refreservation }); - } - }); - } - }) - .fail(function (message, data) { - if (/pool already exists/gi.test(data)) { - modal.hide = false; - - $("#validationwrapper-storagepools-create-name").addClass("has-error"); - $("#helpblock-storagepools-create-name").addClass("has-error").removeClass("hidden").text("Name already exists."); - $("#input-storagepools-create-name").focus(); - } else if (/contains devices of different sizes/gi.test(data)) { - modal.hide = false; - - $("#validationwrapper-storagepools-create-disks").addClass("has-error"); - $("#helpblock-storagepools-create-disks").addClass("has-error").removeClass("hidden").text("Disks are of different sizes. Forcefully create storage pool to override."); - } else { - FnDisplayAlert({ status: "danger", title: "Storage Pool could not be created", description: pool.name, breakword: false }, { name: "storagepool-create", id: pool.id, timeout: 4 }); - } - - FnConsole.warn("Storage Pools, Create: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); - - if (!modal.hide) { - $("#spinner-storagepools-create").addClass("hidden"); - $("#spinner-storagepools-create span").text(""); - $("#btn-storagepools-create-apply").prop("disabled", false); - } - }) - .finally(function () { - if (modal.hide) { - $("#modal-storagepools-create").modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 200); - } - }); -} - -function FnStoragePoolDestroy(pool = { name, id, altroot: false, force: false, labelclear: false }, samba = { restart: false }) { - let disks = { - attached: [] - }; - - pool.attached = []; - pool.attachedconfig = []; - - if (pool.labelclear) { - FnDisksStoragePoolsAttachedGet({ name: pool.name, id: pool.id }, { id: { blockdevice: true } }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Disks, Storage Pools, Attached, Get:" })); - - pool.attached = data.replace(/\n\t+/g, "[TAB1]").split(/\n/g).filter(v => v); - - pool.attached.forEach((_value, _index) => { - if (/\[TAB1\]NAME/g.test(_value)) { //Config header row - _value = _value.split("upath").slice(1).join("."); //Remove config header row (and any previous text if exists) +}; - if (new RegExp("^\\[TAB1\\]" + pool.name).test(_value)) { //Confirm config rows - _value.split("[TAB1]").filter(v => v && pool.attachedconfig.push(v)); - } - } - }); - - pool.attachedconfig.forEach((_value, _index) => { - let config = { - disk: { - upath: "" - }, - tier: { - level: (_value.match(/^\s*/g)[0].length / 2) - } - }; +//#endregion - _value = _value.replace(/ +/g, "\u22C5").replace(/^\u22C5/, "").split("\u22C5").filter(v => v); +//#region Document Ready - if (/^\/dev\/nvme|^\/dev\/sd/gi.test(_value[5])) { //upath - config.disk.upath = _value[5]; - } else if (!$.isNumeric(_value[0]) && _value[5] != "was") { //upath appears after error messages and before trim messages - for (let i = 5; i < _value.length; i++) { - if (/^\/dev\/nvme|^\/dev\/sd/gi.test(_value[i])) { - config.disk.upath = _value[i]; - } - } - } +$(document).ready(function () { + FnConsoleInitialize(); - if (config.tier.level > 0) { - if (/^\/dev\/nvme|^\/dev\/sd/gi.test(config.disk.upath)) { //Block Device via upath - disks.attached.push(config.disk.upath.replace(/^\/dev\//gi, "")); - } else if (/^\/dev\/nvme|^\/dev\/sd/gi.test(_value[0])) { //Block Device - if (/^\/dev\/nvme\d+n\d+p\d+$/gi.test(_value[0])) { - disks.attached.push(_value[0].replace(/^\/dev\//gi, "").replace(/p\d+$/, "")); - } else if (/^\/dev\/sd.*\d+$/gi.test(_value[0])) { - disks.attached.push(_value[0].replace(/^\/dev\//gi, "").replace(/\d+$/, "")); - } else { - disks.attached.push(_value[0]); - } - } else if (/^nvme-nvme/gi.test(_value[0]) || /^wwn-/gi.test(_value[0])) { //WWN - if (/^nvme-nvme.*-part\d+$/gi.test(_value[0])) { - disks.attached.push(_value[0].replace(/-part\d+$/, "")); - } else if (/^wwn-.*-part\d+$/gi.test(_value[0])) { - disks.attached.push(_value[0].replace(/-part\d+$/, "")); - } else { - disks.attached.push(_value[0]); - } - } - } - }); + FnConsole.log[1]("Cockpit ZFS Manager, Version: " + zfsmanager.version); - disks.attached.sort(); - }); - } - - if (samba.restart) { - FnSambaStop() - .finally(function () { - if (zfsmanager.configuration.samba.manage) { - $("#spinner-storagepool-destroy-" + pool.id + " span").text("Retrieving Samba shares..."); - - FnSambaSharesGet({ name: pool.name, id: pool.id }, { name: null, clones: [] }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Shares, Get:" })); - - let filesystems = { - id: data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) - }; - - $("#spinner-storagepool-destroy-" + pool.id + " span").text("Destroying storage pool..."); - - if (filesystems.id.length > 0) { - FnStoragePoolDestroyCommand({ name: pool.name, id: pool.id, force: pool.force }) - .done(function () { - $("#spinner-storagepool-destroy-" + pool.id + " span").text("Destroying Samba shares..."); - - FnSambaSharesDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { id: filesystems.id }, { restart: samba.restart }, { silent: false }) - .finally(function () { - if (pool.labelclear) { - $("#spinner-storagepool-destroy-" + pool.id + " span").text("Clearing disk labels..."); - - FnStoragePoolDestroyLabelClear({ name: pool.name, id: pool.id }, { id: disks.attached }) - .finally(function () { - $("#modal-storagepool-destroy-" + pool.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 200); - }); - } else { - $("#modal-storagepool-destroy-" + pool.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 200); - } - }) - }); - } else { - FnStoragePoolDestroyCommand({ name: pool.name, id: pool.id, force: pool.force }) - .done(function () { - if (pool.labelclear) { - $("#spinner-storagepool-destroy-" + pool.id + " span").text("Clearing disk labels..."); - - FnStoragePoolDestroyLabelClear({ name: pool.name, id: pool.id }, { id: disks.attached }) - .finally(function () { - $("#modal-storagepool-destroy-" + pool.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 200); - }); - } else { - $("#modal-storagepool-destroy-" + pool.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 200); - } - }) - .finally(function () { - FnSambaStart(); - }); - } - }) - .fail(function (message, data) { - FnStoragePoolDestroyFail({ name: pool.name, id: pool.id }, { data: data, message: message }); - FnSambaStart(); - }); - } else { - FnStoragePoolDestroyCommand({ name: pool.name, id: pool.id, force: pool.force }) - .done(function () { - if (pool.labelclear) { - $("#spinner-storagepool-destroy-" + pool.id + " span").text("Clearing disk labels..."); - - FnStoragePoolDestroyLabelClear({ name: pool.name, id: pool.id }, { id: disks.attached }) - .finally(function () { - $("#modal-storagepool-destroy-" + pool.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 200); - }); - } else { - $("#modal-storagepool-destroy-" + pool.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 200); - } - }) - .finally(function () { - FnSambaStart(); - }); - } - }); - } else { - if (zfsmanager.configuration.samba.manage) { - $("#spinner-storagepool-destroy-" + pool.id + " span").text("Retrieving Samba shares..."); - - FnSambaSharesGet({ name: pool.name, id: pool.id }, { name: null, clones: [] }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Shares, Get:" })); - - let filesystems = { - id: data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) - }; - - $("#spinner-storagepool-destroy-" + pool.id + " span").text("Destroying storage pool..."); - - if (filesystems.id.length > 0) { - FnStoragePoolDestroyCommand({ name: pool.name, id: pool.id, force: pool.force }) - .done(function () { - $("#spinner-storagepool-destroy-" + pool.id + " span").text("Destroying Samba shares..."); - - FnSambaSharesDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { id: filesystems.id }, { restart: samba.restart }, { silent: false }) - .finally(function () { - if (pool.labelclear) { - $("#spinner-storagepool-destroy-" + pool.id + " span").text("Clearing disk labels..."); - - FnStoragePoolDestroyLabelClear({ name: pool.name, id: pool.id }, { id: disks.attached }) - .finally(function () { - $("#modal-storagepool-destroy-" + pool.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 200); - }); - } else { - $("#modal-storagepool-destroy-" + pool.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 200); - } - }) - }); - } else { - FnStoragePoolDestroyCommand({ name: pool.name, id: pool.id, force: pool.force }) - .done(function () { - if (pool.labelclear) { - $("#spinner-storagepool-destroy-" + pool.id + " span").text("Clearing disk labels..."); - - FnStoragePoolDestroyLabelClear({ name: pool.name, id: pool.id }, { id: disks.attached }) - .finally(function () { - $("#modal-storagepool-destroy-" + pool.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 200); - }); - } else { - $("#modal-storagepool-destroy-" + pool.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 200); - } - }); - } - }) - .fail(function (message, data) { - FnStoragePoolDestroyFail({ name: pool.name, id: pool.id }, { data: data, message: message }); - }); - } else { - FnStoragePoolDestroyCommand({ name: pool.name, id: pool.id, force: pool.force }) - .done(function () { - if (pool.labelclear) { - $("#spinner-storagepool-destroy-" + pool.id + " span").text("Clearing disk labels..."); - - FnStoragePoolDestroyLabelClear({ name: pool.name, id: pool.id }, { id: disks.attached }) - .finally(function () { - $("#modal-storagepool-destroy-" + pool.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 200); - }); - } else { - $("#modal-storagepool-destroy-" + pool.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 200); - } - }); - } - } -} - -function FnStoragePoolDestroyCommand(pool = { name, id, force: false }) { - let process = { - command: ["/sbin/zpool", "destroy", pool.name] - }; - - if (pool.force) { - process.command.splice(2, 0, "-f"); - } - - FnConsole.log[1]("Storage Pools, Destroy: In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "Storage Pool successfully destroyed", description: pool.name, breakword: false }, { name: "storagepool-destroy", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, Destroy: Success, Pool: " + pool.name); - }) - .fail(function (message, data) { - FnStoragePoolDestroyFail({ name: pool.name, id: pool.id }, { data: data, message: message }); - }); -} - -function FnStoragePoolDestroyFail(pool = { name, id }, process = { data, message }) { - FnDisplayAlert({ status: "danger", title: "Storage Pool could not be destroyed", description: pool.name, breakword: false }, { name: "storagepool-destroy", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, Destroy: Failed, Pool: " + pool.name + ", Message: " + (process.data ? process.data : process.message)); - - $("#modal-storagepool-destroy-" + pool.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 200); -} - -function FnStoragePoolDestroyLabelClear(pool = { name, id }, disks = { id: [] }) { - let process = { - promise: cockpit.defer() - }; - let promise = Promise.resolve(); - - disks.clear = { - error: 0 - }; - - FnConsole.log[2]("Storage Pools, Disk Labels, Clear: In Progress"); - - if (disks.id.length > 0) { - disks.id.forEach((_value, _index) => { - promise = promise.then(_ => new Promise(resolve => - setTimeout(function () { - FnStoragePoolDiskLabelClear({ name: pool.name, id: pool.id }, { id: _value, inactive: true }, { silent: true }) - .fail(function () { - disks.clear.error++; - }); - - if (_index == (disks.id.length - 1)) { - setTimeout(function () { - if (disks.clear.error == 0) { - FnDisplayAlert({ status: "success", title: "Storage Pool disk labels successfully cleared", description: pool.name, breakword: false }, { name: "storagepool-destroy-labelclear", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, Disk Labels, Clear: Success"); - } else { - FnDisplayAlert({ status: "danger", title: "Storage Pool disk labels could not be cleared", description: pool.name, breakword: false }, { name: "storagepool-destroy-labelclear", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, Disk Labels, Clear: Failed"); - } - - process.promise.resolve(); - }, 2000); - } - - resolve(); - }, 2000) - )); - }); - } else { - process.promise.resolve(); - } - - return process.promise.promise(); -} - -function FnStoragePoolDiskAttach(pool = { name, id, force: false }, virtualdevice = { id, disk: true }, disk = { idnew: [] }, modal = { name, id }) { - virtualdevice.mirror = { - start: null, - end: null - }; - - $("#spinner-" + modal.name + "-" + modal.id + " span").text("Attaching disk..."); - - if (!virtualdevice.disk && /^mirror-/.test(virtualdevice.id)) { - disk.id = ""; - - FnDisksStoragePoolsAttachedGet({ name: pool.name, id: pool.id }, { id: { blockdevice: false } }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Disks, Storage Pools, Attached, Get:" })); - - pool.attached = data.replace(/\n\t+/g, "[TAB1]").split(/\n/g).filter(v => v); - pool.attachedconfig = []; - - pool.attached.forEach((_value, _index) => { - if (/\[TAB1\]NAME/g.test(_value)) { //Config header row - _value = _value.split("upath").slice(1).join("."); //Remove config header row (and any previous text if exists) + FnConfigurationGet() + .always(function () { + Requirements({ zfs: false }); + }); - if (new RegExp("^\\[TAB1\\]" + pool.name).test(_value)) { //Confirm config rows - _value.split("[TAB1]").filter(v => v && pool.attachedconfig.push(v)); - } - } - }); - - pool.attachedconfig.forEach((_value, _index) => { //Find disks in Mirror virtual device and get hierarchy information - let config = { - tier: { - level: (_value.match(/^\s*/g)[0].length / 2) - } - }; + $("body").tooltip({ + html: "true", + selector: `[data-toggle="tooltip"]` + }); - _value = _value.replace(/ +/g, "\u22C5").replace(/^\u22C5/, "").split("\u22C5").filter(v => v); + $(cockpit.info).on("changed", function () { + zfsmanager.cockpit.legacy = (cockpit.info["version"] < 207 ? true : false); + }); +}); - virtualdevice.mirror.regexp = new RegExp(virtualdevice.id, "g"); - - if (config.tier.level == 1 && virtualdevice.mirror.regexp.test(_value[0])) { - if (!virtualdevice.mirror.start) { - virtualdevice.mirror.start = _index; - } - } - - if (virtualdevice.mirror.start && _index > virtualdevice.mirror.start) { - if (config.tier.level == 1) { - if (!virtualdevice.mirror.end) { - virtualdevice.mirror.end = _index; - } - } - } - }); +//#endregion - if (!virtualdevice.mirror.end) { - virtualdevice.mirror.end = pool.attachedconfig.length; +//#region Requirements + +function Requirements(skip = { zfs: false }) { + if (!skip.zfs) { + FnZfsVersionGet() + .done(function () { + if ($("#alerts-requirements").hasClass("hidden")) { + if (zfsmanager.configuration.samba.manage) { + FnSambaVersionGet() + .done(function () { + FnFirstSteps(); + }); + } else { + FnFirstSteps(); + } } + }); + } else { + if (zfsmanager.configuration.samba.manage) { + FnSambaVersionGet() + .done(function () { + FnFirstSteps(); + }); + } else { + FnFirstSteps(); + } + } +} - pool.attachedconfig.forEach((_value, _index) => { //Find first healthy disk in the mirror virtual device - let config = { - disk: { - upath: "" - }, - tier: { - level: (_value.match(/^\s*/g)[0].length / 2) - } - }; +//#endregion - _value = _value.replace(/ +/g, "\u22C5").replace(/^\u22C5/, "").split("\u22C5").filter(v => v); +//#region First Steps - if (/^\/dev\/nvme|^\/dev\/sd/gi.test(_value[5])) { //upath - config.disk.upath = _value[5]; - } else if (!$.isNumeric(_value[0]) && _value[5] != "was") { //upath appears after error messages and before trim messages - for (let i = 5; i < _value.length; i++) { - if (/^\/dev\/nvme|^\/dev\/sd/gi.test(_value[i])) { - config.disk.upath = _value[i]; - } - } - } +function FnFirstSteps() { + FnSystemOperatingSystemGet(); + FnCockpitPermissionsGet(); - if (config.tier.level == 2 && _index > virtualdevice.mirror.start && _index < virtualdevice.mirror.end && _value[1] == "ONLINE") { - if (/^\/dev\/nvme|^\/dev\/sd/gi.test(config.disk.upath) || /^\/dev\/nvme|^\/dev\/sd/gi.test(_value[0])) { //Block Device - if (/^\/dev\/nvme\d+n\d+p\d+$/gi.test(_value[0])) { - if (!disk.id) { - disk.id = _value[0].replace(/p\d+$/, ""); - } - } else if (/^\/dev\/sd.*\d+$/gi.test(_value[0])) { - if (!disk.id) { - disk.id = _value[0].replace(/\d+$/, ""); - } - } else { - if (!disk.id) { - disk.id = _value[0].replace(/-part\d+$/, ""); - } - } - } else if (/^nvme-nvme/gi.test(_value[0]) || /^wwn-/gi.test(_value[0])) { //WWN - if (!disk.id) { - disk.id = _value[0].replace(/-part\d+$/, ""); - } - } - } - }); - - if (!disk.id || /^mirror-/g.test(disk.id)) { - FnStoragePoolDiskAttachFail({ name: pool.name, id: pool.id }, { id: virtualdevice.id, disk: virtualdevice.disk }, { idnew: disk.idnew }, { name: modal.name, id: modal.id }, { data: null, message: "There are no healthy disks to attach to." }); - } else { - FnStoragePoolDiskAttachCommand({ name: pool.name, id: pool.id, force: pool.force }, { id: virtualdevice.id, disk: virtualdevice.disk }, { id: disk.id, idnew: disk.idnew }, { name: modal.name, id: modal.id }); - } - }) - .fail(function (message, data) { - FnStoragePoolDiskAttachFail({ name: pool.name, id: pool.id }, { id: virtualdevice.id, disk: virtualdevice.disk }, { idnew: disk.idnew }, { name: modal.name, id: modal.id }, { data: data, message: message }); - }); - } else { - FnStoragePoolDiskAttachCommand({ name: pool.name, id: pool.id, force: pool.force }, { id: virtualdevice.id, disk: virtualdevice.disk }, { id: virtualdevice.id, idnew: disk.idnew }, { name: modal.name, id: modal.id }); - } -} - -function FnStoragePoolDiskAttachCommand(pool = { name, id, force: false }, virtualdevice = { id, disk: true }, disk = { id, idnew }, modal = { name, id }) { - let process = { - command: ["/sbin/zpool", "attach", pool.name, disk.id, disk.idnew] - }; - - if (pool.force) { - process.command.splice(2, 0, "-f"); - } - - FnConsole.log[1]("Storage Pools, Disk, Attach: In Progress, Pool: " + pool.name + ", " + (!virtualdevice.disk ? "Virtual Device: " + virtualdevice.id + ", " : "") + "Disk: " + disk.idnew); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "Disk attached successfully to Storage Pool", description: pool.name, breakword: false }, { name: "storagepool-disk-attach", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, Disk, Attach: Success, Pool: " + pool.name + ", " + (!virtualdevice.disk ? "Virtual Device: " + virtualdevice.id + ", " : "") + "Disk: " + disk.idnew); - }) - .fail(function (message, data) { - FnDisplayAlert({ status: "danger", title: "Disk could not be attached to Storage Pool", description: pool.name, breakword: false }, { name: "storagepool-disk-attach", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, Disk, Attach: Failed, Pool: " + pool.name + ", " + (!virtualdevice.disk ? "Virtual Device: " + virtualdevice.id + ", " : "") + "Disk: " + disk.idnew + ", Message: " + (data ? data : message)); - }) - .finally(function () { - $("#modal-" + modal.name + "-" + modal.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); - }, 200); - });; -} - -function FnStoragePoolDiskAttachFail(pool = { name, id }, virtualdevice = { id, disk: true }, disk = { idnew }, modal = { name, id }, process = { data, message }) { - FnDisplayAlert({ status: "danger", title: "Disk could not be attached to Storage Pool", description: pool.name, breakword: false }, { name: "storagepool-disk-attach", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, Disk, Attach: Failed, Pool: " + pool.name + ", " + (!virtualdevice.disk ? "Virtual Device: " + virtualdevice.id + ", " : "") + "Disk: " + disk.idnew + ", Message: " + (process.data ? process.data : process.message)); - - if (modal.id) { - $("#modal-" + modal.name + "-" + modal.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); - }, 200); - } -} - -function FnStoragePoolDiskClear(pool = { name, id }, disk = { id }, modal = { name, id }) { - let process = { - command: ["/sbin/zpool", "clear", pool.name, disk.id] - }; - - FnConsole.log[2]("Storage Pools, Disk, Clear Errors: In Progress, Pool: " + pool.name + ", Disk: " + disk.id); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-" + modal.name + "-" + modal.id + " span").text("Clearing disk errors..."); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "Disk errors successfully cleared", description: disk.id, breakword: false }, { name: "storagepool-disk-clear", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, Disk, Clear Errors: Success, Pool: " + pool.name + ", Disk: " + disk.id); - }) - .fail(function (message, data) { - FnDisplayAlert({ status: "danger", title: "Disk errors could not be cleared", description: disk.id, breakword: false }, { name: "storagepool-disk-clear", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, Disk, Clear Errors: Failed, Pool: " + pool.name + ", Disk: " + disk.id + ", Message: " + (data ? data : message)); - }) - .finally(function () { - $("#modal-" + modal.name + "-" + modal.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); - }, 200); - }); -} - -function FnStoragePoolDiskDetach(pool = { name, id }, disk = { id, labelclear: false }, modal = { name, id }) { - let process = { - command: ["/sbin/zpool", "detach", pool.name, disk.id] - }; - - modal.hide = true; - - FnConsole.log[1]("Storage Pools, Disk, Detach: In Progress, Pool: " + pool.name + ", Disk: " + disk.id); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-" + modal.name + "-" + modal.id + " span").text("Detaching disk..."); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "Disk detached successfully from Storage Pool", description: pool.name, breakword: false }, { name: "storagepool-disk-detach", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, Disk, Detach: Success, Pool: " + pool.name + ", Disk: " + disk.id); - - if (disk.labelclear) { - modal.hide = false; - - $("#spinner-" + modal.name + "-" + modal.id + " span").text("Clearing disk label..."); - - setTimeout(function () { - FnStoragePoolDiskLabelClear({ name: pool.name, id: pool.id }, { id: disk.id, inactive: false }, { silent: false }) - .finally(function () { - $("#modal-" + modal.name + "-" + modal.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); - }, 200); - }) - }, 2000); - } - }) - .fail(function (message, data) { - FnDisplayAlert({ status: "danger", title: "Disk could not be detached from Storage Pool", description: pool.name, breakword: false }, { name: "storagepool-disk-detach", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, Disk, Detach: Failed, Pool: " + pool.name + ", Disk: " + disk.id + ", Message: " + (data ? data : message)); - }) - .finally(function () { - if (modal.hide) { - $("#modal-" + modal.name + "-" + modal.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); - }, 200); - } - });; -} - -function FnStoragePoolDiskLabelClear(pool = { name, id }, disk = { id, inactive: false }, display = { silent: false }) { - let process = { - command: ["/sbin/zpool", "labelclear", disk.id] - }; - - if (disk.inactive) { - process.command.splice(2, 0, "-f"); - } - - FnConsole.log[2]("Storage Pools, Disk Label, Clear: In Progress, Disk: " + disk.id); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - if (!display.silent) { - FnDisplayAlert({ status: "success", title: "Disk label successfully cleared", description: disk.id, breakword: false }, { name: "storagepool-disk-labelclear", id: pool.id, timeout: 4 }); - } - - FnConsole.log[1]("Storage Pools, Disk Label, Clear: Success, Disk: " + disk.id); - - setTimeout(function () { - FnDisksBlkidGet(); - }, 200); - }) - .fail(function (message, data) { - if (!display.silent) { - FnDisplayAlert({ status: "danger", title: "Disk label could not be cleared", description: disk.id, breakword: false }, { name: "storagepool-disk-labelclear", id: pool.id, timeout: 4 }); - } - - FnConsole.warn("Storage Pools, Disk Label, Clear: Failed, Disk: " + disk.id + ", Message: " + (data ? data : message)); - }); -} - -function FnStoragePoolDiskOffline(pool = { name, id }, disk = { id, force: false, temporary: false }, modal = { name, id }) { - let process = { - command: ["/sbin/zpool", "offline", pool.name, disk.id] - }; - - if (disk.force) { - process.command.splice(2, 0, "-f"); - } - if (disk.temporary) { - process.command.splice(2, 0, "-t"); - } - - FnConsole.log[1]("Storage Pools, Disk, Offline: In Progress, Pool: " + pool.name + ", Disk: " + disk.id); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-" + modal.name + "-" + modal.id + " span").text("Setting disk offline..."); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "Disk successfully set offline", description: disk.id, breakword: false }, { name: "storagepool-disk-offline", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, Disk, Offline: Success, Pool: " + pool.name + ", Disk: " + disk.id); - }) - .fail(function (message, data) { - FnDisplayAlert({ status: "danger", title: "Disk could not be set offline", description: disk.id, breakword: false }, { name: "storagepool-disk-offline", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, Disk, Offline: Failed, Pool: " + pool.name + ", Disk: " + disk.id + ", Message: " + (data ? data : message)); - }) - .finally(function () { - $("#modal-" + modal.name + "-" + modal.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); - }, 200); - });; -} - -function FnStoragePoolDiskOnline(pool = { name, id, scrub: false }, disk = { id, expand: false }, modal = { name, id }) { - let process = { - command: ["/sbin/zpool", "online", pool.name, disk.id] - }; - - if (disk.expand) { - process.command.splice(2, 0, "-e"); - } - - FnConsole.log[1]("Storage Pools, Disk, Online: In Progress, Pool: " + pool.name + ", Disk: " + disk.id); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-" + modal.name + "-" + modal.id + " span").text("Setting disk online..."); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function (data, message) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Storage Pools, Disk, Online:" })); - - if (/^warning:/gi.test(data)) { - FnDisplayAlert({ status: "warning", title: "Disk set online but remains in faulted state", description: disk.id, breakword: false }, { name: "storagepool-disk-online", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, Disk, Online: Warning, Pool: " + pool.name + ", Message: " + (data ? data.replace(/^warning: /gi, "") : message)); - } else { - FnDisplayAlert({ status: "success", title: "Disk successfully set online", description: disk.id, breakword: false }, { name: "storagepool-disk-online", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, Disk, Online: Success, Pool: " + pool.name + ", Disk: " + disk.id); - } - - if (pool.scrub) { - FnStoragePoolScrubStart({ name: pool.name, id: pool.id }, { resume: false }, { refresh: false }); - } - }) - .fail(function (message, data) { - FnDisplayAlert({ status: "danger", title: "Disk could not be set online", description: disk.id, breakword: false }, { name: "storagepool-disk-online", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, Disk, Online: Failed, Pool: " + pool.name + ", Disk: " + disk.id + ", Message: " + (data ? data : message)); - }) - .finally(function () { - $("#modal-" + modal.name + "-" + modal.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); - }, 200); - });; -} - -function FnStoragePoolDiskReplace(pool = { name, id, force: false }, disk = { id, idnew }, modal = { name, id }) { - let process = { - command: ["/sbin/zpool", "replace", pool.name, disk.id, disk.idnew] - }; - - if (pool.force) { - process.command.splice(2, 0, "-f"); - } - - FnConsole.log[1]("Storage Pools, Disk, Replace: In Progress, Pool: " + pool.name + ", Disk: " + disk.id); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-" + modal.name + "-" + modal.id + " span").text("Replacing disk..."); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "Disk replaced successfully on Storage Pool", description: pool.name, breakword: false }, { name: "storagepool-disk-replace", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, Disk, Replace: Success, Pool: " + pool.name + ", Disk: " + disk.id); - }) - .fail(function (message, data) { - FnDisplayAlert({ status: "danger", title: "Disk could not be replaced on Storage Pool", description: pool.name, breakword: false }, { name: "storagepool-disk-replace", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, Disk, Replace: Failed, Pool: " + pool.name + ", Disk: " + disk.id + ", Message: " + (data ? data : message)); - }) - .finally(function () { - $("#modal-" + modal.name + "-" + modal.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); - }, 200); - });; -} - -function FnStoragePoolExport(pool = { name, id, altroot: false, force: false, readonly: false }, samba = { restart: false }) { - if (samba.restart) { - FnSambaStop() - .finally(function () { - if (zfsmanager.configuration.samba.manage) { - $("#spinner-storagepool-export-" + pool.id + " span").text("Retrieving Samba shares..."); - - FnSambaSharesGet({ name: pool.name, id: pool.id }, { name: null, clones: [] }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Shares, Get:" })); - - let filesystems = { - id: data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) - }; - - $("#spinner-storagepool-export-" + pool.id + " span").text("Exporting storage pool..."); - - if (filesystems.id.length > 0) { - FnStoragePoolExportCommand({ name: pool.name, id: pool.id, force: pool.force }, { refresh: false }) - .done(function () { - $("#spinner-storagepool-export-" + pool.id + " span").text("Destroying Samba shares..."); - - FnSambaSharesDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { id: filesystems.id }, { restart: samba.restart }, { silent: false }) - .finally(function () { - $("#modal-storagepool-export-" + pool.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 200); - }); - }); - } else { - FnStoragePoolExportCommand({ name: pool.name, id: pool.id, force: pool.force }, { refresh: true }) - .finally(function () { - FnSambaStart(); - }); - } - }) - .fail(function (message, data) { - FnStoragePoolExportFail({ name: pool.name, id: pool.id }, { data: data, message: message }, { refresh: true }); - FnSambaStart(); - }); - } else { - FnStoragePoolExportCommand({ name: pool.name, id: pool.id, force: pool.force }, { refresh: true }) - .finally(function () { - FnSambaStart(); - }); - } - }); - } else { - if (zfsmanager.configuration.samba.manage) { - $("#spinner-storagepool-export-" + pool.id + " span").text("Retrieving Samba shares..."); - - FnSambaSharesGet({ name: pool.name, id: pool.id }, { name: null, clones: [] }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Shares, Get:" })); - - let filesystems = { - id: data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) - }; - - $("#spinner-storagepool-export-" + pool.id + " span").text("Exporting storage pool..."); - - if (filesystems.id.length > 0) { - FnStoragePoolExportCommand({ name: pool.name, id: pool.id, force: pool.force }, { refresh: false }) - .done(function () { - $("#spinner-storagepool-export-" + pool.id + " span").text("Destroying Samba shares..."); - - FnSambaSharesDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { id: filesystems.id }, { restart: samba.restart }, { silent: false }) - .finally(function () { - $("#modal-storagepool-export-" + pool.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 200); - }); - }); - } else { - FnStoragePoolExportCommand({ name: pool.name, id: pool.id, force: pool.force }, { refresh: true }); - } - }) - .fail(function (message, data) { - FnStoragePoolExportFail({ name: pool.name, id: pool.id }, { data: data, message: message }, { refresh: true }); - }); - } else { - FnStoragePoolExportCommand({ name: pool.name, id: pool.id, force: pool.force }, { refresh: true }); - } - } -} - -function FnStoragePoolExportCommand(pool = { name, id, force: false }, display = { refresh: true }) { - let process = { - command: ["/sbin/zpool", "export", pool.name] - }; - - if (pool.force) { - process.command.splice(2, 0, "-f"); - } - - FnConsole.log[1]("Storage Pools, Export: In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "Storage Pool successfully exported", description: pool.name, breakword: false }, { name: "storagepool-export", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, Export: Success, Pool: " + pool.name); - }) - .fail(function (message, data) { - FnStoragePoolExportFail({ name: pool.name, id: pool.id }, { data: data, message: message }, { refresh: false }); - - display.refresh = true; - }) - .finally(function () { - if (display.refresh) { - $("#modal-storagepool-export-" + pool.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 200); - } - }); -} - -function FnStoragePoolExportFail(pool = { name, id }, process = { data, message }, display = { refresh: true }) { - FnDisplayAlert({ status: "danger", title: "Storage Pool could not be exported", description: pool.name, breakword: false }, { name: "storagepool-export", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, Export: Failed, Pool: " + pool.name + ", Message: " + (process.data ? process.data : process.message)); + FnModalsRegister(); + FnStoragePoolsGet(); + + FnVersionWarning(); + FnZfsVersionWarnings() +} - if (display.refresh) { - $("#modal-storagepool-export-" + pool.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 200); +function FnFirstStepsPrivileged() { + //Execute functions when user is an administrator + + FnConfigurationDirectoryCreate(); + FnConfigurationDirectoryRuntimeCreate(); + + if (!zfsmanager.user.configuration) { + FnConfigurationLegacyGet(); + } else { + if (zfsmanager.configuration.cockpit.manage) { + FnCockpitManage(); + } + if (zfsmanager.configuration.samba.manage) { + FnSambaManage(); + } + FnSambaUsersharesDirectoryCreate(); + if (zfsmanager.configuration.updates.check) { + FnUpdatesCheck({ alert: true }); + } } -} - -function FnStoragePoolHealthIcon(pool = { health }) { - switch (pool.health.toLowerCase()) { - case "online": - pool.healthicon = "pficon pficon-ok list-view-pf-icon-sm"; - break; - case "offline": - pool.healthicon = "fa pficon-info list-view-pf-icon-sm"; - break; - case "split": - pool.healthicon = "fa pficon-info list-view-pf-icon-sm"; - break; - case "degraded": - pool.healthicon = "pficon pficon-warning-triangle-o list-view-pf-icon-sm"; - break; - case "unknown": - pool.healthicon = "pficon pficon-warning-triangle-o list-view-pf-icon-sm"; - break; - case "removed": - pool.healthicon = "pficon pficon-error-circle-o list-view-pf-icon-sm"; - break; - case "faulted": - pool.healthicon = "pficon pficon-error-circle-o list-view-pf-icon-sm"; - break; - case "unavail": - pool.healthicon = "pficon pficon-error-circle-o list-view-pf-icon-sm"; - break; - case "avail": - pool.healthicon = "pficon pficon-ok list-view-pf-icon-sm"; - break; - case "inuse": - pool.healthicon = "pficon pficon-ok list-view-pf-icon-sm"; - break; - case "fail": - pool.healthicon = "pficon pficon-error-circle-o list-view-pf-icon-sm"; - break; - case "destroyed": - pool.healthicon = "pficon pficon-error-circle-o list-view-pf-icon-sm"; - break; - default: - pool.healthicon = "fa pficon-info list-view-pf-icon-sm"; - break; - } - - return pool.healthicon; -} - -function FnStoragePoolImport(pool = { name, altroot, destroyed: false, force: false, guid, ignoremissinglog: false, namenew, readonly: false, recoverymode: false }, filesystem = { mount: true, selinux: true }, disks = { id: { blockdevice: true, disk: false, path: false, vdev: false }, identifier }) { - let process = { - command: ["/sbin/zpool", "import", pool.guid] - }; - let modal = { - hide: true - }; - - disks.devpath = "/dev"; - disks.fallback = false; - disks.identifiertext = "Block Device"; - - if (pool.namenew) { - pool.name = pool.namenew; - } - - process.command.push(pool.name); - - pool.id = FnGenerateId({ at: false, colon: true, forwardslash: false, period: true, underscore: true, whitespace: true }, { name: pool.name, attribute: true }); - pool.imported = false; - - if (!filesystem.mount) { - process.command.splice(2, 0, "-N"); - } - - if (pool.altroot) { - process.command.splice(2, 0, "-o"); - process.command.splice(3, 0, "altroot=" + pool.altroot); - } - if (pool.destroyed) { - process.command.splice(2, 0, "-D"); - } - if (pool.force) { - process.command.splice(2, 0, "-f"); - } - if (pool.recoverymode) { - process.command.splice(2, 0, "-F"); - } - if (pool.ignoremissinglog) { - process.command.splice(2, 0, "-m"); - } - if (pool.readonly) { - process.command.splice(2, 0, "-o"); - process.command.splice(3, 0, "readonly=on"); - } - - process.command.splice(2, 0, "-d"); - - switch (disks.identifier) { //Fallback to block device to prevent import error when selected identifier is not available - case "disk": - if (disks.id.disk) { - disks.devpath = "/dev/disk/by-id"; - } else { - disks.fallback = true; - } - disks.identifiertext = "Disk / WWN"; - break; - case "path": - if (disks.id.path) { - disks.devpath = "/dev/disk/by-path"; - } else { - disks.fallback = true; - } - disks.identifiertext = "Hardware Path"; - break; - case "vdev": - if (disks.id.vdev) { - disks.devpath = "/dev/disk/by-vdev"; +} + +//#endregion + +//#region Fixed Content Click Actions + +$(document).on("click", "#btn-alerts-requirements-samba-refresh", function () { + Requirements({ zfs: true }); +}); + +$(document).on("click", "#btn-alerts-requirements-zfs-refresh", function () { + Requirements({ zfs: false }); +}); + +$(document).on("click", "#btn-storagepools-refresh", function () { + FnStoragePoolsGet(); +}); + +$(document).on("click", "#table-storagepools > tbody > tr.listing-ct-item", function (element) { + if (!$(this).hasClass("listing-ct-storagepoolsnotfound") && !$(element.target).is("a, button, .fa.fa-ellipsis-v, input")) { + if (!$(this).parent().hasClass("open")) { + $(this).parent().addClass("open"); + + $(this).attr("data-pool-refresh-filesystems", "false"); + $(this).attr("data-pool-refresh-snapshots", "false"); + $(this).attr("data-pool-refresh-status", "false"); + + FnStoragePoolRefresh({ name: $(this).attr("data-pool-name"), id: $(this).attr("data-pool-id") }, { storagepool: true, filesystems: true, snapshots: true, status: true }); + } else { + if (!$("#spinner-storagepool-" + $(this).attr("data-pool-id")).hasClass("hidden")) { + //Disable click action while information is still loading } else { - disks.fallback = true; + $(this).parent().removeClass("open"); + + $(this).attr("data-pool-refresh-filesystems", "false"); + $(this).attr("data-pool-refresh-snapshots", "false"); + $(this).attr("data-pool-refresh-status", "false"); + + $("#spinner-storagepool-" + $(this).attr("data-pool-id")).removeClass("hidden"); + $("#listingcthead-storagepool-" + $(this).attr("data-pool-id")).addClass("hidden"); + $("#listingctbody-storagepool-" + $(this).attr("data-pool-id")).addClass("hidden"); + + FnStoragePoolRefreshAutoDisable({ name: $(this).attr("data-pool-name"), id: $(this).attr("data-pool-id") }); } - disks.identifiertext = "Virtual Device Mapping"; - break; - } - - process.command.splice(3, 0, disks.devpath); - - FnConsole.log[1]("Storage Pools, Import: In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-storagepools-import span").text("Importing storage pool..."); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - pool.imported = true; - - if (disks.fallback) { - FnDisplayAlert({ status: "warning", title: "Storage Pool imported with errors", description: pool.name, breakword: false }, { name: "storagepools-import", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, Import: Warning, Pool: " + pool.name + ", Message: " + disks.identifiertext + " disks identifier was not available during import. Block Device disks identifier was used."); - } else { - FnDisplayAlert({ status: "success", title: "Storage Pool successfully imported", description: pool.name, breakword: false }, { name: "storagepools-import", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, Import: Success, Pool: " + pool.name); - } - }) - .fail(function (message, data) { - if (/cannot mount.*directory is not empty|smb add share failed|cannot share/gi.test(data)) { //Storage pool has successfully imported, however a file system error is generated - pool.imported = true; - - FnDisplayAlert({ status: "warning", title: "Storage Pool imported with errors", description: pool.name, breakword: false }, { name: "storagepools-import", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, Import: Warning, Pool: " + pool.name + ", Message: " + (data ? data : message)); - } else if (/cannot import.*pool already exists/gi.test(data)) { - modal.hide = false; - - if (!$("#switch-storagepools-import-rename input").prop("checked")) { - $("#switch-storagepools-import-rename input").click(); - } - $("#validationwrapper-storagepools-import-storagepools").addClass("has-error"); - $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text("Storage pool name already exists. New name is needed."); - $("#input-storagepools-import-namenew").focus(); - } else { - FnDisplayAlert({ status: "danger", title: "Storage Pool could not be imported", description: pool.name, breakword: false }, { name: "storagepools-import", id: pool.id, timeout: 4 }); - } - - if (!modal.hide) { - $("#spinner-storagepools-import").addClass("hidden"); - $("#spinner-storagepools-import span").text(""); - $("#btn-storagepools-import-apply").prop("disabled", false); - } - - if (!pool.imported) { - FnConsole.warn("Storage Pools, Import: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); - } - }) - .finally(function () { - if (pool.imported) { - if (filesystem.selinux && !pool.readonly) { - $("#spinner-storagepools-import span").text("Configuring SELinux contexts for Samba..."); - - FnStoragePoolSelinuxContextsSambaSet({ name: pool.name, id: pool.id }) - .finally(function () { - if (zfsmanager.configuration.samba.manage) { - if (!pool.readonly) { - $("#spinner-storagepools-import span").text("Disabling Samba share inheritance..."); - - FnFileSystemShareSmbInheritedDisable({ name: pool.name, id: pool.id, altroot: (pool.altroot ? true : false) }, { name: null }, { disable: false }) - .finally(function () { - $("#spinner-storagepools-import span").text("Creating Samba shares..."); - - FnSambaSharesEnable({ name: pool.name, id: pool.id, altroot: (pool.altroot ? true : false), readonly: pool.readonly }, { name: null, force: true }, { restart: false }, { refresh: false, silent: false }) - .finally(function () { - if (modal.hide) { - $("#modal-storagepools-import").modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 200); - } - }); - }); - } else { - $("#spinner-storagepools-import span").text("Creating Samba shares..."); - - FnSambaSharesEnable({ name: pool.name, id: pool.id, altroot: (pool.altroot ? true : false), readonly: pool.readonly }, { name: null, force: true }, { restart: false }, { refresh: false, silent: false }) - .finally(function () { - if (modal.hide) { - $("#modal-storagepools-import").modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 200); - } - }); - } - } else { - if (modal.hide) { - $("#modal-storagepools-import").modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 200); - } - } - }); - } else { - if (zfsmanager.configuration.samba.manage) { - if (!pool.readonly) { - $("#spinner-storagepools-import span").text("Disabling Samba share inheritance..."); - - FnFileSystemShareSmbInheritedDisable({ name: pool.name, id: pool.id, altroot: (pool.altroot ? true : false) }, { name: null }, { disable: false }) - .finally(function () { - $("#spinner-storagepools-import span").text("Creating Samba shares..."); - - FnSambaSharesEnable({ name: pool.name, id: pool.id, altroot: (pool.altroot ? true : false), readonly: pool.readonly }, { name: null, force: true }, { restart: false }, { refresh: false, silent: false }) - .finally(function () { - if (modal.hide) { - $("#modal-storagepools-import").modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 200); - } - }); - }); - } else { - $("#spinner-storagepools-import span").text("Creating Samba shares..."); - - FnSambaSharesEnable({ name: pool.name, id: pool.id, altroot: (pool.altroot ? true : false), readonly: pool.readonly }, { name: null, force: true }, { restart: false }, { refresh: false, silent: false }) - .finally(function () { - if (modal.hide) { - $("#modal-storagepools-import").modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 200); - } - }); - } - } else { - if (modal.hide) { - $("#modal-storagepools-import").modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 200); - } - } - } - } else { - if (modal.hide) { - $("#modal-storagepools-import").modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 200); - } - } - }); -} - -function FnStoragePoolRefreservationSet(pool = { name, id }, filesystem = { refreservation }) { - let process = { - command: ["/sbin/zfs", "set", "refreservation=" + filesystem.refreservation, pool.name] - }; - - FnConsole.log[2]("Storage Pools, Refreservation, Set: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnConsole.log[2]("Storage Pools, Refreservation, Set: Success, Pool: " + pool.name); - }) - .fail(function (message, data) { - FnConsole.warn("Storage Pools, Refreservation, Set: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); - }); -} - -function FnStoragePoolRefresh(pool = { name, id }, refresh = { storagepool: true, filesystems: false, snapshots: false, status: false }) { - if (zfsmanager.configuration.zfs.storagepool.refreshall || refresh.storagepool) { - FnStoragePoolRefreshCommand({ name: pool.name, id: pool.id }); - } - - setTimeout(function () { - if (zfsmanager.configuration.zfs.storagepool.refreshall) { - FnStoragePoolRefreshAutoDisable({ name: pool.name, id: pool.id }); - } - - if (zfsmanager.configuration.zfs.storagepool.refreshall || refresh.filesystems) { - $("#btn-storagepool-filesystems-create-" + pool.id).prop("disabled", true); - $("#btn-storagepool-filesystems-refresh-" + pool.id).prop("disabled", true); - $("[id^=btn-storagepool-filesystem-dropdown-" + pool.id + "]").addClass("disabled"); - $("#paneltitle-storagepool-filesystems-" + pool.id).addClass("hidden"); - $("#spinner-storagepool-filesystems-" + pool.id).removeClass("hidden"); - - FnFileSystemsGet({ name: pool.name, id: pool.id }); - } - - if (zfsmanager.configuration.zfs.storagepool.refreshall || refresh.snapshots) { - $("#btn-storagepool-snapshots-create-" + pool.id).prop("disabled", true); - $("#btn-storagepool-snapshots-refresh-" + pool.id).prop("disabled", true); - $("[id^=btn-storagepool-snapshot-dropdown-" + pool.id + "]").addClass("disabled"); - $("#paneltitle-storagepool-snapshots-" + pool.id).addClass("hidden"); - $("#spinner-storagepool-snapshots-" + pool.id).removeClass("hidden"); - - FnSnapshotsGet({ name: pool.name, id: pool.id }); - } - - if (zfsmanager.configuration.zfs.storagepool.refreshall || refresh.status) { - $("#btn-storagepool-status-refresh-" + pool.id).prop("disabled", true); - $("[id^=btn-storagepool-status-dropdown-][id$=" + pool.id + "]").addClass("disabled"); - $("#paneltitle-storagepool-status-" + pool.id).addClass("hidden"); - $("#spinner-storagepool-status-" + pool.id).removeClass("hidden"); - $("#spinner-storagepool-status-0-" + pool.id).removeClass("hidden"); - - FnStatusGet({ name: pool.name, id: pool.id }); - } - }, 200); -} - -function FnStoragePoolRefreshAutoDisable(pool = { name, id }) { - if ($("#tr-storagepool-" + pool.id).attr("data-pool-refresh-id") != "") { - FnConsole.log[2]("Storage Pools, Refresh, Auto: Disabled, Pool: " + pool.name); - } - - clearInterval($("#tr-storagepool-" + pool.id).attr("data-pool-refresh-id")); - - $("#tr-storagepool-" + pool.id).attr("data-pool-refresh-id", ""); - $("#btn-storagepool-status-refresh-" + pool.id).text("Refresh"); -} - -function FnStoragePoolRefreshCommand(pool = { name, id }) { - let process = { - command: ["/sbin/zpool", "list", "-H", "-o", "guid,health,size,alloc,free,fragmentation,autotrim,version,feature@allocation_classes,feature@async_destroy,feature@bookmark_v2,feature@bookmarks,feature@device_removal,feature@edonr,feature@embedded_data,feature@empty_bpobj,feature@enabled_txg,feature@encryption,feature@extensible_dataset,feature@filesystem_limits,feature@hole_birth,feature@large_blocks,feature@large_dnode,feature@lz4_compress,feature@multi_vdev_crash_dump,feature@obsolete_counts,feature@project_quota,feature@resilver_defer,feature@sha512,feature@skein,feature@spacemap_histogram,feature@spacemap_v2,feature@userobj_accounting,feature@zpool_checkpoint", "-p", pool.name] - }; - - FnConsole.log[2]("Storage Pools, Refresh: In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Storage Pools, Refresh:" })); - - pool.properties = data.trim().split(/\t/g).filter(v => v); - - //0=guid, 1=health, 2=size, 3=alloc, 4=free, 5=fragmentation, 6=autotrim, 7=version, 8=feature@allocation_classes, 9=feature@async_destroy, 10=feature@bookmark_v2, 11=feature@bookmarks, 12=feature@device_removal, 13=feature@edonr, 14=feature@embedded_data, 15=feature@empty_bpobj, 16=feature@enabled_txg, 17=feature@encryption, 18=feature@extensible_dataset, 19=feature@filesystem_limits, 20=feature@hole_birth, 21=feature@large_blocks, 22=feature@large_dnode, 23=feature@lz4_compress, 24=feature@multi_vdev_crash_dump, 25=feature@obsolete_counts, 26=feature@project_quota, 27=feature@resilver_defer, 28=feature@sha512, 29=feature@skein, 30=feature@spacemap_histogram, 31=feature@spacemap_v2, 32=feature@userobj_accounting, 33=feature@zpool_checkpoint - - pool.allocated = FnFormatBytes({ base2: true, decimals: 2, value: pool.properties[3] }); - pool.allocatedpercent = FnRound({ decimals: 2, value: (pool.properties[3] / pool.properties[2]) * 100 }); - pool.autotrim = (pool.properties[6].toLowerCase() == "on" ? true : false); - pool.boot = (zfsmanager.zfs.storagepool.boot && pool.name == zfsmanager.zfs.storagepool.boot ? true : false); - pool.feature = { - allocation_classes: (/active|enabled/gi.test(pool.properties[8]) ? true : false), - async_destroy: (/active|enabled/gi.test(pool.properties[9]) ? true : false), - bookmark_v2: (/active|enabled/gi.test(pool.properties[10]) ? true : false), - bookmarks: (/active|enabled/gi.test(pool.properties[11]) ? true : false), - device_removal: (/active|enabled/gi.test(pool.properties[12]) ? true : false), - edonr: (/active|enabled/gi.test(pool.properties[13]) ? true : false), - embedded_data: (/active|enabled/gi.test(pool.properties[14]) ? true : false), - empty_bpobj: (/active|enabled/gi.test(pool.properties[15]) ? true : false), - enabled_txg: (/active|enabled/gi.test(pool.properties[16]) ? true : false), - encryption: (/active|enabled/gi.test(pool.properties[17]) ? true : false), - extensible_dataset: (/active|enabled/gi.test(pool.properties[18]) ? true : false), - filesystem_limits: (/active|enabled/gi.test(pool.properties[19]) ? true : false), - hole_birth: (/active|enabled/gi.test(pool.properties[20]) ? true : false), - large_blocks: (/active|enabled/gi.test(pool.properties[21]) ? true : false), - large_dnode: (/active|enabled/gi.test(pool.properties[22]) ? true : false), - lz4_compress: (/active|enabled/gi.test(pool.properties[23]) ? true : false), - multi_vdev_crash_dump: (/active|enabled/gi.test(pool.properties[24]) ? true : false), - obsolete_counts: (/active|enabled/gi.test(pool.properties[25]) ? true : false), - project_quota: (/active|enabled/gi.test(pool.properties[26]) ? true : false), - resilver_defer: (/active|enabled/gi.test(pool.properties[27]) ? true : false), - sha512: (/active|enabled/gi.test(pool.properties[28]) ? true : false), - skein: (/active|enabled/gi.test(pool.properties[29]) ? true : false), - spacemap_histogram: (/active|enabled/gi.test(pool.properties[30]) ? true : false), - spacemap_v2: (/active|enabled/gi.test(pool.properties[31]) ? true : false), - userobj_accounting: (/active|enabled/gi.test(pool.properties[32]) ? true : false), - zpool_checkpoint: (/active|enabled/gi.test(pool.properties[33]) ? true : false) - }; - pool.fragmentation = (pool.properties[5] == "-" ? 0 : pool.properties[5]); - pool.free = FnFormatBytes({ base2: true, decimals: 2, value: pool.properties[4] }); - pool.freepercent = FnRound({ decimals: 2, value: (pool.properties[4] / pool.properties[2]) * 100 }); - pool.guid = pool.properties[0]; - pool.health = pool.properties[1]; - pool.healthicon = FnStoragePoolHealthIcon({ health: pool.health }); - pool.root = (zfsmanager.zfs.storagepool.root && pool.name == zfsmanager.zfs.storagepool.root ? true : false); - pool.size = FnFormatBytes({ base2: true, decimals: 2, value: pool.properties[2] }); - pool.upgrade = ($.isNumeric(pool.properties[6] && !pool.boot) ? true : false); - pool.version = pool.properties[7]; - - //Upgrade available if a requested feature flag returns false - if (!pool.boot) { - for (var x in pool.feature) { - if (!pool.feature[x] && !pool.upgrade) { - pool.upgrade = true; - } - } - } - - if (pool.upgrade) { - $("#span-storagepool-upgrade-" + pool.id).removeClass("hidden"); - } else { - $("#span-storagepool-upgrade-" + pool.id).addClass("hidden"); - } - - $("#div-storagepool-health-" + pool.id).empty().html(` ` + pool.health); - $("#div-storagepool-size-" + pool.id).text(pool.size); - $("#div-storagepool-allocated-" + pool.id).text(pool.allocated); - $("#div-storagepool-free-" + pool.id).text(pool.free); - $("#div-storagepool-fragmentation-" + pool.id).text(pool.fragmentation + " %"); - - $("#progressbar-storagepool-allocated-" + pool.id).attr("aria-valuenow", pool.allocatedpercent); - $("#progressbar-storagepool-allocated-" + pool.id).attr("title", pool.allocatedpercent + "% Allocated"); - $("#progressbar-storagepool-allocated-" + pool.id).attr("data-original-title", pool.allocatedpercent + "% Allocated"); - $("#progressbar-storagepool-allocated-" + pool.id).css("width", pool.allocatedpercent + "%"); - $("#progressbar-storagepool-allocated-" + pool.id + " .sr-only").text(pool.allocatedpercent + "% Allocated"); - - $("#progressbar-storagepool-free-" + pool.id).attr("aria-valuenow", pool.freepercent); - $("#progressbar-storagepool-free-" + pool.id).attr("title", pool.freepercent + "% Free"); - $("#progressbar-storagepool-free-" + pool.id).attr("data-original-title", pool.freepercent + "% Free"); - $("#progressbar-storagepool-free-" + pool.id).css("width", pool.freepercent + "%"); - $("#progressbar-storagepool-free-" + pool.id + " .sr-only").text(pool.freepercent + "% Free"); - - $("#tr-storagepool-" + pool.id).attr("data-pool-autotrim", pool.autotrim); - $("#tr-storagepool-" + pool.id).attr("data-pool-feature-allocation_classes", pool.feature.allocation_classes); - $("#tr-storagepool-" + pool.id).attr("data-pool-feature-device_removal", pool.feature.device_removal); - $("#tr-storagepool-" + pool.id).attr("data-pool-feature-edonr", pool.feature.edonr); - $("#tr-storagepool-" + pool.id).attr("data-pool-feature-encryption", pool.feature.encryption); - $("#tr-storagepool-" + pool.id).attr("data-pool-feature-large_blocks", pool.feature.large_blocks); - $("#tr-storagepool-" + pool.id).attr("data-pool-feature-lz4_compress", pool.feature.lz4_compress); - $("#tr-storagepool-" + pool.id).attr("data-pool-feature-resilver_defer", pool.feature.resilver_defer); - $("#tr-storagepool-" + pool.id).attr("data-pool-feature-sha512", pool.feature.sha512); - $("#tr-storagepool-" + pool.id).attr("data-pool-feature-skein", pool.feature.skein); - $("#tr-storagepool-" + pool.id).attr("data-pool-guid", pool.guid); - $("#tr-storagepool-" + pool.id).attr("data-pool-version", pool.version); - - FnConsole.log[1]("Storage Pools, Refresh: Success, Pool: " + pool.name); - }) - .fail(function (message, data) { - FnConsole.warn("Storage Pools, Refresh: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); - }); -} - -function FnStoragePoolRegenerateGuid(pool = { name, id }, modal = { name, id }) { - let process = { - command: ["/sbin/zpool", "reguid", pool.name] - }; - - FnConsole.log[2]("Storage Pools, Regenerate GUID: In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-" + modal.name + "-" + modal.id + " span").text("Regenerating storage pool GUID..."); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "Storage Pool GUID successfully regenerated", description: pool.name, breakword: false }, { name: "storagepool-regenerateguid", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, Regenerate GUID: Success, Pool: " + pool.name); - }) - .fail(function (message, data) { - FnDisplayAlert({ status: "danger", title: "Storage Pool GUID could not be regenerated", description: pool.name, breakword: false }, { name: "storagepool-regenerateguid", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, Regenerate GUID: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); - }) - .finally(function () { - $("#modal-" + modal.name + "-" + modal.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); - }, 200); - });; -} - -function FnStoragePoolResilver(pool = { name, id }, modal = { name, id }) { - let process = { - command: ["/sbin/zpool", "resilver", pool.name] - }; - - FnConsole.log[1]("Storage Pools, Resilver, Start: In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-" + modal.name + "-" + modal.id + " span").text("Starting storage pool resilver..."); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "Storage Pool resilver successfully started", description: pool.name, breakword: false }, { name: "storagepool-resilver", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, Resilver, Start: Success, Pool: " + pool.name); - }) - .fail(function (message, data) { - FnDisplayAlert({ status: "danger", title: "Storage Pool resilver could not be started", description: pool.name, breakword: false }, { name: "storagepool-resilver", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, Resilver, Start: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); - }) - .finally(function () { - $("#modal-" + modal.name + "-" + modal.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); - }, 200); - }); -} - -function FnStoragePoolScrubPause(pool = { name, id }, display = { refresh: true }) { - let process = { - command: ["/sbin/zpool", "scrub", "-p", pool.name] - }; - - FnConsole.log[2]("Storage Pools, Scrub, Pause: In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "Storage Pool scrub successfully paused", description: pool.name, breakword: false }, { name: "storagepool-scrub-pause", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, Scrub, Pause: Success, Pool: " + pool.name); - }) - .fail(function (message, data) { - FnDisplayAlert({ status: "danger", title: "Storage Pool scrub could not be paused", description: pool.name, breakword: false }, { name: "storagepool-scrub-pause", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, Scrub, Pause: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); - }) - .finally(function () { - if (display.refresh) { - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); - }, 200); - } - });; -} - -function FnStoragePoolScrubStart(pool = { name, id }, scrub = { resume: false }, display = { refresh: true }) { - let process = { - command: ["/sbin/zpool", "scrub", pool.name] - }; - - FnConsole.log[2]("Storage Pools, Scrub, " + (scrub.resume ? "Resume" : "Start") + ": In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "Storage Pool scrub successfully " + (scrub.resume ? "resumed" : "started"), description: pool.name, breakword: false }, { name: "storagepool-scrub-start", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, Scrub, " + (scrub.resume ? "Resume" : "Start") + ": Success, Pool: " + pool.name); - }) - .fail(function (message, data) { - if (/currently scrubbing/gi.test(data)) { //Start scrub will fail if the storage pool has already initiated scrub - FnDisplayAlert({ status: "success", title: "Storage Pool scrub successfully " + (scrub.resume ? "resumed" : "started"), description: pool.name, breakword: false }, { name: "storagepool-scrub-start", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, Scrub, " + (scrub.resume ? "Resume" : "Start") + ": Success, Pool: " + pool.name); - } else { - if (/currently resilvering/gi.test(data)) { //Start scrub will fail if the storage pool has initiated resilver - FnDisplayAlert({ status: "warning", title: "Storage Pool scrub could not be " + (scrub.resume ? "resumed" : "started") + ". Resilver in progress", description: pool.name, breakword: false }, { name: "storagepool-scrub-start", id: pool.id, timeout: 4 }); - } else { - FnDisplayAlert({ status: "danger", title: "Storage Pool scrub could not be " + (scrub.resume ? "resumed" : "started"), description: pool.name, breakword: false }, { name: "storagepool-scrub-start", id: pool.id, timeout: 4 }); - } - - FnConsole.warn("Storage Pools, Scrub, " + (scrub.resume ? "Resume" : "Start") + ": Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); - } - }) - .finally(function () { - if (display.refresh) { - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); - }, 200); - } - }); -} - -function FnStoragePoolScrubStop(pool = { name, id }, display = { refresh: true }) { - let process = { - command: ["/sbin/zpool", "scrub", "-s", pool.name] - }; - - FnConsole.log[2]("Storage Pools, Scrub, Stop: In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "Storage Pool scrub successfully stopped", description: pool.name, breakword: false }, { name: "storagepool-scrub-stop", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, Scrub, Stop: Success, Pool: " + pool.name); - }) - .fail(function (message, data) { - FnDisplayAlert({ status: "danger", title: "Storage Pool scrub could not be stopped", description: pool.name, breakword: false }, { name: "storagepool-scrub-stop", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, Scrub, Stop: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); - }) - .finally(function () { - if (display.refresh) { - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); - }, 200); - } - });; -} - -function FnStoragePoolSelinuxContextsSambaSet(pool = { name, id }, display = { silent: false }) { - let process = { - command: ["/sbin/zfs", "list", "-H", "-o", "name", "-r", "-t", "filesystem", pool.name], - promise: cockpit.defer() - }; - - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Storage Pools, SELinux Contexts, Samba, Set:" })); - - let filesystems = data.split(/\n/g).filter(v => v); - let promise = Promise.resolve(); - - if (filesystems.length > 0) { - filesystems.forEach((_value, _index) => { - promise = promise.then(_ => new Promise(resolve => - setTimeout(function () { - FnFileSystemSelinuxContextsSambaSet({ name: pool.name, id: pool.id }, { name: _value }) - .finally(function () { - if (_index == (filesystems.length - 1)) { - if (!display.silent) { - FnDisplayAlert({ status: "success", title: "SELinux contexts for Samba successfully configured", description: pool.name, breakword: false }, { name: "selinux-enable", id: pool.id, timeout: 4 }); - } - - process.promise.resolve(); - } - }); - - resolve(); - }, 500) - )); - }); - } else { - if (!display.silent) { - FnDisplayAlert({ status: "success", title: "SELinux contexts for Samba successfully configured", description: pool.name, breakword: false }, { name: "selinux-enable", id: pool.id, timeout: 4 }); - } - - process.promise.resolve(); - } - }) - .fail(function (message, data) { - if (!display.silent) { - FnDisplayAlert({ status: "danger", title: "SELinux contexts for Samba could not be configured", description: pool.name, breakword: false }, { name: "selinux-enable", id: pool.id, timeout: 4 }); - } - - FnConsole.warn("Storage Pools, SELinux Contexts, Samba, Set: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); - - process.promise.resolve(); - }); - - return process.promise.promise(); -} - -function FnStoragePoolSizeGet(pool = { name, id }) { - let process = { - command: ["/sbin/zpool", "get", "size", "-H", "-o", "value", "-p", pool.name] - }; - - FnConsole.log[2]("Storage Pools, Size, Get: In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function () { - FnConsole.log[2]("Storage Pools, Size, Get: Success, Pool: " + pool.name); - }) - .fail(function (message, data) { - FnConsole.warn("Storage Pools, Size. Get: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); - }); -} - -function FnStoragePoolSpinnerHide(pool = { name, id }) { - if ($("#tr-storagepool-" + pool.id).attr("data-pool-refresh-filesystems") == "true" && $("#tr-storagepool-" + pool.id).attr("data-pool-refresh-snapshots") == "true" && $("#tr-storagepool-" + pool.id).attr("data-pool-refresh-status") == "true") { - setTimeout(function () { - $("#spinner-storagepool-" + pool.id).addClass("hidden"); - $("#listingcthead-storagepool-" + pool.id).removeClass("hidden"); - $("#listingctbody-storagepool-" + pool.id).removeClass("hidden"); - }, 200); - } -} - -function FnStoragePoolTrimCancel(pool = { name, id }, disk = { id }) { - let process = { - command: ["/sbin/zpool", "trim", "-c", pool.name] - }; - - if (disk.id) { - process.command.push(disk.id); - } - - FnConsole.log[2]("Storage Pools, " + (disk.id ? "Disk, " : "") + "TRIM, Cancel: In Progress, Pool: " + pool.name + (disk.id ? ", Disk: " + disk.id : "")); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: (disk.id ? "Disk" : "Storage Pool") + " TRIM successfully cancelled", description: (disk.id ? disk.id : pool.name), breakword: false }, { name: "storagepool-" + (disk.id ? "disk-" : "") + "trim-cancel", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, " + (disk.id ? "Disk, " : "") + "TRIM, Cancel: Success, Pool: " + pool.name + (disk.id ? ", Disk: " + disk.id : "")); - }) - .fail(function (message, data) { - FnDisplayAlert({ status: "danger", title: (disk.id ? "Disk" : "Storage Pool") + " TRIM could not be cancelled", description: (disk.id ? disk.id : pool.name), breakword: false }, { name: "storagepool-" + (disk.id ? "disk-" : "") + "trim-cancel", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, " + (disk.id ? "Disk, " : "") + "TRIM, Cancel: Failed, Pool: " + pool.name + (disk.id ? ", Disk: " + disk.id : "") + ", Message: " + (data ? data : message)); - }) - .finally(function () { - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); - }, 200); - }); -} - -function FnStoragePoolTrimStart(pool = { name, id }, disk = { id }, trim = { resume: false, secure: false }, modal = { name, id }) { - let process = { - command: ["/sbin/zpool", "trim", pool.name] - }; - - if (trim.secure) { - process.command.splice(2, 0, "-d"); - } - if (disk.id) { - process.command.push(disk.id); - } - - FnConsole.log[2]("Storage Pools, " + (disk.id ? "Disk, " : "") + "TRIM, " + (trim.resume ? "Resume" : "Start") + ": In Progress, Pool: " + pool.name + (disk.id ? ", Disk: " + disk.id : "")); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - if (!trim.resume) { - $("#spinner-" + modal.name + "-" + modal.id + " span").text("Starting " + (disk.id ? "disk" : "storage pool") + " TRIM..."); - } - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: (disk.id ? "Disk" : "Storage Pool") + " TRIM successfully " + (trim.resume ? "resumed" : "started"), description: (disk.id ? disk.id : pool.name), breakword: false }, { name: "storagepool-" + (disk.id ? "disk-" : "") + "trim-start", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, " + (disk.id ? "Disk, " : "") + "TRIM, " + (trim.resume ? "Resume" : "Start") + ": Success, Pool: " + pool.name + (disk.id ? ", Disk: " + disk.id : "")); - }) - .fail(function (message, data) { - FnDisplayAlert({ status: "danger", title: (disk.id ? "Disk" : "Storage Pool") + " TRIM could not be " + (trim.resume ? "resumed" : "started"), description: (disk.id ? disk.id : pool.name), breakword: false }, { name: "storagepool-" + (disk.id ? "disk-" : "") + "trim-start", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, " + (disk.id ? "Disk, " : "") + "TRIM, " + (trim.resume ? "Resume" : "Start") + ": Failed, Pool: " + pool.name + (disk.id ? ", Disk: " + disk.id : "") + ", Message: " + (data ? data : message)); - }) - .finally(function () { - if (modal.name && modal.id) { - $("#modal-" + modal.name + "-" + modal.id).modal("hide"); - } - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); - }, 200); - }); -} - -function FnStoragePoolTrimSuspend(pool = { name, id }, disk = { id }) { - let process = { - command: ["/sbin/zpool", "trim", "-s", pool.name] - }; - - if (disk.id) { - process.command.push(disk.id); - } - - FnConsole.log[2]("Storage Pools, " + (disk.id ? "Disk, " : "") + "TRIM, Suspend: In Progress, Pool: " + pool.name + (disk.id ? ", Disk: " + disk.id : "")); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: (disk.id ? "Disk" : "Storage Pool") + " TRIM successfully suspended", description: (disk.id ? disk.id : pool.name), breakword: false }, { name: "storagepool-" + (disk.id ? "disk-" : "") + "trim-suspend", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, " + (disk.id ? "Disk, " : "") + "TRIM, Suspend: Success, Pool: " + pool.name + (disk.id ? ", Disk: " + disk.id : "")); - }) - .fail(function (message, data) { - FnDisplayAlert({ status: "danger", title: (disk.id ? "Disk" : "Storage Pool") + " TRIM could not be suspended", description: (disk.id ? disk.id : pool.name), breakword: false }, { name: "storagepool-" + (disk.id ? "disk-" : "") + "trim-suspend", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, " + (disk.id ? "Disk, " : "") + "TRIM, Suspend: Failed, Pool: " + pool.name + (disk.id ? ", Disk: " + disk.id : "") + ", Message: " + (data ? data : message)); - }) - .finally(function () { - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); - }, 200); - }); -} - -function FnStoragePoolUpgrade(pool = { name, id }, modal = { name, id }) { - let process = { - command: ["/sbin/zpool", "upgrade", pool.name] - }; - - FnConsole.log[1]("Storage Pools, Upgrade: In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-" + modal.name + "-" + modal.id + " span").text("Upgrading storage pool..."); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function (data, message) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Storage Pools, Upgrade:" })); - - if (/Successfully upgraded|Enabled the following features/gi.test(data)) { - FnDisplayAlert({ status: "success", title: "Storage Pool successfully upgraded", description: pool.name, breakword: false }, { name: "storagepool-upgrade", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, Upgrade: Success, Pool: " + pool.name); - } else { - FnStoragePoolUpgradeFail({ name: pool.name, id: pool.id }, { data: data, message: message }); - } - }) - .fail(function (message, data) { - FnStoragePoolUpgradeFail({ name: pool.name, id: pool.id }, { data: data, message: message }); - }) - .finally(function () { - $("#modal-" + modal.name + "-" + modal.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true , snapshots: true, status: true }); - }, 200); - });; -} - -function FnStoragePoolUpgradeFail(pool = { name, id }, process = { data, message }) { - FnDisplayAlert({ status: "danger", title: "Storage Pool could not be upgraded", description: pool.name, breakword: false }, { name: "storagepool-upgrade", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, Upgrade: Failed, Pool: " + pool.name + ", Message: " + (process.data ? process.data : process.message)); -} - -function FnStoragePoolVirtualDeviceAdd(pool = { name, id, force: false, virtualdevice }, disks = { id: [] }, modal = { name, id }) { - let process = { - command: ["/sbin/zpool", "add", pool.name] - }; - - modal.hide = true; - - if (pool.force) { - process.command.splice(2, 0, "-f"); - } - if (pool.virtualdevice) { - if (pool.virtualdevice == "dedup mirror") { - process.command.push("dedup"); - process.command.push("mirror"); - } else if (pool.virtualdevice == "log mirror") { - process.command.push("log"); - process.command.push("mirror"); - } else if (pool.virtualdevice == "special mirror") { - process.command.push("special"); - process.command.push("mirror"); - } else { - process.command.push(pool.virtualdevice); - } - } - - disks.id.forEach(_value => _value && process.command.push(_value)); - - FnConsole.log[1]("Storage Pools, Virtual Device, Add: In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-" + modal.name + "-" + modal.id + " span").text("Adding virtual device..."); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "Virtual Device successfully added to Storage Pool", description: pool.name, breakword: false }, { name: "storagepool-virtualdevice-add", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, Virtual Device, Add: Success, Pool: " + pool.name); - }) - .fail(function (message, data) { - if (/contains devices of different sizes/gi.test(data)) { - modal.hide = false; - - $("#validationwrapper-" + modal.name + "-disks-" + modal.id).addClass("has-error"); - $("#helpblock-" + modal.name + "-disks-" + modal.id).addClass("has-error").removeClass("hidden").text("Disks are of different sizes. Forcefully add virtual device to override."); - } else if (/mismatched replication level/gi.test(data)) { - modal.hide = false; - - $("#validationwrapper-" + modal.name + "-disks-" + modal.id).addClass("has-error"); - $("#helpblock-" + modal.name + "-disks-" + modal.id).addClass("has-error").removeClass("hidden").text("Mismatched replication level. Forcefully add virtual device to override."); - } - - if (!modal.hide) { - $("#spinner-" + modal.name + "-" + modal.id).addClass("hidden"); - $("#btn-" + modal.name + "-apply-" + modal.id).prop("disabled", false); - - $("[id^=btn-storagepool-status-dropdown-][id$=" + pool.id + "]").removeClass("disabled"); - $("#spinner-storagepool-status-" + modal.id).addClass("hidden"); - } - - if (modal.hide) { - FnDisplayAlert({ status: "danger", title: "Virtual Device could not be added to Storage Pool", description: pool.name, breakword: false }, { name: "storagepool-virtualdevice-add", id: pool.id, timeout: 4 }); - } - - FnConsole.warn("Storage Pools, Virtual Device, Add: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); - }) - .finally(function () { - if (modal.hide) { - $("#modal-" + modal.name + "-" + modal.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: true }); - }, 200); - } - }); -} - -function FnStoragePoolVirtualDeviceClear(pool = { name, id }, virtualdevice = { id }, modal = { name, id }) { - let process = { - command: ["/sbin/zpool", "clear", pool.name, virtualdevice.id] - }; - - FnConsole.log[2]("Storage Pools, Virtual Device, Clear Errors: In Progress, Pool: " + pool.name + ", Virtual Device: " + virtualdevice.id); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-" + modal.name + "-" + modal.id + " span").text("Clearing virtual device errors..."); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "Virtual Device errors successfully cleared", description: virtualdevice.id, breakword: false }, { name: "storagepool-virtualdevice-clear", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, Virtual Device, Clear Errors: Success, Pool: " + pool.name + ", Virtual Device: " + virtualdevice.id); - }) - .fail(function (message, data) { - FnDisplayAlert({ status: "danger", title: "Virtual Device errors could not be cleared", description: virtualdevice.id, breakword: false }, { name: "storagepool-virtualdevice-clear", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, Virtual Device, Clear Errors: Failed, Pool: " + pool.name + ", Virtual Device: " + virtualdevice.id + ", Message: " + (data ? data : message)); - }) - .finally(function () { - $("#modal-" + modal.name + "-" + modal.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); - }, 200); - }); -} - -function FnStoragePoolVirtualDeviceRemove(pool = { name, id }, virtualdevice = { id, labelclear: false }, modal = { name, id }) { - let process = { - command: ["/sbin/zpool", "remove", pool.name, virtualdevice.id] - }; - - modal.hide = true; - - FnConsole.log[1]("Storage Pools, Virtual Device, Remove: In Progress, Pool: " + pool.name + ", Virtual Device: " + virtualdevice.id); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-" + modal.name + "-" + modal.id + " span").text("Removing virtual device..."); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "Virtual Device successfully removed from Storage Pool", description: pool.name, breakword: false }, { name: "storagepool-virtualdevice-remove", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Storage Pools, Virtual Device, Remove: Success, Pool: " + pool.name + ", Virtual Device: " + virtualdevice.id); - - if (virtualdevice.labelclear) { - modal.hide = false; - - $("#spinner-" + modal.name + "-" + modal.id + " span").text("Clearing disk label..."); - - setTimeout(function () { - FnStoragePoolDiskLabelClear({ name: pool.name, id: pool.id }, { id: virtualdevice.id, inactive: true }, { silent: false }) - .finally(function () { - $("#modal-" + modal.name + "-" + modal.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: true }); - }, 200); - }); - }, 2000); - } - }) - .fail(function (message, data) { - FnDisplayAlert({ status: "danger", title: "Virtual Device could not be removed from Storage Pool", description: pool.name, breakword: false }, { name: "storagepool-virtualdevice-remove", id: pool.id, timeout: 4 }); - - FnConsole.warn("Storage Pools, Virtual Device, Remove: Failed, Pool: " + pool.name + ", Virtual Device: " + virtualdevice.id + ", Message: " + (data ? data : message)); - }) - .finally(function () { - if (modal.hide) { - $("#modal-" + modal.name + "-" + modal.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: true }); - }, 200); - } - }); -} - -//#endregion - -//#region File Systems - -function FnFileSystemsGet(pool = { name, id }) { - let process = { - command: ["/sbin/zfs", "list", "-H", "-o", "readonly,name,avail,used,usedsnap,usedrefreserv,recordsize,compression,dedup,sharenfs,sharesmb,mountpoint,mounted,origin,encryption,encryptionroot,keyformat,keystatus", "-r", "-p", pool.name] - }; - let filesystems = { - empty: true - }; - - pool.altroot = (($("#tr-storagepool-" + pool.id).attr("data-pool-altroot") == "true") ? true : false); - pool.boot = (($("#tr-storagepool-" + pool.id).attr("data-pool-boot") == "true") ? true : false); - pool.readonly = (($("#tr-storagepool-" + pool.id).attr("data-pool-readonly") == "true") ? true : false); - pool.feature = { - allocation_classes: (($("#tr-storagepool-" + pool.id).attr("data-pool-feature-allocation_classes") == "true") ? true : false), - edonr: (($("#tr-storagepool-" + pool.id).attr("data-pool-feature-edonr") == "true") ? true : false), - encryption: (($("#tr-storagepool-" + pool.id).attr("data-pool-feature-encryption") == "true") ? true : false), - large_blocks: (($("#tr-storagepool-" + pool.id).attr("data-pool-feature-large_blocks") == "true") ? true : false), - large_dnode: (($("#tr-storagepool-" + pool.id).attr("data-pool-feature-large_dnode") == "true") ? true : false), - lz4_compress: (($("#tr-storagepool-" + pool.id).attr("data-pool-feature-lz4_compress") == "true") ? true : false), - sha512: (($("#tr-storagepool-" + pool.id).attr("data-pool-feature-sha512") == "true") ? true : false), - skein: (($("#tr-storagepool-" + pool.id).attr("data-pool-feature-skein") == "true") ? true : false) - }; - - FnConsole.log[2]("File Systems, Get: In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data, message) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Get:" })); - - if (data) { - filesystems.empty = false; - - FnStoragePoolSizeGet({ name: pool.name, id: pool.id }) - .done(function (_data) { - FnConsole.log[4](FnConsoleVerbose({ data: _data, message: "Storage Pools, Size, Get:" })); - - if (_data) { - pool.sizeraw = _data.replace(/\n+/g, ""); - - FnFileSystemsGetCommand({ name: pool.name, id: pool.id, altroot: pool.altroot, boot: pool.boot, feature: { allocation_classes: pool.feature.allocation_classes, edonr: pool.feature.edonr, encryption: pool.feature.encryption, large_blocks: pool.feature.large_blocks, large_dnode: pool.feature.large_dnode, lz4_compress: pool.feature.lz4_compress, sha512: pool.feature.sha512, skein: pool.feature.skein }, readonly: pool.readonly, sizeraw: pool.sizeraw }, { data: data, message: message }); - } - }) - .fail(function () { - FnFileSystemsGetCommand({ name: pool.name, id: pool.id, altroot: pool.altroot, boot: pool.boot, feature: { allocation_classes: pool.feature.allocation_classes, edonr: pool.feature.edonr, encryption: pool.feature.encryption, large_blocks: pool.feature.large_blocks, large_dnode: pool.feature.large_dnode, lz4_compress: pool.feature.lz4_compress, sha512: pool.feature.sha512, skein: pool.feature.skein }, readonly: pool.readonly, sizeraw: null }, { data: data, message: message }); - }); - } - - FnConsole.log[1]("File Systems, Get: Success, Pool: " + pool.name); - }) - .fail(function (message, data) { - FnConsole.warn("File Systems, Get: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); - }) - .finally(function () { - if (filesystems.empty) { - $("#tbody-storagepool-filesystems-" + pool.id).empty(); - $("#tbody-storagepool-filesystems-" + pool.id).append(`No file systems found.`); - $("#modals-storagepool-filesystems-" + pool.id).remove(); - $("#modals-storagepool-filesystem-" + pool.id).remove(); - $("#modals").append(`
    `); - - //Register file systems modals - if (!pool.readonly) { - FnModalFileSystemsCreate({ name: pool.name, id: pool.id, altroot: pool.altroot, feature: { allocation_classes: pool.feature.allocation_classes, edonr: pool.feature.edonr, encryption: pool.feature.encryption, large_blocks: pool.feature.large_blocks, large_dnode: pool.feature.large_dnode, lz4_compress: pool.feature.lz4_compress, sha512: pool.feature.sha512, skein: pool.feature.skein } }); - } - - $("#tr-storagepool-" + pool.id).attr("data-pool-refresh-filesystems", "true"); - - $("#spinner-storagepool-filesystems-" + pool.id).addClass("hidden"); - $("#paneltitle-storagepool-filesystems-" + pool.id).removeClass("hidden").text(FnDateTime()); - $("#btn-storagepool-filesystems-create-" + pool.id).prop("disabled", false); - $("#btn-storagepool-filesystems-refresh-" + pool.id).prop("disabled", false); - } - - FnStoragePoolSpinnerHide({ name: pool.name, id: pool.id }); - FnCockpitElementsUpdate(); - }); -} - -function FnFileSystemsGetCommand(pool = { name, id, altroot: false, boot: false, feature: { allocation_classes: true, edonr: true, encryption: true, large_blocks: true, large_dnode: true, lz4_compress: true, sha512: true, skein: true }, readonly: false, sizeraw: 0 }, process = { data, message }) { - let filesystems = process.data.split(/\n/g).filter(v => v); - - $("#tbody-storagepool-filesystems-" + pool.id).empty(); - $("#modals-storagepool-filesystems-" + pool.id).remove(); - $("#modals-storagepool-filesystem-" + pool.id).remove(); - $("#modals").append(`
    `); - $("#modals").append(`
    `); - - filesystems.forEach((_value, _index) => { - let filesystem = { - properties: _value.split(/\t/g).filter(v => v), - clone: false, - compression: "", - dedup: "", - encryption: false, - encryptionroot: "", - id: "", - keyformat: "", - keystatus: "", - mounted: false, - mountpoint: "", - name: "", - origin: "", - readonly: false, - recordsize: "", - shares: [], - sharenfs: false, - sharesmb: false, - type: "File System", - actionsmenu: { - register: { - samba: {}, - snapshot: {} - } - } - }; - - filesystem.output = ``; - - filesystem.properties.forEach((__value, __index) => { - //0=readonly, 1=name, 2=avail, 3=used, 4=usedsnap, 5=usedrefreserv, 6=recordsize, 7=compression, 8=dedup, 9=sharenfs, 10=sharesmb, 11=mountpoint, 12=mounted, 13=origin, 14=encryption, 15=encryptionroot, 16=keyformat, 17=keystatus - - switch (__index) { - case 0: //0=readonly - if (__value.toLowerCase() == "on" || pool.boot && zfsmanager.configuration.zfs.storagepool.bootlockdown) { - filesystem.readonly = true; - } - - break; - case 1: //1=name - filesystem.name = __value; - filesystem.id = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: filesystem.name, attribute: true }); - - filesystem.output += `Name:` + __value + (filesystem.readonly ? ` ` : ``) + ``; - - break; - case 2: //2=avail - filesystem.output += `Available:` + FnFormatBytes({ base2: true, decimals: 2, value: __value }) + ``; - - break; - case 3: //3=used - filesystem.output += `Used:` + FnFormatBytes({ base2: true, decimals: 2, value: __value }) + ``; - - break; - case 4: //4=usedsnap - filesystem.output += `Snapshots:` + FnFormatBytes({ base2: true, decimals: 2, value: __value }) + ``; - - break; - case 5: //5=usedrefreserv - if (pool.sizeraw) { - filesystem.usedrefreservpercent = FnRound({ decimals: 1, value: (__value / pool.sizeraw) * 100 }); - - __value = FnFormatBytes({ base2: true, decimals: 2, value: __value }); - - if ($.isNumeric(filesystem.usedrefreservpercent) && filesystem.usedrefreservpercent > 0) { - __value += " (" + filesystem.usedrefreservpercent + " %)"; - } - } else { - __value = FnFormatBytes({ base2: true, decimals: 2, value: __value }); - } - - filesystem.output += `Refreservation:` + __value + ``; - - break; - case 6: //6=recordsize - filesystem.recordsize = __value; - - filesystem.output += `Record Size:` + FnFormatBytes({ base2: true, decimals: 0, value: __value }) + ``; - - break; - case 7: //7=compression - filesystem.compression = __value; - - if (/off|on/gi.test(__value)) { - __value = __value.charAt(0).toUpperCase() + __value.slice(1); - } else { - __value = __value.toUpperCase(); - } - - filesystem.output += `Compression:` + __value + ``; - - break; - case 8: //8=dedup - filesystem.dedup = __value; - - if (/sha256|sha512/gi.test(__value)) { - __value = __value.replace(/sha/gi, "SHA-"); - } - if (/off|on|verify|skein/gi.test(__value)) { - __value = __value.charAt(0).toUpperCase() + __value.slice(1); - } - if (/edonr/gi.test(__value)) { - __value = __value.replace(/edonr/gi, "Edon-R"); - } - - filesystem.output += `Deduplication:` + __value.replace(/,verify/g, " + Verify") + ``; - - break; - case 9: //9=sharenfs - filesystem.sharenfs = __value; - - if (__value.toLowerCase() != "off" && __value.toLowerCase() != "-") { - filesystem.sharenfs = true; - filesystem.shares.push("NFS"); - } else { - filesystem.sharenfs = false; - } - - break; - case 10: //10=sharesmb - filesystem.sharesmb = __value; - - if (__value.toLowerCase() == "on") { - filesystem.sharesmb = true; - filesystem.shares.push("SMB"); - } else { - filesystem.sharesmb = false; - } - - if (/off|on/gi.test(__value)) { - __value = __value.charAt(0).toUpperCase() + __value.slice(1); - } else { - __value = __value.toUpperCase(); - } - - filesystem.output += `Share:` + (filesystem.shares.length > 0 ? filesystem.shares.join(" + ") : "Off") + ``; - - break; - case 11: //11=mountpoint - filesystem.mountpoint = __value; - break; - case 12: //12=mounted - if (__value.toLowerCase() == "yes") { - filesystem.mounted = true; - } else { - filesystem.mounted = false; - } - - if (/yes|no/gi.test(__value)) { - __value = __value.charAt(0).toUpperCase() + __value.slice(1); - } - - filesystem.output += `Mounted:` + __value + ``; - - break; - case 13: //13=origin - if (__value != "-") { - filesystem.origin = __value; - filesystem.clone = true; - filesystem.type = "Clone File System"; - } else { - filesystem.clone = false; - filesystem.type = "File System"; - } - - break; - case 14: //14=encryption - if (__value.toLowerCase() != "off") { - filesystem.encryption = true; - } else { - filesystem.encryption = false; - } - - break; - case 15: //15=encryptionroot - filesystem.encryptionroot = __value; - - break; - case 16: //16=keyformat - if (filesystem.encryption && __value.toLowerCase() == "passphrase") { - filesystem.keyformat = "passphrase"; - } - - break; - case 17: //17=keystatus - if (__value != "-") { - filesystem.keystatus = __value; - } else { - filesystem.keystatus = ""; - } - - break; - } - - //Add icons and actions menu at end of array - if (__index >= (filesystem.properties.length - 1)) { - filesystem.icons = { - clone: ``, - keystatus: { - locked: ``, - unlocked: `` - } - }; - - filesystem.output += `Clone:` + (filesystem.clone ? `Yes` + filesystem.icons.clone : `No`) + ``; - filesystem.output += `Encrypted:` + (/available|unavailable/.test(filesystem.keystatus) ? `Yes` : `No`) + ``; - - if (filesystem.keystatus == "unavailable") { - filesystem.output += filesystem.icons.keystatus.locked; - } else if (filesystem.keystatus == "available") { - filesystem.output += filesystem.icons.keystatus.unlocked; - } - - filesystem.output += ``; - - //Actions menu - filesystem.actionsmenu.items = { - itemconfigure: [], - itemconfiguredivider: function () { - if (this.itemconfigure.length > 0 && this.item.length > 0) { - this.itemconfigure.push(this.divider); - } - }, - item: [], - itemdivider: function () { - if (this.item.length > 0 && this.itemencrypted.length > 0) { - this.item.push(this.divider); - } - }, - itemencrypted: [], - itemencrypteddivider: function () { - if ((this.item.length > 0 || this.itemencrypted.length > 0) && (this.itemsamba.length > 0 || this.itemsnapshot.length > 0)) { - this.itemencrypted.push(this.divider); - } - }, - itemsamba: [], - itemsambadivider: function () { - if ((this.item.length > 0 || this.itemencrypted.length > 0) && this.itemsamba.length > 0 && this.itemsnapshot.length > 0) { - this.itemsamba.push(this.divider); - } - }, - itemsnapshot: [], - divider: `` - }; - filesystem.actionsmenu.display = function () { - if (/@/g.test(filesystem.name) == false && (this.items.itemconfigure.length + this.items.item.length + this.items.itemencrypted.length + this.items.itemsamba.length + this.items.itemsnapshot.length) > 0) { - this.items.itemconfiguredivider(); - this.items.itemdivider(); - this.items.itemencrypteddivider(); - this.items.itemsambadivider(); - - return this.header + this.items.itemconfigure.join("\n") + this.items.item.join("\n") + this.items.itemencrypted.join("\n") + this.items.itemsamba.join("\n") + this.items.itemsnapshot.join("\n") + this.footer; - } else { - return ""; - } - }; - filesystem.actionsmenu.header = ` - - `; - - //Configure File System - filesystem.actionsmenu.items.itemconfigure.push(`
  • Configure ` + filesystem.type + `
  • `); - - //Rename File System - if (!pool.readonly && (!filesystem.readonly || filesystem.readonly && !zfsmanager.configuration.zfs.filesystem.readonlylockdown) && filesystem.name != pool.name) { - filesystem.actionsmenu.items.item.push(`
  • Rename ` + filesystem.type + `
  • `); - - filesystem.actionsmenu.register.rename = true; - } - - //Promote Clone File System - if (!pool.readonly && (!filesystem.readonly || filesystem.readonly && !zfsmanager.configuration.zfs.filesystem.readonlylockdown) && filesystem.clone && filesystem.origin.replace(/^(.*)\@.*$/, "$1") != pool.name) { - filesystem.actionsmenu.items.item.push(`
  • Promote ` + filesystem.type + `
  • `); - - filesystem.actionsmenu.register.promote = true; - } - - //Mount File System / Unmount File System - if (!pool.boot || pool.boot && !zfsmanager.configuration.zfs.storagepool.bootlockdown) { - if (!filesystem.mounted && filesystem.keystatus != "unavailable") { - filesystem.actionsmenu.items.item.push(`
  • Mount ` + filesystem.type + `
  • `); - - filesystem.actionsmenu.register.mount = true; - } else if (filesystem.mounted) { - filesystem.actionsmenu.items.item.push(`
  • Unmount ` + filesystem.type + `
  • `); - - filesystem.actionsmenu.register.unmount = true; - } - } - - //Unlock File System / Lock File System - if (filesystem.keystatus == "unavailable" && !filesystem.clone && filesystem.encryptionroot == filesystem.name) { - filesystem.actionsmenu.items.item.push(`
  • Unlock File System
  • `); - - filesystem.actionsmenu.register.unlock = true; - } else if (filesystem.keystatus == "available" && !filesystem.mounted && !filesystem.clone && filesystem.encryptionroot == filesystem.name) { - filesystem.actionsmenu.items.item.push(`
  • Lock File System
  • `); - - filesystem.actionsmenu.register.lock = true; - } - - //Change Passphrase - if (!pool.readonly && (!filesystem.readonly || filesystem.readonly && !zfsmanager.configuration.zfs.filesystem.readonlylockdown) && filesystem.keystatus == "available" && !filesystem.clone && filesystem.encryptionroot == filesystem.name) { - filesystem.actionsmenu.items.itemencrypted.push(`
  • Change Passphrase
  • `); - - filesystem.actionsmenu.register.changepassphrase = true; - } - - //Destroy File System - if (!pool.readonly && (!filesystem.readonly || filesystem.readonly && !zfsmanager.configuration.zfs.filesystem.readonlylockdown) && filesystem.name != pool.name) { - if (!filesystem.clone || filesystem.clone && new RegExp("^" + filesystem.name + "/").test(filesystem.origin.replace(/^(.*)\@.*$/, "$1")) == false) { //Do not display if clone origin is a child file system - will generate recursive dependency error - filesystem.actionsmenu.items.item.push(`
  • Destroy ` + filesystem.type + `
  • `); - - filesystem.actionsmenu.register.destroy = true; - } - } - - //Enable Samba Share - if (!pool.readonly && (!filesystem.readonly || filesystem.readonly && !zfsmanager.configuration.zfs.filesystem.readonlylockdown) && !filesystem.sharesmb && zfsmanager.configuration.samba.manage) { - filesystem.actionsmenu.items.itemsamba.push(`
  • Enable Samba Share
  • `); - - filesystem.actionsmenu.register.samba.enable = true; - } - - //Configure Samba Share - if (filesystem.sharesmb && zfsmanager.configuration.samba.manage) { - filesystem.actionsmenu.items.itemsamba.push(`
  • Configure Samba Share
  • `); - - filesystem.actionsmenu.register.samba.configure = true; - } - - //Disable Samba Share - if (!pool.readonly && (!filesystem.readonly || filesystem.readonly && !zfsmanager.configuration.zfs.filesystem.readonlylockdown) && filesystem.sharesmb && zfsmanager.configuration.samba.manage) { - filesystem.actionsmenu.items.itemsamba.push(`
  • Disable Samba Share
  • `); - - filesystem.actionsmenu.register.samba.disable = true; - } - - //Create Snapshot - if (!pool.readonly && zfsmanager.configuration.zfs.filesystem.snapshotactions) { - filesystem.actionsmenu.items.itemsnapshot.push(`
  • Create Snapshot
  • `); - - filesystem.actionsmenu.register.snapshot.create = true; - } - - filesystem.output += `` + filesystem.actionsmenu.display() + ``; - } - }); - - filesystem.output += ``; - - $("#tbody-storagepool-filesystems-" + pool.id).append(filesystem.output); - - //Register file system modals - FnModalFileSystemConfigure({ name: pool.name, id: pool.id, altroot: pool.altroot, feature: { allocation_classes: pool.feature.allocation_classes, edonr: pool.feature.edonr, large_blocks: pool.feature.large_blocks, large_dnode: pool.feature.large_dnode, lz4_compress: pool.feature.lz4_compress, sha512: pool.feature.sha512, skein: pool.feature.skein }, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, origin: filesystem.origin, type: filesystem.type }); - if (filesystem.actionsmenu.register.changepassphrase) { - FnModalFileSystemChangePassphrase({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }); - } - if (filesystem.actionsmenu.register.destroy) { - FnModalFileSystemDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, sharesmb: filesystem.sharesmb, type: filesystem.type }); - } - if (filesystem.actionsmenu.register.lock) { - FnModalFileSystemLock({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, type: filesystem.type }); - } - if (filesystem.actionsmenu.register.mount) { - FnModalFileSystemMount({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, sharesmb: filesystem.sharesmb, type: filesystem.type }); - } - if (filesystem.actionsmenu.register.promote) { - FnModalFileSystemPromote({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, origin: filesystem.origin, type: filesystem.type }); - } - if (filesystem.actionsmenu.register.rename) { - FnModalFileSystemRename({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: filesystem.name, id: filesystem.id, clone: filesystem.clone, encryption: filesystem.encryption, encryptionroot: filesystem.encryptionroot, origin: filesystem.origin, sharesmb: filesystem.sharesmb, type: filesystem.type }); - } - if (filesystem.actionsmenu.register.samba.configure) { - FnModalFileSystemSambaConfigure({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, mountpoint: filesystem.mountpoint }); - } - if (filesystem.actionsmenu.register.samba.disable) { - FnModalFileSystemSambaDisable({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, type: filesystem.type }); - } - if (filesystem.actionsmenu.register.samba.enable) { - FnModalFileSystemSambaEnable({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, mounted: filesystem.mounted, mountpoint: filesystem.mountpoint }); - } - if (filesystem.actionsmenu.register.snapshot.create) { - FnModalFileSystemSnapshotCreate({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }); - } - if (filesystem.actionsmenu.register.unlock) { - FnModalFileSystemUnlock({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, sharesmb: filesystem.sharesmb, type: filesystem.type }); - } - if (filesystem.actionsmenu.register.unmount) { - FnModalFileSystemUnmount({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, encryptionroot: filesystem.encryptionroot, keystatus: filesystem.keystatus, sharesmb: filesystem.sharesmb, type: filesystem.type }); - } - }); - - //Register file systems modals - if (!pool.readonly) { - FnModalFileSystemsCreate({ name: pool.name, id: pool.id, altroot: pool.altroot, feature: { allocation_classes: pool.feature.allocation_classes, edonr: pool.feature.edonr, encryption: pool.feature.encryption, large_blocks: pool.feature.large_blocks, large_dnode: pool.feature.large_dnode, lz4_compress: pool.feature.lz4_compress, sha512: pool.feature.sha512, skein: pool.feature.skein } }); - } - - $("#tr-storagepool-" + pool.id).attr("data-pool-refresh-filesystems", "true"); - - $("#spinner-storagepool-filesystems-" + pool.id).addClass("hidden"); - $("#paneltitle-storagepool-filesystems-" + pool.id).removeClass("hidden").html(FnDateTime() + (zfsmanager.configuration.zfs.storagepool.count ? ` ` + filesystems.length + `` : ``)); - $("#btn-storagepool-filesystems-create-" + pool.id).prop("disabled", false); - $("#btn-storagepool-filesystems-refresh-" + pool.id).prop("disabled", false); - - FnStoragePoolSpinnerHide({ name: pool.name, id: pool.id }); - FnCockpitElementsUpdate(); -} - -function FnFileSystemsLockedGet() { - let filesystems = { - id: [] - }; - let process = { - command: ["/sbin/zfs", "list", "-H", "-o", "name,encryption,encryptionroot,keyformat,keystatus", "-r", "-t", "filesystem"] - }; - - $("#listgroup-storagepools-filesystems-unlock-filesystems").empty().append(`
  • `); - - FnConsole.log[2]("File Systems, Locked, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Locked, Get:" })); - - filesystems.id = data.split(/\n/g).filter(v => { - if (!zfsmanager.configuration.zfs.storagepool.boot && zfsmanager.zfs.storagepool.boot && new RegExp("^" + zfsmanager.zfs.storagepool.boot + "\t|^" + zfsmanager.zfs.storagepool.boot + "/").test(v)) { - //Do not display boot - } else if (!zfsmanager.configuration.zfs.storagepool.root && zfsmanager.zfs.storagepool.root && new RegExp("^" + zfsmanager.zfs.storagepool.root + "\t|^" + zfsmanager.zfs.storagepool.root + "/").test(v)) { - //Do not display root - } else { - return v; - } - }); - - filesystems.id.forEach((_value, _index) => { - let filesystem = { - properties: _value.split(/\t/g).filter(v => v) - }; - - filesystem.name = filesystem.properties[0]; - filesystem.encryption = filesystem.properties[1]; - filesystem.encryptionroot = filesystem.properties[2]; - filesystem.keyformat = filesystem.properties[3]; - filesystem.keystatus = filesystem.properties[4]; - - if (filesystem.encryptionroot == filesystem.name && filesystem.keyformat == "passphrase" && filesystem.keystatus == "unavailable") { - filesystems.output = ` - - `; - - $("#listgroup-storagepools-filesystems-unlock-filesystems").append(filesystems.output); - } - }); - - setTimeout(function () { - $("#spinner-storagepools-filesystems-unlock-filesystems").remove(); - $("#listgroup-storagepools-filesystems-unlock-filesystems > li").removeClass("hidden"); - if ($("#helpblock-storagepools-filesystems-unlock-filesystems-warning").text()) { - $("#helpblock-storagepools-filesystems-unlock-filesystems-warning").removeClass("hidden"); - } - - if ($("#listgroup-storagepools-filesystems-unlock-filesystems > li").length == 0) { - filesystems.output = ` -
  • - -
  • - `; - - $("#listgroup-storagepools-filesystems-unlock-filesystems").append(filesystems.output); - } - }, 200); - - FnConsole.log[1]("File Systems, Locked, Get: Success"); - }) - .fail(function (message, data) { - $("#spinner-storagepools-filesystems-unlock-filesystems").remove(); - $("#listgroup-storagepools-filesystems-unlock-filesystems > li").removeClass("hidden"); - - if ($("#listgroup-storagepools-filesystems-unlock-filesystems > li").length == 0) { - filesystems.output = ` -
  • - -
  • - `; - - $("#listgroup-storagepools-filesystems-unlock-filesystems").append(filesystems.output); - } - - FnConsole.warn("File Systems, Locked, Get: Failed, Message: " + (data ? data : message)); - }); -} - -function FnFileSystemsMountedGet(pool = { name, id }, filesystem = { name, id }, modal = { alert: { id, mount: true } }) { - let process = { - command: ["/sbin/zfs", "list", "-H", "-o", "name,mounted", "-r", "-t", "filesystem", filesystem.name] - }; - - filesystem.children = { - mounted: false - } - - FnConsole.log[2]("File Systems, Mounted, Get: In Progress: Success, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Mounted, Get:" })); - - let filesystems = data.split(/\n/g).filter((v, i) => v && i > 0); - - filesystems.forEach((_value, _index) => { - filesystem.properties = _value.split(/\t/g).filter(v => v); - - if (filesystem.properties[1] == "yes" && !filesystem.children.mount) { - filesystem.children.mounted = true; - } - }); - - if (filesystem.children.mounted) { - modal.alert.id.html(FnDisplayInlineAlert({ status: "warning", title: "There are child file systems currently mounted. " + (modal.alert.mount ? "Mounting" : "Unmounting") + " this file system may adversely affect the child file systems.", description: null }, { name: null, id: null, hidden: false })); - } - - FnConsole.log[1]("File Systems, Mounted, Get: Success, Pool: " + pool.name); - }) - .fail(function (message, data) { - FnConsole.warn("File Systems, Mounted, Get: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); - }); -} - -function FnFileSystemsNamesGet(pool = { name, id }, filesystem = { existing: { name, clone: false, encryption: false, encryptionroot, origin }, override: false }, modal = { dropdown: { id, selected } }) { - let process = { - command: ["/sbin/zfs", "list", "-H", "-o", "name,encryption,encryptionroot,keystatus", "-r", "-t", "filesystem", pool.name] - }; - - FnConsole.log[2]("File Systems, Names, Get: In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Names, Get:" })); - - let filesystems = data.split(/\n/g).filter(v => v); - - modal.dropdown.items = []; - - modal.dropdown.id.empty(); - - filesystems.forEach((_value, _index) => { - filesystem.properties = _value.split(/\t/g).filter(v => v); - filesystem.name = filesystem.properties[0]; - filesystem.encryption = (filesystem.properties[1].toLowerCase() != "off" ? true : false); - filesystem.encryptionroot = (filesystem.properties[2] && filesystem.properties[2] != "-" ? filesystem.properties[2] : ""); - filesystem.encryptionstatus = ""; - filesystem.existing.regexp = { - name: new RegExp("^" + filesystem.existing.name + "/", "g") - }; - filesystem.keystatus = filesystem.properties[3].toLowerCase(); - - if (filesystem.encryption && /^available$|^unavailable$/.test(filesystem.keystatus)) { - filesystem.encryptionstatus = `` - } - - modal.dropdown.add = false; - modal.dropdown.item = `
  • ` + filesystem.name + filesystem.encryptionstatus + `
  • `; - - if ((filesystem.override || filesystem.existing.encryption) && filesystem.existing.clone) { //Encrypted clone file systems can only move within origin and child file systems - filesystem.existing.regexp.origin = new RegExp("^" + filesystem.existing.origin.replace(/^(.*)\@.*$/, "$1\/"), "g"); - - if (filesystem.name == filesystem.existing.origin.replace(/^(.*)\@.*$/, "$1")) { //Origin file system - modal.dropdown.add = true; - } else if (filesystem.name == filesystem.existing.name.replace(/\/[^\/]+$/, "")) { //File System parent - modal.dropdown.add = true; - } else if (filesystem.name != filesystem.existing.name && filesystem.existing.regexp.origin.test(filesystem.name) && !filesystem.existing.regexp.name.test(filesystem.name)) { //Origin child file systems - modal.dropdown.add = true; - } - } else if (filesystem.override || filesystem.existing.encryption) { //Encrypted file systems that are their own encryption root can move anywhere, child file system of the encryption root can only move within encryption root and its child file systems - if (filesystem.name != filesystem.existing.name && !filesystem.existing.regexp.name.test(filesystem.name)) { - if (filesystem.existing.name == filesystem.existing.encryptionroot) { //File system is its own encryption root - modal.dropdown.add = true; - } else if (filesystem.encryptionroot == filesystem.existing.encryptionroot) { //File system is a child of the encryption root - modal.dropdown.add = true; - } - } - } else { //Unencrypted file systems can only move to unencrypted file systems - if (!filesystem.encryption && filesystem.name != filesystem.existing.name && !filesystem.existing.regexp.name.test(filesystem.name)) { - modal.dropdown.add = true; - } - } - - if (modal.dropdown.add) { - modal.dropdown.items.push(modal.dropdown.item); - } - }); - - modal.dropdown.id.append(modal.dropdown.items.join("\n")); - - FnConsole.log[1]("File Systems, Names, Get: Success, Pool: " + pool.name); - }) - .fail(function (message, data) { - FnConsole.warn("File Systems, Names, Get: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); - }); -} - -function FnFileSystemsUnlock(filesystems = { id: [] }, filesystem = { mount: true, overlay: true, passphrase }, modal = { name, id }) { - let promise = Promise.resolve(); - - filesystems.count = { - available: 0, - error: 0, - success: 0 - }; - - $("#listgroup-" + modal.name + modal.id + "-filesystems > li.list-group-item > label > span.pficon").removeClass("list-group-ct-warning"); - - if (filesystems.id.length > 0) { - FnConsole.log[2]("File Systems, Unlock: In Progress"); - - $("#spinner-" + modal.name + modal.id + " span").text("Unlocking file system" + (filesystems.id.length > 1 ? "s" : "") + "..."); - - filesystems.id.forEach((_value, _index) => { - promise = promise.then(_ => new Promise(resolve => - setTimeout(function () { - let pool = { - name: _value.replace(/\/.*$/, ""), - id: FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: _value.replace(/\/.*$/, ""), attribute: true }) - }; - - filesystem.name = _value; - filesystem.id = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: _value, attribute: true }); - - FnFileSystemUnlock({ name: pool.name, id: pool.id, altroot: false, readonly: false }, { name: filesystem.name, id: filesystem.id, mount: filesystem.mount, overlay: filesystem.overlay, passphrase: filesystem.passphrase, type: "File System" }, { enable: false }, { name: modal.name, id: modal.id }, { refresh: false }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Unlock:" })); - - if (/error|Incorrect key/i.test(data)) { - filesystems.count.error++; - - $("#listgroup-" + modal.name + modal.id + "-filesystems > li.list-group-item[data-filesystem-name='" + filesystem.name + "'] > label > span.pficon").addClass("list-group-ct-warning"); - } else { - filesystems.count.success++; - - $("#listgroup-" + modal.name + modal.id + "-filesystems > li.list-group-item[data-filesystem-name='" + filesystem.name + "']").remove(); - } - }) - .fail(function (message, data) { - if (/Key already loaded/i.test(data)) { - filesystems.count.success++; - - $("#listgroup-" + modal.name + modal.id + "-filesystems > li.list-group-item[data-filesystem-name='" + filesystem.name + "']").remove(); - } else { - filesystems.count.error++; - - $("#listgroup-" + modal.name + modal.id + "-filesystems > li.list-group-item[data-filesystem-name='" + filesystem.name + "'] > label > span.pficon").addClass("list-group-ct-warning"); - } - }) - .finally(function () { - if (_index == (filesystems.id.length - 1)) { - $("#listgroup-storagepools-filesystems-unlock-filesystems input[name='checkbox-storagepools-filesystems-unlock-filesystems']").map(function () { - filesystems.count.available++; - }); - - if (filesystems.count.error == 0) { - FnConsole.log[1]("File Systems, Unlock: Success"); - } else { - FnConsole.warn("File Systems, Unlock: Failed"); - } - - if (filesystems.count.available == 0) { - $("#modal-" + modal.name + modal.id).modal("hide"); - } else { - $("#spinner-" + modal.name + modal.id).addClass("hidden"); - $("#spinner-" + modal.name + modal.id + " span").text(""); - $("#btn-" + modal.name + "-apply" + modal.id).prop("disabled", false); - } - - setTimeout(function () { - FnStoragePoolsGet(); - }, 1000); - } - }); - - resolve(); - }, 1000) - )); - }); - } else { - $("#modal-" + modal.name + modal.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolsGet(); - }, 1000); - } -} - -//#endregion - -//#region File System - -function FnFileSystemChangePassphrase(pool = { name, id }, filesystem = { name, id, passphrase }) { - let process = { - command: [] - }; - - if (!filesystem.passphrase || filesystem.passphrase.length < 8) { - FnFileSystemChangePassphraseFail({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }, { data: "Passphrase requires a minimum of 8 characters.", message: null }); - return; - } - - //Escape percentage and single quote special character for printf - if (/\%/g.test(filesystem.passphrase)) { - filesystem.passphrase = filesystem.passphrase.replace(/\%/g, "\%\%"); - } - if (/\'/g.test(filesystem.passphrase)) { - filesystem.passphrase = filesystem.passphrase.replace(/\'/g, "\'\"\'\"\'"); - } - - process.command = ["/bin/sh", "-c", "printf '" + filesystem.passphrase + "' | /sbin/zfs change-key \"" + filesystem.name + "\""]; - - FnConsole.log[2]("File Systems, Change Passphrase: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-storagepool-filesystem-changepassphrase-" + filesystem.id + " span").text("Changing passphrase..."); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function (data, message) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Change Passphrase:" })); - - if (/error|Key must be loaded/i.test(data)) { - FnFileSystemChangePassphraseFail({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }, { data: data, message: message }); - return; - } - - FnDisplayAlert({ status: "success", title: "File System passphrase successfully changed", description: filesystem.name, breakword: false }, { name: "filesystem-changepassphrase", id: filesystem.id, timeout: 4 }); - - FnConsole.log[1]("File Systems, Change Passphrase: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - - $("#modal-storagepool-filesystem-changepassphrase-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - }) - .fail(function (message, data) { - FnFileSystemChangePassphraseFail({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }, { data: data, message: message }); - }); -} - -function FnFileSystemChangePassphraseFail(pool = { name, id }, filesystem = { name, id }, process = { data, message }) { - let modal = { - hide: true - }; - - if (/Passphrase requires a minimum of 8 characters./i.test(process.data)) { - modal.hide = false; - - $("#validationwrapper-storagepool-filesystem-changepassphrase-passphrase-" + filesystem.id).addClass("has-error"); - $("#helpblock-storagepool-filesystem-changepassphrase-passphrase-" + filesystem.id).addClass("has-error").removeClass("hidden").text("Passphrase requires a minimum of 8 characters."); - $("#input-storagepool-filesystem-changepassphrase-passphrase-" + filesystem.id).focus(); - } else if (/Key must be loaded/i.test(process.data)) { - modal.hide = false; - - $("#validationwrapper-storagepool-filesystem-changepassphrase-filesystem-" + filesystem.id).addClass("has-error"); - $("#helpblock-storagepool-filesystem-changepassphrase-filesystem-" + filesystem.id).addClass("has-error").removeClass("hidden").text("File System is locked."); - $("#input-storagepool-filesystem-changepassphrase-filesystem-" + filesystem.id).focus(); - } else if (/encryption failure/i.test(process.data)) { //Error message when pool is read only - modal.hide = true; - } else if (/error/i.test(process.data)) { - modal.hide = false; - - $("#validationwrapper-storagepool-filesystem-changepassphrase-passphrase-" + filesystem.id).addClass("has-error"); - $("#helpblock-storagepool-filesystem-changepassphrase-passphrase-" + filesystem.id).addClass("has-error").removeClass("hidden").text("Passphrase is incorrect."); - $("#input-storagepool-filesystem-changepassphrase-passphrase-" + filesystem.id).focus(); - } - - if (!modal.hide) { - $("#spinner-storagepool-filesystem-changepassphrase-" + filesystem.id).addClass("hidden"); - $("#spinner-storagepool-filesystem-changepassphrase-" + filesystem.id + " span").text(""); - $("#btn-storagepool-filesystem-changepassphrase-apply-" + filesystem.id).prop("disabled", false); - } - - FnConsole.warn("File Systems, Change Passphrase: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (process.data ? process.data : process.message)); - - if (modal.hide) { - FnDisplayAlert({ status: "danger", title: "File System passphrase could not be changed", description: filesystem.name, breakword: false }, { name: "filesystem-changepassphrase", id: filesystem.id, timeout: 4 }); - - $("#modal-storagepool-filesystem-changepassphrase-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - } -} - -function FnFileSystemChildDatasetsGet(pool = { name, id }, filesystem = { name, id, clones: true }, modal = { name, id }) { - let process = { - command: ["/sbin/zfs", "list", "-H", "-o", "name,clones", "-r", "-t", "filesystem,snapshot", filesystem.name] - }; - - FnConsole.log[2]("File Systems, Child, Datasets, Get: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Child, Datasets, Get:" })); - - data = data.split(/\n/g).filter(v => v); - - let filesystems = { - id: [] - }; - let snapshots = { - id: [] - }; - - if (data.length > 0) { - data.forEach((_value, _index) => { - let dataset = { - properties: _value.split(/\t/g).filter(v => v) - }; - - dataset.name = dataset.properties[0]; - dataset.clones = (dataset.properties[1] ? dataset.properties[1] : ""); - - if (new RegExp("^" + filesystem.name + ".*@").test(dataset.name)) { - snapshots.id.push(dataset.name); - - if (dataset.clones && filesystem.clones) { - dataset.clones = dataset.clones.split(",").filter(v => v); - - dataset.clones.forEach((_value, _index) => { - filesystems.id.push(_value); - }); - } - - } else if (new RegExp("^" + filesystem.name + ".*@").test(dataset.name) == false) { - filesystems.id.push(dataset.name); - } - }); - } - - filesystems.id.sort(); - snapshots.id.sort(); - - FnConsole.log[1]("File Systems, Child, Datasets, Get: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - - FnFileSystemChildFileSystemsGet({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }, { id: filesystems.id }, { name: modal.name, id: modal.id }); - FnFileSystemChildSnapshotsGet({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }, { id: filesystems.id }, { name: modal.name, id: modal.id }); - }) - .fail(function (message, data) { - FnConsole.warn("File Systems, Child, Datasets, Get: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); - }); -} - -function FnFileSystemChildFileSystemsGet(pool = { name, id }, filesystem = { name, id }, filesystems = { id: [] }, modal = { name, id }) { - let process = { - command: ["/sbin/zfs", "list", "-H", "-o", "name", "-r", "-t", "filesystem"] - }; - - filesystems.id.forEach(_value => _value && process.command.push(_value)); - - FnConsole.log[2]("File Systems, Child, File Systems, Get: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Child, File Systems, Get:" })); - - let filesystems = { - id: data.split(/\n/g).filter(v => v), - count: { - filesystems: 0, - filesystemswithclones: 0 - } - }; - - if (filesystems.id.length > 0) { - filesystems.id.forEach((_value, _index) => { - if (new RegExp("^" + filesystem.name + "/").test(_value)) { - filesystems.count.filesystems++; - - $("#ul-" + modal.name + "-child-filesystems-" + modal.id).append("
  • " + _value + "
  • \n"); - } - - if (_value != filesystem.name) { - filesystems.count.filesystemswithclones++; - - $("#ul-" + modal.name + "-child-filesystemswithclones-" + modal.id).append("
  • " + _value + "
  • \n"); - } - }); - - $("#panelgroup-" + modal.name + "-" + modal.id).attr("data-filesystem-child-filesystems", filesystems.count.filesystems); - $("#panelgroup-" + modal.name + "-" + modal.id).attr("data-filesystem-child-filesystemswithclones", filesystems.count.filesystemswithclones); - } - - FnConsole.log[1]("File Systems, Child, File Systems, Get: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - }) - .fail(function (message, data) { - FnConsole.warn("File Systems, Child, File Systems, Get: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); - }); -} - -function FnFileSystemChildSnapshotsGet(pool = { name, id }, filesystem = { name, id }, snapshots = { id: [] }, modal = { name, id }) { - let process = { - command: ["/sbin/zfs", "list", "-H", "-o", "name", "-r", "-t", "snapshot"] - }; - - snapshots.id.forEach(_value => _value && process.command.push(_value)); - - FnConsole.log[2]("File Systems, Child, Snapshots, Get: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Child, Snapshots, Get:" })); - - let snapshots = { - id: data.split(/\n/g).filter(v => v), - count: { - snapshots: 0, - snapshotswithclones: 0 - } - }; - - if (snapshots.id.length > 0) { - snapshots.id.forEach((_value, _index) => { - if (new RegExp("^" + filesystem.name + ".*@").test(_value)) { - snapshots.count.snapshots++; - - $("#ul-" + modal.name + "-child-snapshots-" + modal.id).append("
  • " + _value + "
  • \n"); - } - - snapshots.count.snapshotswithclones++; - - $("#ul-" + modal.name + "-child-snapshotswithclones-" + modal.id).append("
  • " + _value + "
  • \n"); - }); - - $("#panelgroup-" + modal.name + "-" + modal.id).attr("data-filesystem-child-snapshots", snapshots.count.snapshots); - $("#panelgroup-" + modal.name + "-" + modal.id).attr("data-filesystem-child-snapshotswithclones", snapshots.count.snapshotswithclones); - } - - FnConsole.log[1]("File Systems, Child, Snapshots, Get: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - }) - .fail(function (message, data) { - FnConsole.warn("File Systems, Child, Snapshots, Get: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); - }); -} - -function FnFileSystemConfigurationGet(pool = { name, id, readonly: false }, filesystem = { name, id }, modal = { name, id }) { - let process = { - command: ["/sbin/zfs", "get", "readonly,aclinherit,acltype,atime,available,canmount,casesensitivity,checksum,compression,context,dedup,dnodesize,defcontext,encryption,encryptionroot,fscontext,guid,mountpoint,quota,recordsize,refreservation,rootcontext,sharenfs,sharesmb,special_small_blocks,used,xattr", "-H", "-o", "property,value,source", "-p", filesystem.name] - }; - - if (!zfsmanager.user.admin) { - pool.readonly = true; - } - - filesystem.available = ""; - filesystem.context = false; - filesystem.fscontext = false; - filesystem.defcontext = false; - filesystem.readonly = false; - filesystem.rootcontext = false; - - FnConsole.log[2]("File Systems, Configuration, Get: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Configuration, Get:" })); - - process.data = data.replace(/\t+/g, "\u22C5").split(/\n/g).filter(v => v); - - process.data.forEach((_value, _index) => { - _value = _value.split("\u22C5"); - - filesystem.properties = { - property: _value[0].toLowerCase(), - value: _value[1].toLowerCase(), - valueraw: _value[1], - source: _value[2] - }; - - let size = {}; - - switch (filesystem.properties.property) { - case "aclinherit": //Default is restricted - filesystem.property = { - value: "Restricted", - valueinherited: "" - }; - - switch (filesystem.properties.value) { - case "discard": - filesystem.property.value = "Discard"; - break; - case "noallow": - filesystem.property.value = "No Allow"; - break; - case "restricted": - filesystem.property.value = "Restricted"; - break; - case "passthrough": - filesystem.property.value = "Passthrough"; - break; - case "passthrough-x": - filesystem.property.value = "Passthrough-X"; - break; - default: - filesystem.property.value = "Restricted"; - break; - } - - if (/^inherited/gi.test(filesystem.properties.source)) { - filesystem.property.source = "inherited"; - filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; - - $("#dropdown-" + modal.name + "-aclinherit-" + modal.id + " li[value='Inherited']").removeClass("hidden"); - $("#dropdown-" + modal.name + "-aclinherit-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); - } else if (/^default|^local/gi.test(filesystem.properties.source)) { - $("#dropdown-" + modal.name + "-aclinherit-" + modal.id + " li[value='InheritedReset']").removeClass("hidden"); - - if (/^default/gi.test(filesystem.properties.source)) { - filesystem.property.source = "default"; - filesystem.property.valueinherited = "Default (Restricted)"; - - $("#dropdown-" + modal.name + "-aclinherit-" + modal.id + " li[value='InheritedReset'] a").text(filesystem.property.valueinherited); - } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name == pool.name) { - filesystem.property.source = "local"; - - $("#dropdown-" + modal.name + "-aclinherit-" + modal.id + " li[value='InheritedReset'] a").text("Default (Restricted)"); - } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name != pool.name) { - filesystem.property.source = "local"; - - FnFileSystemConfigurationInheritedPropertyGet({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, property: "aclinherit" }, { name: modal.name, id: modal.id }); - } - } - - $("#btnspan-" + modal.name + "-aclinherit-" + modal.id).text((filesystem.property.valueinherited ? filesystem.property.valueinherited : filesystem.property.value)).attr("data-field-value", filesystem.properties.valueraw).attr("data-field-source", filesystem.property.source); - $("#dropdown-" + modal.name + "-aclinherit-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-aclinherit-" + modal.id + " li[value='" + (filesystem.property.valueinherited ? (filesystem.property.source == "inherited" ? "Inherited" : "InheritedReset") : filesystem.properties.valueraw) + "']").addClass("active"); - - if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { - $("#div-" + modal.name + "-aclinherit-dropdown-" + modal.id + " button").prop("disabled", true); - } - - break; - case "acltype": //Default is off - filesystem.property = { - value: "Off", - valueinherited: "" - }; - - switch (filesystem.properties.value) { - case "off": - filesystem.property.value = "Off"; - break; - case "noacl": - filesystem.property.value = "No ACL"; - break; - case "posixacl": - filesystem.property.value = "POSIX ACL"; - break; - default: - filesystem.property.value = "Off"; - break; - } - - if (/^inherited/gi.test(filesystem.properties.source)) { - filesystem.property.source = "inherited"; - filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; - - $("#dropdown-" + modal.name + "-acltype-" + modal.id + " li[value='Inherited']").removeClass("hidden"); - $("#dropdown-" + modal.name + "-acltype-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); - } else if (/^default|^local/gi.test(filesystem.properties.source)) { - $("#dropdown-" + modal.name + "-acltype-" + modal.id + " li[value='InheritedReset']").removeClass("hidden"); - - if (/^default/gi.test(filesystem.properties.source)) { - filesystem.property.source = "default"; - filesystem.property.valueinherited = "Default (Off)"; - - $("#dropdown-" + modal.name + "-acltype-" + modal.id + " li[value='InheritedReset'] a").text(filesystem.property.valueinherited); - } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name == pool.name) { - filesystem.property.source = "local"; - - $("#dropdown-" + modal.name + "-acltype-" + modal.id + " li[value='InheritedReset'] a").text("Default (Off)"); - } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name != pool.name) { - filesystem.property.source = "local"; - - FnFileSystemConfigurationInheritedPropertyGet({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, property: "acltype" }, { name: modal.name, id: modal.id }); - } - } - - $("#btnspan-" + modal.name + "-acltype-" + modal.id).text((filesystem.property.valueinherited ? filesystem.property.valueinherited : filesystem.property.value)).attr("data-field-value", filesystem.properties.valueraw).attr("data-field-source", filesystem.property.source); - $("#dropdown-" + modal.name + "-acltype-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-acltype-" + modal.id + " li[value='" + (filesystem.property.valueinherited ? (filesystem.property.source == "inherited" ? "Inherited" : "InheritedReset") : filesystem.properties.valueraw) + "']").addClass("active"); - - if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { - $("#div-" + modal.name + "-acltype-dropdown-" + modal.id + " button").prop("disabled", true); - } - break; - case "atime": //Default is on - filesystem.property = { - source: "", - value: "On", - valueinherited: "" - }; - - switch (filesystem.properties.value) { - case "off": - filesystem.property.value = "Off"; - break; - case "on": - filesystem.property.value = "On"; - break; - default: - filesystem.property.value = "On"; - break; - } - - if (/^inherited/gi.test(filesystem.properties.source)) { - filesystem.property.source = "inherited"; - filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; - - $("#dropdown-" + modal.name + "-atime-" + modal.id + " li[value='Inherited']").removeClass("hidden"); - $("#dropdown-" + modal.name + "-atime-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); - } else if (/^default|^local/gi.test(filesystem.properties.source)) { - $("#dropdown-" + modal.name + "-atime-" + modal.id + " li[value='InheritedReset']").removeClass("hidden"); - - if (/^default/gi.test(filesystem.properties.source)) { - filesystem.property.source = "default"; - filesystem.property.valueinherited = "Default (On)"; - - $("#dropdown-" + modal.name + "-atime-" + modal.id + " li[value='InheritedReset'] a").text(filesystem.property.valueinherited); - } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name == pool.name) { - filesystem.property.source = "local"; - - $("#dropdown-" + modal.name + "-atime-" + modal.id + " li[value='InheritedReset'] a").text("Default (On)"); - } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name != pool.name) { - filesystem.property.source = "local"; - - FnFileSystemConfigurationInheritedPropertyGet({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, property: "atime" }, { name: modal.name, id: modal.id }); - } - } - - $("#btnspan-" + modal.name + "-atime-" + modal.id).text((filesystem.property.valueinherited ? filesystem.property.valueinherited : filesystem.property.value)).attr("data-field-value", filesystem.properties.valueraw).attr("data-field-source", filesystem.property.source); - $("#dropdown-" + modal.name + "-atime-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-atime-" + modal.id + " li[value='" + (filesystem.property.valueinherited ? (filesystem.property.source == "inherited" ? "Inherited" : "InheritedReset") : filesystem.properties.valueraw) + "']").addClass("active"); - - if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { - $("#div-" + modal.name + "-atime-dropdown-" + modal.id + " button").prop("disabled", true); - } - break; - case "available": - filesystem.available = filesystem.properties.value; - - filesystem.property = { - value: "0 B" - }; - - if (filesystem.properties.value == "none" || filesystem.properties.value == "0" || filesystem.properties.value == "0b") { - filesystem.property.value = "0 B"; - } else { - filesystem.property.value = FnFormatBytes({ base2: true, decimals: 2, value: filesystem.properties.value }); - } - - $("#helpblock-" + modal.name + "-available-" + modal.id).text("Available size: " + filesystem.property.value); - break; - case "canmount": //Default is on - filesystem.property = { - value: "On" - }; - - switch (filesystem.properties.value) { - case "on": - filesystem.property.value = "On"; - break; - case "off": - filesystem.property.value = "Off"; - break; - case "noauto": - filesystem.property.value = "No Auto"; - break; - default: - filesystem.property.value = "On"; - break; - } - - $("#btnspan-" + modal.name + "-canmount-" + modal.id).text(filesystem.property.value).attr("data-field-value", filesystem.properties.value); - $("#dropdown-" + modal.name + "-canmount-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-canmount-" + modal.id + " li[value='" + filesystem.properties.valueraw + "']").addClass("active"); - - if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { - $("#div-" + modal.name + "-canmount-dropdown-" + modal.id + " button").prop("disabled", true); - } - break; - case "casesensitivity": //Default is sensitive - $("#div-" + modal.name + "-casesensitivity-" + modal.id).text(filesystem.properties.value.charAt(0).toUpperCase() + filesystem.properties.value.slice(1)); - break; - case "checksum": //Default is on - filesystem.property = { - value: "On", - valueinherited: "" - }; - - switch (filesystem.properties.value) { - case "on": - filesystem.property.value = "On"; - break; - case "off": - filesystem.property.value = "Off"; - break; - case "edonr": - filesystem.property.value = "Edon-R"; - break; - case "fletcher2": - filesystem.property.value = "Fletcher2"; - break; - case "fletcher4": - filesystem.property.value = "Fletcher4"; - break; - case "noparity": - filesystem.property.value = "No Parity"; - break; - case "sha256": - filesystem.property.value = "SHA-256"; - break; - case "sha512": - filesystem.property.value = "SHA-512"; - break; - case "skein": - filesystem.property.value = "Skein"; - break; - default: - filesystem.property.value = "On"; - break; - } - - if (/^inherited/gi.test(filesystem.properties.source)) { - filesystem.property.source = "inherited"; - filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; - - $("#dropdown-" + modal.name + "-checksum-" + modal.id + " li[value='Inherited']").removeClass("hidden"); - $("#dropdown-" + modal.name + "-checksum-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); - } else if (/^default|^local/gi.test(filesystem.properties.source)) { - $("#dropdown-" + modal.name + "-checksum-" + modal.id + " li[value='InheritedReset']").removeClass("hidden"); - - if (/^default/gi.test(filesystem.properties.source)) { - filesystem.property.source = "default"; - filesystem.property.valueinherited = "Default (On)"; - - $("#dropdown-" + modal.name + "-checksum-" + modal.id + " li[value='InheritedReset'] a").text(filesystem.property.valueinherited); - } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name == pool.name) { - filesystem.property.source = "local"; - - $("#dropdown-" + modal.name + "-checksum-" + modal.id + " li[value='InheritedReset'] a").text("Default (On)"); - } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name != pool.name) { - filesystem.property.source = "local"; - - FnFileSystemConfigurationInheritedPropertyGet({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, property: "checksum" }, { name: modal.name, id: modal.id }); - } - } - - $("#btnspan-" + modal.name + "-checksum-" + modal.id).text((filesystem.property.valueinherited ? filesystem.property.valueinherited : filesystem.property.value)).attr("data-field-value", filesystem.properties.valueraw).attr("data-field-source", filesystem.property.source); - $("#dropdown-" + modal.name + "-checksum-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-checksum-" + modal.id + " li[value='" + (filesystem.property.valueinherited ? (filesystem.property.source == "inherited" ? "Inherited" : "InheritedReset") : filesystem.properties.valueraw) + "']").addClass("active"); - - if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { - $("#div-" + modal.name + "-checksum-dropdown-" + modal.id + " button").prop("disabled", true); - } - break; - case "compression": //Default is off - filesystem.property = { - value: "Off", - valueinherited: "" - }; - - switch (filesystem.properties.value) { - case "on": - filesystem.property.value = "On"; - break; - case "gzip": - filesystem.property.value = "GZIP"; - break; - case "lz4": - filesystem.property.value = "LZ4"; - break; - case "lzjb": - filesystem.property.value = "LZJB"; - break; - case "zle": - filesystem.property.value = "ZLE"; - break; - default: - filesystem.property.value = "Off"; - break; - } - - if (/^inherited/gi.test(filesystem.properties.source)) { - filesystem.property.source = "inherited"; - filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; - - $("#dropdown-" + modal.name + "-compression-" + modal.id + " li[value='Inherited']").removeClass("hidden"); - $("#dropdown-" + modal.name + "-compression-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); - } else if (/^default|^local/gi.test(filesystem.properties.source)) { - $("#dropdown-" + modal.name + "-compression-" + modal.id + " li[value='InheritedReset']").removeClass("hidden"); - - if (/^default/gi.test(filesystem.properties.source)) { - filesystem.property.source = "default"; - filesystem.property.valueinherited = "Default (Off)"; - - $("#dropdown-" + modal.name + "-compression-" + modal.id + " li[value='InheritedReset'] a").text(filesystem.property.valueinherited); - } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name == pool.name) { - filesystem.property.source = "local"; - - $("#dropdown-" + modal.name + "-compression-" + modal.id + " li[value='InheritedReset'] a").text("Default (Off)"); - } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name != pool.name) { - filesystem.property.source = "local"; - - FnFileSystemConfigurationInheritedPropertyGet({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, property: "compression" }, { name: modal.name, id: modal.id }); - } - } - - $("#btnspan-" + modal.name + "-compression-" + modal.id).text((filesystem.property.valueinherited ? filesystem.property.valueinherited : filesystem.property.value)).attr("data-field-value", filesystem.properties.valueraw).attr("data-field-source", filesystem.property.source); - $("#dropdown-" + modal.name + "-compression-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-compression-" + modal.id + " li[value='" + (filesystem.property.valueinherited ? (filesystem.property.source == "inherited" ? "Inherited" : "InheritedReset") : filesystem.properties.valueraw) + "']").addClass("active"); - - if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { - $("#div-" + modal.name + "-compression-dropdown-" + modal.id + " button").prop("disabled", true); - } - break; - case "context": //Default is empty - if (filesystem.properties.value == "system_u:object_r:samba_share_t:s0") { - filesystem.context = true; - } - break; - case "dedup": //Default is off - filesystem.property = { - value: "Off", - valueinherited: "" - }; - - switch (filesystem.properties.value) { - case "on": - filesystem.property.value = "On"; - break; - case "off": - filesystem.property.value = "Off"; - break; - case "edonr,verify": - filesystem.property.value = "Edon-R + Verify"; - break; - case "sha256": - filesystem.property.value = "SHA-256"; - break; - case "sha256,verify": - filesystem.property.value = "SHA-256 + Verify"; - break; - case "sha512": - filesystem.property.value = "SHA-512"; - break; - case "sha512,verify": - filesystem.property.value = "SHA-512 + Verify"; - break; - case "skein": - filesystem.property.value = "Skein"; - break; - case "skein,verify": - filesystem.property.value = "Skein + Verify"; - break; - case "verify": - filesystem.property.value = "Verify"; - break; - default: - filesystem.property.value = "Off"; - break; - } - - if (/^inherited/gi.test(filesystem.properties.source)) { - filesystem.property.source = "inherited"; - filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; - - $("#dropdown-" + modal.name + "-dedup-" + modal.id + " li[value='Inherited']").removeClass("hidden"); - $("#dropdown-" + modal.name + "-dedup-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); - } else if (/^default|^local/gi.test(filesystem.properties.source)) { - $("#dropdown-" + modal.name + "-dedup-" + modal.id + " li[value='InheritedReset']").removeClass("hidden"); - - if (/^default/gi.test(filesystem.properties.source)) { - filesystem.property.source = "default"; - filesystem.property.valueinherited = "Default (Off)"; - - $("#dropdown-" + modal.name + "-dedup-" + modal.id + " li[value='InheritedReset'] a").text(filesystem.property.valueinherited); - } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name == pool.name) { - filesystem.property.source = "local"; - - $("#dropdown-" + modal.name + "-dedup-" + modal.id + " li[value='InheritedReset'] a").text("Default (Off)"); - } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name != pool.name) { - filesystem.property.source = "local"; - - FnFileSystemConfigurationInheritedPropertyGet({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, property: "dedup" }, { name: modal.name, id: modal.id }); - } - } - - $("#btnspan-" + modal.name + "-dedup-" + modal.id).text((filesystem.property.valueinherited ? filesystem.property.valueinherited : filesystem.property.value)).attr("data-field-value", filesystem.properties.valueraw).attr("data-field-source", filesystem.property.source); - $("#dropdown-" + modal.name + "-dedup-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-dedup-" + modal.id + " li[value='" + (filesystem.property.valueinherited ? (filesystem.property.source == "inherited" ? "Inherited" : "InheritedReset") : filesystem.properties.valueraw) + "']").addClass("active"); - - if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { - $("#div-" + modal.name + "-dedup-dropdown-" + modal.id + " button").prop("disabled", true); - } - break; - case "dnodesize": //Default is legacy - filesystem.property = { - value: "Off", - valueinherited: "" - }; - - switch (filesystem.properties.value) { - case "1k": - filesystem.property.value = "1 KiB"; - break; - case "2k": - filesystem.property.value = "2 KiB"; - break; - case "4k": - filesystem.property.value = "4 KiB"; - break; - case "8k": - filesystem.property.value = "8 KiB"; - break; - case "16k": - filesystem.property.value = "16 KiB"; - break; - case "auto": - filesystem.property.value = "Auto"; - break; - case "legacy": - filesystem.property.value = "Legacy"; - break; - default: - filesystem.property.value = "Legacy"; - break; - } - - if (/^inherited/gi.test(filesystem.properties.source)) { - filesystem.property.source = "inherited"; - filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; - - $("#dropdown-" + modal.name + "-dnodesize-" + modal.id + " li[value='Inherited']").removeClass("hidden"); - $("#dropdown-" + modal.name + "-dnodesize-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); - } else if (/^default|^local/gi.test(filesystem.properties.source)) { - $("#dropdown-" + modal.name + "-dnodesize-" + modal.id + " li[value='InheritedReset']").removeClass("hidden"); - - if (/^default/gi.test(filesystem.properties.source)) { - filesystem.property.source = "default"; - filesystem.property.valueinherited = "Default (Legacy)"; - - $("#dropdown-" + modal.name + "-dnodesize-" + modal.id + " li[value='InheritedReset'] a").text(filesystem.property.valueinherited); - } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name == pool.name) { - filesystem.property.source = "local"; - - $("#dropdown-" + modal.name + "-dnodesize-" + modal.id + " li[value='InheritedReset'] a").text("Default (Legacy)"); - } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name != pool.name) { - filesystem.property.source = "local"; - - FnFileSystemConfigurationInheritedPropertyGet({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, property: "dnodesize" }, { name: modal.name, id: modal.id }); - } - } - - $("#btnspan-" + modal.name + "-dnodesize-" + modal.id).text((filesystem.property.valueinherited ? filesystem.property.valueinherited : filesystem.property.value)).attr("data-field-value", filesystem.properties.valueraw).attr("data-field-source", filesystem.property.source); - $("#dropdown-" + modal.name + "-dnodesize-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-dnodesize-" + modal.id + " li[value='" + (filesystem.property.valueinherited ? (filesystem.property.source == "inherited" ? "Inherited" : "InheritedReset") : filesystem.properties.valueraw) + "']").addClass("active"); - - if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { - $("#div-" + modal.name + "-dnodesize-dropdown-" + modal.id + " button").prop("disabled", true); - } - break; - case "defcontext": //Default is empty - if (filesystem.properties.value == "system_u:object_r:samba_share_t:s0") { - filesystem.defcontext = true; - } - break; - case "encryption": //Default is off - filesystem.property = { - value: "Off" - }; - - switch (filesystem.properties.value) { - case "on": - filesystem.property.value = "On"; - break; - case "off": - filesystem.property.value = "Off"; - break; - case "aes-128-ccm": - filesystem.property.value = "AES-128-CCM"; - break; - case "aes-192-ccm": - filesystem.property.value = "AES-192-CCM"; - break; - case "aes-256-ccm": - filesystem.property.value = "AES-256-CCM"; - break; - case "aes-128-gcm": - filesystem.property.value = "AES-128-GCM"; - break; - case "aes-192-gcm": - filesystem.property.value = "AES-192-GCM"; - break; - case "aes-256-gcm": - filesystem.property.value = "AES-256-GCM"; - break; - default: - filesystem.property.value = "Off"; - break; - } - - $("#div-" + modal.name + "-encryption-" + modal.id).text(filesystem.property.value); - - if (filesystem.property.value != "Off") { - $("#controllabel-" + modal.name + "-encryption-" + modal.id).removeClass("hidden"); - $("#div-" + modal.name + "-encryption-" + modal.id).removeClass("hidden"); - } - break; - case "encryptionroot": - if (filesystem.properties.valueraw && filesystem.properties.valueraw == "-") { - filesystem.properties.valueraw = ""; - } - - if (filesystem.properties.valueraw && filesystem.properties.valueraw != filesystem.name) { - $("#controllabel-" + modal.name + "-encryptionroot-" + modal.id).removeClass("hidden"); - $("#div-" + modal.name + "-encryptionroot-" + modal.id).text(filesystem.properties.valueraw).removeClass("hidden"); - } - break; - case "fscontext": //Default is empty - if (filesystem.properties.value == "system_u:object_r:samba_share_t:s0") { - filesystem.fscontext = true; - } - break; - case "guid": - $("#div-" + modal.name + "-guid-" + modal.id).text(filesystem.properties.value); - break; - case "mountpoint": - $("#input-" + modal.name + "-mountpoint-" + modal.id).val(filesystem.properties.valueraw).attr("data-field-value", filesystem.properties.valueraw); - - if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { - $("#input-" + modal.name + "-mountpoint-" + modal.id).prop("disabled", true); - } - break; - case "quota": //Default is none - filesystem.property = { - value: "0 B", - valueraw: "0", - valueunit: "KiB" - }; - - if (filesystem.properties.value == "none" || filesystem.properties.value == "0" || filesystem.properties.value == "0b") { - filesystem.property.value = "0 B"; - } else { - filesystem.property.value = FnFormatBytes({ base2: true, decimals: 1, value: filesystem.properties.value }); - - if (/KiB/g.test(filesystem.property.value)) { - filesystem.property.valueunit = "KiB"; - } else if (/MiB/g.test(filesystem.property.value)) { - filesystem.property.valueunit = "MiB"; - } else if (/GiB/g.test(filesystem.property.value)) { - filesystem.property.valueunit = "GiB"; - } else if (/TiB/g.test(filesystem.property.value)) { - filesystem.property.valueunit = "TiB"; - } - - filesystem.property.valueraw = filesystem.property.value.toString().replace(" " + filesystem.property.valueunit, ""); - } - - $("#input-" + modal.name + "-quota-" + modal.id).val(filesystem.property.valueraw); - - size.quota = { - quota: parseInt(filesystem.properties.value), - max: { - raw: 1099511627776000, - unit: "", - unitnumber: 0 - }, - slider: { - valuemax: 1000 - }, - property: filesystem.property - }; - - FnStoragePoolSizeGet({ name: pool.name, id: null }) - .done(function (_data) { - FnConsole.log[4](FnConsoleVerbose({ data: _data, message: "Storage Pools, Size, Get:" })); - - if (_data && zfsmanager.configuration.zfs.filesystem.quotarestrict) { - size.quota.max.raw = parseInt(_data.replace(/\n+/g, "")); - } - }) - .finally(function () { - size.quota.max.raw = (size.quota.max.raw > size.quota.quota ? size.quota.max.raw : size.quota.quota); - size.quota.max.unitnumber = FnFormatBytes({ base2: true, decimals: 2, value: size.quota.max.raw }).replace(/ .*$/g, ""); - size.quota.max.unit = FnFormatBytes({ base2: true, decimals: 2, value: size.quota.max.raw }).replace(/ /g, "").replace(/^[0-9.]/, ""); - - if (size.quota.max.raw <= 1024000) { - $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-kib", size.quota.max.unitnumber); - } - if (size.quota.max.raw > 1024000) { - $("#dropdown-" + modal.name + "-quota-" + modal.id + " li[value='MiB']").removeClass("hidden"); - - $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-kib", size.quota.slider.valuemax); - $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-mib", size.quota.max.unitnumber); - } - if (size.quota.max.raw > 1048576000) { - $("#dropdown-" + modal.name + "-quota-" + modal.id + " li[value='GiB']").removeClass("hidden"); - - $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-kib", size.quota.slider.valuemax); - $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-mib", size.quota.slider.valuemax); - $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-gib", size.quota.max.unitnumber); - } - if (size.quota.max.raw > 1073741824000) { - $("#dropdown-" + modal.name + "-quota-" + modal.id + " li[value='TiB']").removeClass("hidden"); - - $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-kib", size.quota.slider.valuemax); - $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-mib", size.quota.slider.valuemax); - $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-gib", size.quota.slider.valuemax); - $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-tib", size.quota.max.unitnumber); - } - - if (size.quota.property.valueunit == "KiB") { - size.quota.slider.valuemax = $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-kib"); - } - if (size.quota.property.valueunit == "MiB") { - size.quota.slider.valuemax = $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-mib"); - } - if (size.quota.property.valueunit == "GiB") { - size.quota.slider.valuemax = $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-gib"); - } - if (size.quota.property.valueunit == "TiB") { - size.quota.slider.valuemax = $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-tib"); - } - - $("#slider-" + modal.name + "-quota-" + modal.id).data("slider").options.max = size.quota.slider.valuemax; - $("#slider-" + modal.name + "-quota-" + modal.id).data("slider").options.step = (size.quota.slider.valuemax < 10 ? "0.1" : "1"); - $("#slider-" + modal.name + "-quota-" + modal.id).slider("setValue", size.quota.property.valueraw); - - $("#btnspan-" + modal.name + "-quota-" + modal.id).text(size.quota.property.valueunit).attr("data-field-value", size.quota.property.valueunit); - $("#dropdown-" + modal.name + "-quota-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-quota-" + modal.id + " li[value='" + size.quota.property.valueunit + "']").addClass("active"); - $("#input-" + modal.name + "-quota-" + modal.id).attr("data-field-value", size.quota.property.value.toString().replace(/ /g, "").replace(/iB$/g, "")); - }); - - if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { - $("#input-" + modal.name + "-quota-" + modal.id).prop("disabled", true); - $("#div-" + modal.name + "-quota-dropdown-" + modal.id + " button").prop("disabled", true); - $("#validationwrapper-" + modal.name + "-quota-" + modal.id + " .slider-pf .slider *").addClass("disabled"); - $("#slider-" + modal.name + "-quota-" + modal.id).slider("disable"); - } - break; - case "readonly": //Default is off - if (filesystem.properties.value == "on") { - filesystem.readonly = true; - } - - if (filesystem.properties.value == "on" && !$("#switch-" + modal.name + "-readonly-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-readonly-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-readonly-" + modal.id).attr("data-field-value", filesystem.properties.value); - - if (pool.readonly) { - $("#switch-" + modal.name + "-readonly-" + modal.id + " input").prop("disabled", true); - } - break; - case "recordsize": //Default is 128K - filesystem.property = { - value: FnFormatBytes({ base2: true, decimals: 0, value: filesystem.properties.value }), - valueinherited: "" - }; - - if (/^inherited/gi.test(filesystem.properties.source)) { - filesystem.property.source = "inherited"; - filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; - - $("#dropdown-" + modal.name + "-recordsize-" + modal.id + " li[value='Inherited']").removeClass("hidden"); - $("#dropdown-" + modal.name + "-recordsize-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); - } else if (/^default|^local/gi.test(filesystem.properties.source)) { - $("#dropdown-" + modal.name + "-recordsize-" + modal.id + " li[value='InheritedReset']").removeClass("hidden"); - - if (/^default/gi.test(filesystem.properties.source)) { - filesystem.property.source = "default"; - filesystem.property.valueinherited = "Default (128 KiB)"; - - $("#dropdown-" + modal.name + "-recordsize-" + modal.id + " li[value='InheritedReset'] a").text(filesystem.property.valueinherited); - } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name == pool.name) { - filesystem.property.source = "local"; - - $("#dropdown-" + modal.name + "-recordsize-" + modal.id + " li[value='InheritedReset'] a").text("Default (128 KiB)"); - } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name != pool.name) { - filesystem.property.source = "local"; - - FnFileSystemConfigurationInheritedPropertyGet({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, property: "recordsize" }, { name: modal.name, id: modal.id }); - } - } - - $("#btnspan-" + modal.name + "-recordsize-" + modal.id).text((filesystem.property.valueinherited ? filesystem.property.valueinherited : filesystem.property.value)).attr("data-field-value", filesystem.properties.valueraw).attr("data-field-source", filesystem.property.source); - $("#dropdown-" + modal.name + "-recordsize-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-recordsize-" + modal.id + " li[value='" + (filesystem.property.valueinherited ? (filesystem.property.source == "inherited" ? "Inherited" : "InheritedReset") : filesystem.properties.valueraw) + "']").addClass("active"); - - if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { - $("#div-" + modal.name + "-recordsize-dropdown-" + modal.id + " button").prop("disabled", true); - } - break; - case "refreservation": //Default is none / 0 - filesystem.property = { - value: "0 B", - valueraw: "0", - valueunit: "KiB" - }; - - if (filesystem.properties.value == "none" || filesystem.properties.value == "0" || filesystem.properties.value == "0b") { - filesystem.property.value = "0 B"; - } else { - filesystem.property.value = FnFormatBytes({ base2: true, decimals: 1, value: filesystem.properties.value }); - - if (/KiB/g.test(filesystem.property.value)) { - filesystem.property.valueunit = "KiB"; - } else if (/MiB/g.test(filesystem.property.value)) { - filesystem.property.valueunit = "MiB"; - } else if (/GiB/g.test(filesystem.property.value)) { - filesystem.property.valueunit = "GiB"; - } else if (/TiB/g.test(filesystem.property.value)) { - filesystem.property.valueunit = "TiB"; - } - - filesystem.property.valueraw = filesystem.property.value.toString().replace(" " + filesystem.property.valueunit, ""); - } - - $("#input-" + modal.name + "-refreservation-" + modal.id).val(filesystem.property.valueraw); - - size.refreservation = { - available: parseInt(filesystem.available), - refreservation: parseInt(filesystem.properties.value), - max: { - raw: 0, - unit: "", - unitnumber: 0 - }, - slider: { - valuemax: 1000 - } - }; - - size.refreservation.max.raw = (size.refreservation.available > size.refreservation.refreservation ? size.refreservation.available : size.refreservation.refreservation); - size.refreservation.max.unitnumber = FnFormatBytes({ base2: true, decimals: 2, value: size.refreservation.max.raw }).replace(/ .*$/g, ""); - size.refreservation.max.unit = FnFormatBytes({ base2: true, decimals: 2, value: size.refreservation.max.raw }).replace(/ /g, "").replace(/^[0-9.]/, ""); - - if (size.refreservation.max.raw <= 1024000) { - $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-kib", size.refreservation.max.unitnumber); - } - if (size.refreservation.max.raw > 1024000) { - $("#dropdown-" + modal.name + "-refreservation-" + modal.id + " li[value='MiB']").removeClass("hidden"); - - $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-kib", size.refreservation.slider.valuemax); - $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-mib", size.refreservation.max.unitnumber); - } - if (size.refreservation.max.raw > 1048576000) { - $("#dropdown-" + modal.name + "-refreservation-" + modal.id + " li[value='GiB']").removeClass("hidden"); - - $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-kib", size.refreservation.slider.valuemax); - $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-mib", size.refreservation.slider.valuemax); - $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-gib", size.refreservation.max.unitnumber); - } - if (size.refreservation.max.raw > 1073741824000) { - $("#dropdown-" + modal.name + "-refreservation-" + modal.id + " li[value='TiB']").removeClass("hidden"); - - $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-kib", size.refreservation.slider.valuemax); - $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-mib", size.refreservation.slider.valuemax); - $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-gib", size.refreservation.slider.valuemax); - $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-tib", size.refreservation.max.unitnumber); - } - - if (filesystem.property.valueunit == "KiB") { - size.refreservation.slider.valuemax = $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-kib"); - } - if (filesystem.property.valueunit == "MiB") { - size.refreservation.slider.valuemax = $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-mib"); - } - if (filesystem.property.valueunit == "GiB") { - size.refreservation.slider.valuemax = $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-gib"); - } - if (filesystem.property.valueunit == "TiB") { - size.refreservation.slider.valuemax = $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-tib"); - } - - $("#slider-" + modal.name + "-refreservation-" + modal.id).data("slider").options.max = size.refreservation.slider.valuemax; - $("#slider-" + modal.name + "-refreservation-" + modal.id).data("slider").options.step = (size.refreservation.slider.valuemax < 10 ? "0.1" : "1"); - $("#slider-" + modal.name + "-refreservation-" + modal.id).slider("setValue", filesystem.property.valueraw); - - $("#btnspan-" + modal.name + "-refreservation-" + modal.id).text(filesystem.property.valueunit).attr("data-field-value", filesystem.property.valueunit); - $("#dropdown-" + modal.name + "-refreservation-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-refreservation-" + modal.id + " li[value='" + filesystem.property.valueunit + "']").addClass("active"); - $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-field-value", filesystem.property.value.toString().replace(/ /g, "").replace(/iB$/g, "")); - - if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { - $("#input-" + modal.name + "-refreservation-" + modal.id).prop("disabled", true); - $("#div-" + modal.name + "-refreservation-dropdown-" + modal.id + " button").prop("disabled", true); - $("#validationwrapper-" + modal.name + "-refreservation-" + modal.id + " .slider-pf .slider *").addClass("disabled"); - $("#slider-" + modal.name + "-refreservation-" + modal.id).slider("disable"); - } - break; - case "rootcontext": //Default is empty - if (filesystem.properties.value == "system_u:object_r:samba_share_t:s0") { - filesystem.rootcontext = true; - } - break; - case "sharenfs": //Default is off - if (filesystem.properties.value != "off") { - if (!$("#switch-" + modal.name + "-sharenfs-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-sharenfs-" + modal.id + " input").click(); - } - - $("#controllabel-" + modal.name + "-sharenfs-options-" + modal.id).removeClass("hidden"); - $("#validationwrapper-" + modal.name + "-sharenfs-options-" + modal.id).removeClass("hidden"); - $("#input-" + modal.name + "-sharenfs-options-" + modal.id).val((filesystem.properties.value == "on" ? "sec=sys,rw,crossmnt,no_subtree_check,no_root_squash" : filesystem.properties.value)); - - FnSystemNfsVersionGet({ alert: { id: $("#alert-" + modal.name + "-sharenfs-options-" + modal.id) } }); - } - - $("#input-" + modal.name + "-sharenfs-options-" + modal.id).attr("data-field-value", filesystem.properties.value); - - if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { - $("#switch-" + modal.name + "-sharenfs-" + modal.id + " input").prop("disabled", true); - $("#input-" + modal.name + "-sharenfs-options-" + modal.id).prop("disabled", true); - } - break; - case "sharesmb": - if (filesystem.properties.value == "on" && !$("#switch-" + modal.name + "-sharesmb-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-sharesmb-" + modal.id + " input").click(); - } - - if (pool.readonly || zfsmanager.configuration.samba.manage) { - $("#switch-" + modal.name + "-sharesmb-" + modal.id + " input").prop("disabled", true); - } - - $("#switch-" + modal.name + "-sharesmb-" + modal.id).attr("data-field-value", filesystem.properties.value); - break; - case "special_small_blocks": //Default is 0 - filesystem.property = { - value: FnFormatBytes({ base2: true, decimals: 0, value: filesystem.properties.value }), - valueinherited: "" - }; - - if (/^inherited/gi.test(filesystem.properties.source)) { - filesystem.property.source = "inherited"; - filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; - - $("#dropdown-" + modal.name + "-special_small_blocks-" + modal.id + " li[value='Inherited']").removeClass("hidden"); - $("#dropdown-" + modal.name + "-special_small_blocks-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); - } else if (/^default|^local/gi.test(filesystem.properties.source)) { - $("#dropdown-" + modal.name + "-special_small_blocks-" + modal.id + " li[value='InheritedReset']").removeClass("hidden"); - - if (/^default/gi.test(filesystem.properties.source)) { - filesystem.property.source = "default"; - filesystem.property.valueinherited = "Default (0 B)"; - - $("#dropdown-" + modal.name + "-special_small_blocks-" + modal.id + " li[value='InheritedReset'] a").text(filesystem.property.valueinherited); - } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name == pool.name) { - filesystem.property.source = "local"; - - $("#dropdown-" + modal.name + "-special_small_blocks-" + modal.id + " li[value='InheritedReset'] a").text("Default (0 B)"); - } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name != pool.name) { - filesystem.property.source = "local"; - - FnFileSystemConfigurationInheritedPropertyGet({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, property: "special_small_blocks" }, { name: modal.name, id: modal.id }); - } - } - - $("#btnspan-" + modal.name + "-special_small_blocks-" + modal.id).text((filesystem.property.valueinherited ? filesystem.property.valueinherited : filesystem.property.value)).attr("data-field-value", filesystem.properties.valueraw).attr("data-field-source", filesystem.property.source); - $("#dropdown-" + modal.name + "-special_small_blocks-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-special_small_blocks-" + modal.id + " li[value='" + (filesystem.property.valueinherited ? (filesystem.property.source == "inherited" ? "Inherited" : "InheritedReset") : filesystem.properties.valueraw) + "']").addClass("active"); - - if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { - $("#div-" + modal.name + "-special_small_blocks-dropdown-" + modal.id + " button").prop("disabled", true); - } - break; - case "used": - filesystem.used = filesystem.properties.value; - - filesystem.property = { - value: "0 B" - }; - - if (filesystem.properties.value == "none" || filesystem.properties.value == "0" || filesystem.properties.value == "0b") { - filesystem.property.value = "0 B"; - } else { - filesystem.property.value = FnFormatBytes({ base2: true, decimals: 2, value: filesystem.properties.value }); - } - - $("#helpblock-" + modal.name + "-used-" + modal.id).text("Used size: " + filesystem.property.value); - break; - case "xattr": //Default is on - filesystem.property = { - value: "On", - valueinherited: "" - }; - - switch (filesystem.properties.value) { - case "off": - filesystem.property.value = "Off"; - break; - case "sa": - filesystem.property.value = "System Attribute"; - break; - default: - filesystem.property.value = "On"; - break; - } - - if (/^inherited/gi.test(filesystem.properties.source)) { - filesystem.property.source = "inherited"; - filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; - - $("#dropdown-" + modal.name + "-xattr-" + modal.id + " li[value='Inherited']").removeClass("hidden"); - $("#dropdown-" + modal.name + "-xattr-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); - } else if (/^default|^local/gi.test(filesystem.properties.source)) { - $("#dropdown-" + modal.name + "-xattr-" + modal.id + " li[value='InheritedReset']").removeClass("hidden"); - - if (/^default/gi.test(filesystem.properties.source)) { - filesystem.property.source = "default"; - filesystem.property.valueinherited = "Default (On)"; - - $("#dropdown-" + modal.name + "-xattr-" + modal.id + " li[value='InheritedReset'] a").text(filesystem.property.valueinherited); - } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name == pool.name) { - filesystem.property.source = "local"; - - $("#dropdown-" + modal.name + "-xattr-" + modal.id + " li[value='InheritedReset'] a").text("Default (On)"); - } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name != pool.name) { - filesystem.property.source = "local"; - - FnFileSystemConfigurationInheritedPropertyGet({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, property: "xattr" }, { name: modal.name, id: modal.id }); - } - } - - $("#btnspan-" + modal.name + "-xattr-" + modal.id).text((filesystem.property.valueinherited ? filesystem.property.valueinherited : filesystem.property.value)).attr("data-field-value", filesystem.properties.valueraw).attr("data-field-source", filesystem.property.source); - $("#dropdown-" + modal.name + "-xattr-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-xattr-" + modal.id + " li[value='" + (filesystem.property.valueinherited ? (filesystem.property.source == "inherited" ? "Inherited" : "InheritedReset") : filesystem.properties.valueraw) + "']").addClass("active"); - - if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { - $("#div-" + modal.name + "-xattr-dropdown-" + modal.id + " button").prop("disabled", true); - } - break; - } - }); - - if (filesystem.context && filesystem.fscontext && filesystem.defcontext && filesystem.rootcontext) { - if (!$("#switch-" + modal.name + "-selinux-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-selinux-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-selinux-" + modal.id).attr("data-field-value", "true"); - } else { - $("#switch-" + modal.name + "-selinux-" + modal.id).attr("data-field-value", "false"); - } - - if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { - $("#switch-" + modal.name + "-selinux-" + modal.id + " input").prop("disabled", true); - } - if (pool.readonly) { - $("#btn-" + modal.name + "-apply-" + modal.id).prop("disabled", true); - } - - FnConsole.log[1]("File Systems, Configuration, Get: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - }) - .fail(function (message, data) { - FnConsole.warn("File Systems, Configuration, Get: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + " , Message: " + (data ? data : message)); - }); -} - -function FnFileSystemConfigurationInheritedGet(pool = { name, id }, filesystem = { name }, modal = { name, id }) { - let process = { - command: ["/sbin/zfs", "get", "atime,casesensitivity,compression,dedup,dnodesize,encryption,recordsize,special_small_blocks,xattr", "-H", "-o", "property,value,source", "-p", filesystem.name] - }; - - FnConsole.log[2]("File Systems, Configuration, Inherited, Get: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Configuration, Inherited, Get:" })); - - process.data = data.replace(/\t+/g, "\u22C5").split(/\n/g).filter(v => v); - - process.data.forEach((_value, _index) => { - _value = _value.split("\u22C5"); - - filesystem.properties = { - property: _value[0].toLowerCase(), - value: _value[1].toLowerCase(), - valueraw: _value[1], - source: _value[2] - }; - - switch (filesystem.properties.property) { - case "atime": //Default is on - filesystem.property = { - value: "On", - valueinherited: "" - }; - - switch (filesystem.properties.value) { - case "on": - filesystem.property.value = "On"; - break; - case "gzip": - filesystem.property.value = "GZIP"; - break; - case "lz4": - filesystem.property.value = "LZ4"; - break; - case "lzjb": - filesystem.property.value = "LZJB"; - break; - case "zle": - filesystem.property.value = "ZLE"; - break; - default: - filesystem.property.value = "Off"; - break; - } - - filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; - - $("#btnspan-" + modal.name + "-atime-" + modal.id).text(filesystem.property.valueinherited).attr("data-field-value", "Inherited"); - $("#dropdown-" + modal.name + "-atime-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-atime-" + modal.id + " li[value='Inherited']").removeClass("hidden"); - $("#dropdown-" + modal.name + "-atime-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); - $("#dropdown-" + modal.name + "-atime-" + modal.id + " li[value='Inherited']").addClass("active"); - break; case "casesensitivity": //Default is sensitive - filesystem.property = { - value: "Sensitive", - valueinherited: "" - }; - - switch (filesystem.properties.value) { - case "insensitive": - filesystem.property.value = "Insensitive"; - break; - case "mixed": - filesystem.property.value = "Mixed"; - break; - case "sensitive": - filesystem.property.value = "Sensitive"; - break; - default: - filesystem.property.value = "Sensitive"; - break; - } - - filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; - - $("#btnspan-" + modal.name + "-casesensitivity-" + modal.id).text(filesystem.property.valueinherited).attr("data-field-value", "Inherited"); - $("#dropdown-" + modal.name + "-casesensitivity-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-casesensitivity-" + modal.id + " li[value='Inherited']").removeClass("hidden"); - $("#dropdown-" + modal.name + "-casesensitivity-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); - $("#dropdown-" + modal.name + "-casesensitivity-" + modal.id + " li[value='Inherited']").addClass("active"); - break; - case "compression": //Default is off - filesystem.property = { - value: "Off", - valueinherited: "" - }; - - switch (filesystem.properties.value) { - case "on": - filesystem.property.value = "On"; - break; - case "gzip": - filesystem.property.value = "GZIP"; - break; - case "lz4": - filesystem.property.value = "LZ4"; - break; - case "lzjb": - filesystem.property.value = "LZJB"; - break; - case "zle": - filesystem.property.value = "ZLE"; - break; - default: - filesystem.property.value = "Off"; - break; - } - - filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; - - $("#btnspan-" + modal.name + "-compression-" + modal.id).text(filesystem.property.valueinherited).attr("data-field-value", "Inherited"); - $("#dropdown-" + modal.name + "-compression-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-compression-" + modal.id + " li[value='Inherited']").removeClass("hidden"); - $("#dropdown-" + modal.name + "-compression-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); - $("#dropdown-" + modal.name + "-compression-" + modal.id + " li[value='Inherited']").addClass("active"); - break; - case "dedup": //Default is off - filesystem.property = { - value: "Off", - valueinherited: "" - }; - - switch (filesystem.properties.value) { - case "on": - filesystem.property.value = "On"; - break; - case "off": - filesystem.property.value = "Off"; - break; - case "verify": - filesystem.property.value = "Verify"; - break; - case "sha256": - filesystem.property.value = "SHA-256"; - break; - case "sha256,verify": - filesystem.property.value = "SHA-256 + Verify"; - break; - case "sha512": - filesystem.property.value = "SHA-512"; - break; - case "sha512,verify": - filesystem.property.value = "SHA-512 + Verify"; - break; - case "skein": - filesystem.property.value = "Skein"; - break; - case "skein,verify": - filesystem.property.value = "Skein + Verify"; - break; - case "edonr,verify": - filesystem.property.value = "Edon-R + Verify"; - break; - default: - filesystem.property.value = "Off"; - break; - } - - filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; - - $("#btnspan-" + modal.name + "-dedup-" + modal.id).text(filesystem.property.valueinherited).attr("data-field-value", "Inherited"); - $("#dropdown-" + modal.name + "-dedup-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-dedup-" + modal.id + " li[value='Inherited']").removeClass("hidden"); - $("#dropdown-" + modal.name + "-dedup-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); - $("#dropdown-" + modal.name + "-dedup-" + modal.id + " li[value='Inherited']").addClass("active"); - break; - case "dnodesize": //Default is legacy - filesystem.property = { - value: "Off", - valueinherited: "" - }; - - switch (filesystem.properties.value) { - case "1k": - filesystem.property.value = "1 KiB"; - break; - case "2k": - filesystem.property.value = "2 KiB"; - break; - case "4k": - filesystem.property.value = "4 KiB"; - break; - case "8k": - filesystem.property.value = "8 KiB"; - break; - case "16k": - filesystem.property.value = "16 KiB"; - break; - case "auto": - filesystem.property.value = "Auto"; - break; - case "legacy": - filesystem.property.value = "Legacy"; - break; - default: - filesystem.property.value = "Legacy"; - break; - } - - filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; - - $("#btnspan-" + modal.name + "-dnodesize-" + modal.id).text(filesystem.property.valueinherited).attr("data-field-value", "Inherited"); - $("#dropdown-" + modal.name + "-dnodesize-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-dnodesize-" + modal.id + " li[value='Inherited']").removeClass("hidden"); - $("#dropdown-" + modal.name + "-dnodesize-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); - $("#dropdown-" + modal.name + "-dnodesize-" + modal.id + " li[value='Inherited']").addClass("active"); - break; - case "encryption": //Default is off - filesystem.property = { - value: "Off", - valueinherited: "" - }; - - switch (filesystem.properties.value) { - case "on": - filesystem.property.value = "On"; - break; - case "off": - filesystem.property.value = "Off"; - break; - case "aes-128-ccm": - filesystem.property.value = "AES-128-CCM"; - break; - case "aes-192-ccm": - filesystem.property.value = "AES-192-CCM"; - break; - case "aes-256-ccm": - filesystem.property.value = "AES-256-CCM"; - break; - case "aes-128-gcm": - filesystem.property.value = "AES-128-GCM"; - break; - case "aes-192-gcm": - filesystem.property.value = "AES-192-GCM"; - break; - case "aes-256-gcm": - filesystem.property.value = "AES-256-GCM"; - break; - } - - filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; - - if (filesystem.properties.value != "off") { - if (!$("#switch-" + modal.name + "-encryption-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-encryption-" + modal.id + " input").click(); - } - - $("#switch-" + modal.name + "-encryption-" + modal.id + " input").prop("disabled", true); - $("#btnspan-" + modal.name + "-encryption-cipher-" + modal.id).text(filesystem.property.valueinherited).attr("data-field-value", "Inherited"); - $("#dropdown-" + modal.name + "-encryption-cipher-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-encryption-cipher-" + modal.id + " li[value='Inherited']").removeClass("hidden"); - $("#dropdown-" + modal.name + "-encryption-cipher-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); - $("#dropdown-" + modal.name + "-encryption-cipher-" + modal.id + " li[value='Inherited']").addClass("active"); - $("#helpblock-" + modal.name + "-encryption-passphrase-" + modal.id).removeClass("has-error").removeClass("hidden").text("Passphrase is not required."); - } else if (filesystem.properties.value == "off") { - $("#switch-" + modal.name + "-encryption-" + modal.id + " input").prop("disabled", false); - - if ($("#switch-" + modal.name + "-encryption-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-encryption-" + modal.id + " input").click(); - } - - $("#btnspan-" + modal.name + "-encryption-cipher-" + modal.id).text("AES-256-GCM").attr("data-field-value", "aes-256-gcm"); - $("#dropdown-" + modal.name + "-encryption-cipher-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-encryption-cipher-" + modal.id + " li[value='aes-256-gcm']").addClass("active"); - $("#dropdown-" + modal.name + "-encryption-cipher-" + modal.id + " li[value='Inherited']").addClass("hidden"); - $("#dropdown-" + modal.name + "-encryption-cipher-" + modal.id + " li[value='Inherited'] a").text("Inherited"); - - if ($("#input-" + modal.name + "-encryption-passphrase-" + modal.id).val().length == 0) { - $("#validationwrapper-" + modal.name + "-encryption-passphrase-" + modal.id).removeClass("has-error"); - $("#helpblock-" + modal.name + "-encryption-passphrase-" + modal.id).removeClass("has-error").addClass("hidden").text(""); - $("#validationwrapper-" + modal.name + "-encryption-passphrase-confirm-" + modal.id).removeClass("has-error"); - $("#helpblock-" + modal.name + "-encryption-passphrase-" + modal.id).removeClass("has-error").addClass("hidden").text(""); - } - } - break; - case "recordsize": //Default is 128K - filesystem.property = { - value: FnFormatBytes({ base2: true, decimals: 0, value: filesystem.properties.value }), - valueinherited: "" - }; - - filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; - - $("#btnspan-" + modal.name + "-recordsize-" + modal.id).text(filesystem.property.valueinherited).attr("data-field-value", "Inherited"); - $("#dropdown-" + modal.name + "-recordsize-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-recordsize-" + modal.id + " li[value='Inherited']").removeClass("hidden"); - $("#dropdown-" + modal.name + "-recordsize-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); - $("#dropdown-" + modal.name + "-recordsize-" + modal.id + " li[value='Inherited']").addClass("active"); - break; - case "special_small_blocks": //Default is 0 - filesystem.property = { - value: FnFormatBytes({ base2: true, decimals: 0, value: filesystem.properties.value }), - valueinherited: "" - }; - - filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; - - $("#btnspan-" + modal.name + "-special_small_blocks-" + modal.id).text(filesystem.property.valueinherited).attr("data-field-value", "Inherited"); - $("#dropdown-" + modal.name + "-special_small_blocks-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-special_small_blocks-" + modal.id + " li[value='Inherited']").removeClass("hidden"); - $("#dropdown-" + modal.name + "-special_small_blocks-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); - $("#dropdown-" + modal.name + "-special_small_blocks-" + modal.id + " li[value='Inherited']").addClass("active"); - break; - case "xattr": //Default is on - filesystem.property = { - value: "On", - valueinherited: "" - }; - - switch (filesystem.properties.value) { - case "on": - filesystem.property.value = "On"; - break; - case "off": - filesystem.property.value = "Off"; - break; - case "sa": - filesystem.property.value = "System Attribute"; - break; - default: - filesystem.property.value = "On"; - break; - } - - filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; - - $("#btnspan-" + modal.name + "-xattr-" + modal.id).text(filesystem.property.valueinherited).attr("data-field-value", "Inherited"); - $("#dropdown-" + modal.name + "-xattr-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-xattr-" + modal.id + " li[value='Inherited']").removeClass("hidden"); - $("#dropdown-" + modal.name + "-xattr-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); - $("#dropdown-" + modal.name + "-xattr-" + modal.id + " li[value='Inherited']").addClass("active"); - break; - } - }); - - //Quota - let size = { - quota: { - max: { - raw: 1099511627776000, - unit: "", - unitnumber: 0 - }, - slider: { - valuemax: 1000 - }, - property: { - value: "0 B", - valueraw: "0", - valueunit: "KiB" - } - } - }; - - FnStoragePoolSizeGet({ name: pool.name, id: null }) - .done(function (_data) { - FnConsole.log[4](FnConsoleVerbose({ data: _data, message: "Storage Pools, Size, Get:" })); - - if (_data && zfsmanager.configuration.zfs.filesystem.quotarestrict) { - size.quota.max.raw = parseInt(_data.replace(/\n+/g, "")); - } - }) - .finally(function () { - size.quota.max.unitnumber = FnFormatBytes({ base2: true, decimals: 2, value: size.quota.max.raw }).replace(/ .*$/g, ""); - size.quota.max.unit = FnFormatBytes({ base2: true, decimals: 2, value: size.quota.max.raw }).replace(/ /g, "").replace(/^[0-9.]/, ""); - - if (size.quota.max.raw <= 1024000) { - $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-kib", size.quota.max.unitnumber); - } - if (size.quota.max.raw > 1024000) { - $("#dropdown-" + modal.name + "-quota-" + modal.id + " li[value='MiB']").removeClass("hidden"); - - $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-kib", size.quota.slider.valuemax); - $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-mib", size.quota.max.unitnumber); - } - if (size.quota.max.raw > 1048576000) { - $("#dropdown-" + modal.name + "-quota-" + modal.id + " li[value='GiB']").removeClass("hidden"); - - $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-kib", size.quota.slider.valuemax); - $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-mib", size.quota.slider.valuemax); - $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-gib", size.quota.max.unitnumber); - } - if (size.quota.max.raw > 1073741824000) { - $("#dropdown-" + modal.name + "-quota-" + modal.id + " li[value='TiB']").removeClass("hidden"); - - $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-kib", size.quota.slider.valuemax); - $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-mib", size.quota.slider.valuemax); - $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-gib", size.quota.slider.valuemax); - $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-tib", size.quota.max.unitnumber); - } - - if (size.quota.property.valueunit == "KiB") { - size.quota.slider.valuemax = $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-kib"); - } - if (size.quota.property.valueunit == "MiB") { - size.quota.slider.valuemax = $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-mib"); - } - if (size.quota.property.valueunit == "GiB") { - size.quota.slider.valuemax = $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-gib"); - } - if (size.quota.property.valueunit == "TiB") { - size.quota.slider.valuemax = $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-tib"); - } - - $("#slider-" + modal.name + "-quota-" + modal.id).data("slider").options.max = size.quota.slider.valuemax; - $("#slider-" + modal.name + "-quota-" + modal.id).data("slider").options.step = (size.quota.slider.valuemax < 10 ? "0.1" : "1"); - $("#slider-" + modal.name + "-quota-" + modal.id).slider("setValue", size.quota.property.valueraw); - - $("#btnspan-" + modal.name + "-quota-" + modal.id).text(size.quota.property.valueunit).attr("data-field-value", size.quota.property.valueunit); - $("#dropdown-" + modal.name + "-quota-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-quota-" + modal.id + " li[value='" + size.quota.property.valueunit + "']").addClass("active"); - $("#input-" + modal.name + "-quota-" + modal.id).attr("data-field-value", size.quota.property.value.toString().replace(/ /g, "").replace(/iB$/g, "")); - }); - - FnConsole.log[1]("File Systems, Configuration, Inherited, Get: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - }) - .fail(function (message, data) { - FnConsole.warn("File Systems, Configuration, Inherited, Get: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + " , Message: " + (data ? data : message)); - }); -} - -function FnFileSystemConfigurationInheritedPropertyGet(pool = { name, id }, filesystem = { name, id, property }, modal = { name, id }) { - let process = { - command: ["/sbin/zfs", "get", filesystem.property, "-H", "-o", "value", "-p", "-d", "0", filesystem.name.replace(/\/[^\/]+$/, "")] - }; - - FnConsole.log[2]("File Systems, Configuration, Property, Inherited, Get: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Configuration, Property, Get:" })); - - filesystem.properties = { - value: data.trim() - }; - - switch (filesystem.properties.value) { - case "edonr": - filesystem.properties.value = "Edon-R"; - break; - case "edonr,verify": - filesystem.properties.value = "Edon-R + Verify"; - break; - case "gzip": - filesystem.properties.value = "GZIP"; - break; - case "lz4": - filesystem.properties.value = "LZ4"; - break; - case "lzjb": - filesystem.properties.value = "LZJB"; - break; - case "noacl": - filesystem.properties.value = "No ACL"; - break; - case "noallow": - filesystem.properties.value = "No Allow"; - break; - case "noparity": - filesystem.properties.value = "No Parity"; - break; - case "passthrough-x": - filesystem.properties.value = "Passthrough-X"; - break; - case "posixacl": - filesystem.properties.value = "POSIX ACL"; - break; - case "sa": - filesystem.properties.value = "System Attribute"; - break; - case "sha256": - filesystem.properties.value = "SHA-256"; - break; - case "sha256,verify": - filesystem.properties.value = "SHA-256 + Verify"; - break; - case "sha512": - filesystem.properties.value = "SHA-512"; - break; - case "sha512,verify": - filesystem.properties.value = "SHA-512 + Verify"; - break; - case "skein,verify": - filesystem.properties.value = "Skein + Verify"; - break; - case "zle": - filesystem.properties.value = "ZLE"; - break; - default: - filesystem.properties.value = ($.isNumeric(filesystem.properties.value) ? FnFormatBytes({ base2: true, decimals: 0, value: filesystem.properties.value }) : filesystem.properties.value.charAt(0).toUpperCase() + filesystem.properties.value.slice(1)); - } - - $("#dropdown-" + modal.name + "-" + filesystem.property + "-" + modal.id + " li[value='InheritedReset'] a").text("Inherited" + (filesystem.properties.value ? " (" + filesystem.properties.value + ")" : "")); - - FnConsole.log[2]("File Systems, Configuration, Property, Inherited, Get: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - }) - .fail(function (message, data) { - $("#dropdown-" + modal.name + "-" + filesystem.property + "-" + modal.id + " li[value='InheritedReset'] a").text("Inherited"); - - FnConsole.warn("File Systems, Configuration, Property, Inherited, Get: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + " , Message: " + (data ? data : message)); - }); -} - -function FnFileSystemConfigure(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, aclinherit, acltype, atime, canmount, checksum, compression, context, dedup, dnodesize, defcontext, fscontext, mountpoint, quota, readonly, recordsize, refreservation, rootcontext, sharenfs, sharesmb, special_small_blocks, type, xattr }, samba = { restart: false }, modal = { id }) { - filesystem.properties = { - inherit: [], - new: [] - }; - - if (filesystem.aclinherit) { - if (/^Default|^Inherited/g.test(filesystem.aclinherit)) { - filesystem.properties.inherit.push("aclinherit"); - } else { - filesystem.properties.new.push("aclinherit=" + filesystem.aclinherit); - } - } - if (filesystem.acltype) { - if (/^Default|^Inherited/g.test(filesystem.acltype)) { - filesystem.properties.inherit.push("acltype"); - } else { - filesystem.properties.new.push("acltype=" + filesystem.acltype); - } - } - if (filesystem.atime) { - if (/^Default|^Inherited/g.test(filesystem.atime)) { - filesystem.properties.inherit.push("atime"); - } else { - filesystem.properties.new.push("atime=" + filesystem.atime); - } - } - if (filesystem.canmount) { - filesystem.properties.new.push("canmount=" + filesystem.canmount); - } - if (filesystem.checksum) { - if (/^Default|^Inherited/g.test(filesystem.checksum)) { - filesystem.properties.inherit.push("checksum"); - } else { - filesystem.properties.new.push("checksum=" + filesystem.checksum); - } - } - if (filesystem.compression) { - if (/^Default|^Inherited/g.test(filesystem.compression)) { - filesystem.properties.inherit.push("compression"); - } else { - filesystem.properties.new.push("compression=" + filesystem.compression); - } - } - if (filesystem.context) { - filesystem.properties.new.push("context=" + filesystem.context); - } - if (filesystem.dedup) { - if (/^Default|^Inherited/g.test(filesystem.dedup)) { - filesystem.properties.inherit.push("dedup"); - } else { - filesystem.properties.new.push("dedup=" + filesystem.dedup); - } - } - if (filesystem.dnodesize) { - if (/^Default|^Inherited/g.test(filesystem.dnodesize)) { - filesystem.properties.inherit.push("dnodesize"); - } else { - filesystem.properties.new.push("dnodesize=" + filesystem.dnodesize); - } - } - if (filesystem.defcontext) { - filesystem.properties.new.push("defcontext=" + filesystem.defcontext); - } - if (filesystem.fscontext) { - filesystem.properties.new.push("fscontext=" + filesystem.fscontext); - } - if (filesystem.mountpoint) { - filesystem.properties.new.push(`mountpoint="` + filesystem.mountpoint + `"`); - } - if (filesystem.quota) { - filesystem.properties.new.push(`quota="` + filesystem.quota + `"`); - } - if (filesystem.readonly) { - filesystem.properties.new.push("readonly=" + filesystem.readonly); - } - if (filesystem.recordsize) { - if (/^Default|^Inherited/g.test(filesystem.recordsize)) { - filesystem.properties.inherit.push("recordsize"); - } else { - filesystem.properties.new.push("recordsize=" + filesystem.recordsize); - } - } - if (filesystem.refreservation) { - filesystem.properties.new.push("refreservation=" + filesystem.refreservation); - } - if (filesystem.rootcontext) { - filesystem.properties.new.push("rootcontext=" + filesystem.rootcontext); - } - if (filesystem.sharenfs) { - filesystem.properties.new.push(`sharenfs="` + filesystem.sharenfs + `"`); - } - if (filesystem.sharesmb && !zfsmanager.configuration.samba.manage) { - filesystem.properties.new.push("sharesmb=" + filesystem.sharesmb); - } - if (filesystem.special_small_blocks) { - if (/^Default|^Inherited/g.test(filesystem.special_small_blocks)) { - filesystem.properties.inherit.push("special_small_blocks"); - } else { - filesystem.properties.new.push("special_small_blocks=" + filesystem.special_small_blocks); - } - } - if (filesystem.xattr) { - if (/^Default|^Inherited/g.test(filesystem.xattr)) { - filesystem.properties.inherit.push("xattr"); - } else { - filesystem.properties.new.push("xattr=" + filesystem.xattr); - } - } - - if (filesystem.properties.inherit.length > 0 && !pool.readonly) { - FnFileSystemConfigureInheritance({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, properties: { inherit: filesystem.properties.inherit }, type: filesystem.type }) - .finally(function () { - if (filesystem.properties.new.length > 0 && !pool.readonly) { - FnFileSystemConfigureCommand({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: filesystem.name, id: filesystem.id, mountpoint: filesystem.mountpoint, properties: { new: filesystem.properties.new }, type: filesystem.type }, { restart: samba.restart }, { id: modal.id }); - } else { - modal.id.modal("hide"); - } - }); - } else if (filesystem.properties.new.length > 0 && !pool.readonly) { - FnFileSystemConfigureCommand({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: filesystem.name, id: filesystem.id, mountpoint: filesystem.mountpoint, properties: { new: filesystem.properties.new }, type: filesystem.type }, { restart: samba.restart }, { id: modal.id }); - } else { - modal.id.modal("hide"); - } -} - -function FnFileSystemConfigureCommand(pool = { name, id, altroot: false }, filesystem = { name, id, mountpoint, properties: { new: [] }, type }, samba = { restart: false }, modal = { id }) { - let process = { - command: ["/bin/sh", "-c", "/sbin/zfs set " + filesystem.properties.new.join(" ") + " " + `"` + filesystem.name + `"`] - }; - - modal.hide = true; - - FnConsole.log[2]("File Systems, Configure: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-storagepool-filesystem-configure-" + filesystem.id + " span").text("Configuring " + filesystem.type.toLowerCase() + "..."); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "File System successfully configured", description: filesystem.name, breakword: false }, { name: "filesystem-configure", id: filesystem.id, timeout: 4 }); - - FnConsole.log[1]("File Systems, Configure: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - - if (zfsmanager.configuration.samba.manage) { - if (filesystem.mountpoint) { - modal.hide = false; - - $("#spinner-storagepool-filesystem-configure-" + filesystem.id + " span").text("Updating Samba shares..."); - - FnSambaZfsShareConfigurationPathsSet({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: filesystem.name }, { restart: samba.restart }, display = { refresh: false, silent: true }) - .finally(function () { - modal.id.modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - }); - } else if (samba.restart) { - FnSambaRestart(); - } - } else { - if (samba.restart) { - FnSambaRestart(); - } - } - }) - .fail(function (message, data) { - filesystem.configured = false; - - if (/size is greater than available space/gi.test(data)) { - modal.hide = false; - - $("#validationwrapper-storagepool-filesystem-configure-refreservation-" + filesystem.id).addClass("has-error"); - $("#helpblock-storagepool-filesystem-configure-refreservation-" + filesystem.id).addClass("has-error").removeClass("hidden").text("Refreservation can not be greater than available size."); - $("#input-storagepool-filesystem-configure-refreservation-" + filesystem.id).focus(); - } else if (/size is less than current used or reserved space/gi.test(data)) { - modal.hide = false; - - $("#validationwrapper-storagepool-filesystem-configure-quota-" + filesystem.id).addClass("has-error"); - $("#helpblock-storagepool-filesystem-configure-quota-" + filesystem.id).addClass("has-error").removeClass("hidden").text("Quota can not be less than used size."); - $("#input-storagepool-filesystem-configure-quota-" + filesystem.id).focus(); - } else if (/property may be set/gi.test(data)) { - filesystem.configured = true; - - FnDisplayAlert({ status: "warning", title: "File system configured with errors", description: filesystem.name, breakword: false }, { name: "filesystem-configure", id: filesystem.id, timeout: 4 }); - - FnConsole.warn("File Systems, Configure: Warning, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); - } - - if (!filesystem.configured) { - if (modal.hide) { - FnDisplayAlert({ status: "danger", title: "File System could not be configured", description: filesystem.name, breakword: false }, { name: "filesystem-configure", id: filesystem.id, timeout: 4 }); - } - - FnConsole.warn("File Systems, Configure: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); - } - - if (!modal.hide) { - $("#spinner-storagepool-filesystem-configure-" + filesystem.id).addClass("hidden"); - $("#spinner-storagepool-filesystem-configure-" + filesystem.id + " span").text(""); - $("#btn-storagepool-filesystem-configure-apply-" + filesystem.id).prop("disabled", false); - } - }) - .finally(function () { - if (modal.hide) { - modal.id.modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - } - }); -} - -function FnFileSystemConfigureInheritance(pool = { name, id }, filesystem = { name, id, properties: { inherit: [] }, type }) { - let process = { - promise: cockpit.defer() - }; - let promise = Promise.resolve(); - - filesystem.properties.errorcount = 0; - - $("#spinner-storagepool-filesystem-configure-" + filesystem.id + " span").text("Configuring " + filesystem.type.toLowerCase() + " inheritance..."); - - filesystem.properties.inherit.forEach((_value, _index) => { - promise = promise.then(_ => new Promise(resolve => - setTimeout(function () { - process.command = ["/sbin/zfs", "inherit", _value, filesystem.name]; - - FnConsole.log[2]("File Systems, Configure, Inheritance: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnConsole.log[2]("File Systems, Configure, Inheritance: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - - if (_index == (filesystem.properties.inherit.length - 1)) { - if (filesystem.properties.errorcount == 0) { - FnDisplayAlert({ status: "success", title: "File System inheritance successfully configured", description: filesystem.name, breakword: false }, { name: "filesystem-configure-inheritance", id: filesystem.id, timeout: 4 }); - } else { - FnDisplayAlert({ status: "danger", title: "File System inheritance could not be configured", description: filesystem.name, breakword: false }, { name: "filesystem-configure-inheritance", id: filesystem.id, timeout: 4 }); - } - - process.promise.resolve(); - } - }) - .fail(function (message, data) { - filesystem.properties.errorcount++; - - FnConsole.warn("File Systems, Configure, Inheritance: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); - - if (_index == (filesystem.properties.inherit.length - 1)) { - FnDisplayAlert({ status: "danger", title: "File System inheritance could not be configured", description: filesystem.name, breakword: false }, { name: "filesystem-configure-inheritance", id: filesystem.id, timeout: 4 }); - - process.promise.resolve(); - } - }); - - resolve(); - }, 500) - )); - }); - - return process.promise.promise(); -} - -function FnFileSystemCreate(pool = { name, id, altroot: false }, filesystem = { name, id, atime, casesensitivity, cipher, compression, dedup, dnodesize, encryption, passphrase, quota, readonly, recordsize, selinux, sharenfs, sharesmb, special_small_blocks, xattr }) { - let process = { - command: [], - options: `-o normalization=formD -o sharenfs="` + filesystem.sharenfs + `" -o sharesmb=` + filesystem.sharesmb + ` -o utf8only=on` - }; - - if (filesystem.quota) { - process.options += " -o quota=" + filesystem.quota; - } - if (filesystem.readonly) { - process.options += " -o readonly=" + filesystem.readonly; - } - if (filesystem.selinux) { - process.options += " -o context=system_u:object_r:samba_share_t:s0 -o fscontext=system_u:object_r:samba_share_t:s0 -o defcontext=system_u:object_r:samba_share_t:s0 -o rootcontext=system_u:object_r:samba_share_t:s0"; - } - if (/^Inherited/g.test(filesystem.atime) == false) { - process.options += " -o atime=" + filesystem.atime; - } - if (/^Inherited/g.test(filesystem.casesensitivity) == false) { - process.options += " -o casesensitivity=" + filesystem.casesensitivity; - } - if (/^Inherited/g.test(filesystem.dedup) == false) { - process.options += " -o dedup=" + filesystem.dedup; - } - if (/^Inherited/g.test(filesystem.dnodesize) == false) { - process.options += " -o dnodesize=" + filesystem.dnodesize; - } - if (/^Inherited/g.test(filesystem.compression) == false) { - process.options += " -o compression=" + filesystem.compression; - } - if (/^Inherited/g.test(filesystem.recordsize) == false) { - process.options += " -o recordsize=" + filesystem.recordsize; - } - if (/^Inherited/g.test(filesystem.special_small_blocks) == false) { - process.options += " -o special_small_blocks=" + filesystem.special_small_blocks; - } - if (/^Inherited/g.test(filesystem.xattr) == false) { - process.options += " -o xattr=" + filesystem.xattr; - } - if (/^Inherited/g.test(filesystem.cipher) == false && filesystem.encryption) { - process.options += " -o encryption=" + filesystem.cipher; - } - - if (filesystem.encryption && filesystem.passphrase) { - process.options += " -o keyformat=passphrase -o keylocation=prompt"; - - if (filesystem.passphrase.length < 8) { - FnFileSystemCreateFail({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: filesystem.name, id: filesystem.id, sharesmb: filesystem.sharesmb }, { data: "Passphrase requires a minimum of 8 characters.", message: null }); - return; - } - - //Escape percentage and single quote special character for printf - if (/\%/g.test(filesystem.passphrase)) { - filesystem.passphrase = filesystem.passphrase.replace(/\%/g, "\%\%"); - } - if (/\'/g.test(filesystem.passphrase)) { - filesystem.passphrase = filesystem.passphrase.replace(/\'/g, "\'\"\'\"\'"); - } - - process.command = ["/bin/sh", "-c", "printf '" + filesystem.passphrase + "' | /sbin/zfs create " + process.options + ` "` + filesystem.name + `"`]; - } else { - process.command = ["/bin/sh", "-c", "/sbin/zfs create " + process.options + ` "` + filesystem.name + `"`]; - } - - FnConsole.log[1]("File Systems, Create: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-storagepool-filesystems-create-" + pool.id + " span").text("Creating file system..."); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "File System successfully created", description: filesystem.name, breakword: false }, { name: "filesystem-create", id: filesystem.id, timeout: 4 }); - - FnConsole.log[1]("File Systems, Create: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - - if (filesystem.sharesmb == "on" && zfsmanager.configuration.samba.manage) { - $("#spinner-storagepool-filesystems-create-" + pool.id + " span").text("Enabling Samba share..."); - - FnSambaShareEnableMountpointGet({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { name: filesystem.name, id: filesystem.id, sharesmb: true }, { silent: false }); - } - - setTimeout(function () { - $("#modal-storagepool-filesystems-create-" + pool.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - }, (filesystem.sharesmb == "on" && zfsmanager.configuration.samba.manage ? 500 : 0)); - }) - .fail(function (message, data) { - FnFileSystemCreateFail({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: filesystem.name, id: filesystem.id, sharesmb: filesystem.sharesmb }, { data: data, message: message }); - }); -} - -function FnFileSystemCreateFail(pool = { name, id, altroot: false }, filesystem = { name, id, sharesmb }, process = { data, message }) { - let modal = { - hide: true - }; - - filesystem.created = false; - - if (/dataset already exists/gi.test(process.data)) { - modal.hide = false; - - $("#validationwrapper-storagepool-filesystems-create-name-" + pool.id).addClass("has-error"); - $("#helpblock-storagepool-filesystems-create-name-" + pool.id).addClass("has-error").removeClass("hidden").text("Name already exists."); - $("#input-storagepool-filesystems-create-name-" + pool.id).focus(); - } else if (/encryption root's key is not loaded or provided/gi.test(process.data)) { - modal.hide = false; - - $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-" + pool.id).addClass("has-error"); - $("#helpblock-storagepool-filesystems-create-encryption-passphrase-" + pool.id).addClass("has-error").removeClass("hidden").html("Parent file system is locked.
    Unlock parent file system or enter a passphrase to create an independent encryption root."); - $("#input-storagepool-filesystems-create-encryption-passphrase-" + pool.id).focus(); - } else if (/Passphrase requires a minimum of 8 characters./i.test(process.data)) { - modal.hide = false; - - $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-" + pool.id).addClass("has-error"); - $("#helpblock-storagepool-filesystems-create-encryption-passphrase-" + pool.id).addClass("has-error").removeClass("hidden").text("Passphrase requires a minimum of 8 characters."); - $("#input-storagepool-filesystems-create-encryption-passphrase-" + pool.id).focus(); - } else if (/filesystem successfully created/gi.test(process.data)) { - filesystem.created = true; - - FnDisplayAlert({ status: "warning", title: "File system created with errors", description: filesystem.name, breakword: false }, { name: "filesystem-create", id: filesystem.id, timeout: 4 }); - - FnConsole.warn("File Systems, Create: Warning, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (process.data ? process.data : process.message)); - - if (filesystem.sharesmb == "on" && zfsmanager.configuration.samba.manage) { - $("#spinner-storagepool-filesystems-create-" + pool.id + " span").text("Enabling Samba share..."); - - FnSambaShareEnableMountpointGet({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { name: filesystem.name, id: filesystem.id, sharesmb: true }, { silent: false }); - } - } - - if (!modal.hide) { - $("#spinner-storagepool-filesystems-create-" + pool.id).addClass("hidden"); - $("#spinner-storagepool-filesystems-create-" + pool.id + " span").text(""); - $("#btn-storagepool-filesystems-create-apply-" + pool.id).prop("disabled", false); - } - - if (!filesystem.created) { - FnConsole.warn("File Systems, Create: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (process.data ? process.data : process.message)); - } - - if (modal.hide) { - if (!filesystem.created) { - FnDisplayAlert({ status: "danger", title: "File System could not be created", description: filesystem.name, breakword: false }, { name: "filesystem-create", id: filesystem.id, timeout: 4 }); - } - - $("#modal-storagepool-filesystems-create-" + pool.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - } -} - -function FnFileSystemDestroy(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, force: false, recursive: false, recursiveall: false, sharesmb: false, type }, samba = { restart: false }) { - if (samba.restart) { - FnSambaStop() - .finally(function () { - if ((filesystem.recursive || filesystem.recursiveall) && zfsmanager.configuration.samba.manage) { - $("#spinner-storagepool-filesystem-destroy-" + filesystem.id + " span").text("Retrieving Samba shares..."); - - FnSambaSharesGet({ name: pool.name, id: pool.id }, { name: filesystem.name, clones: [] }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Shares, Get:" })); - - let filesystems = { - id: data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) - }; - - $("#spinner-storagepool-filesystem-destroy-" + filesystem.id + " span").text("Destroying " + filesystem.type.toLowerCase() + "s..."); - - if (filesystems.id.length > 0) { - FnFileSystemDestroyCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, force: filesystem.force, recursive: filesystem.recursive, recursiveall: filesystem.recursiveall }, { refresh: false }) - .done(function () { - $("#spinner-storagepool-filesystem-destroy-" + filesystem.id + " span").text("Destroying Samba shares..."); - - FnSambaSharesDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { id: filesystems.id }, { restart: samba.restart }, { silent: true }) - .finally(function () { - $("#modal-storagepool-filesystem-destroy-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - }); - }); - } else { - FnFileSystemDestroyCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, force: filesystem.force, recursive: filesystem.recursive, recursiveall: filesystem.recursiveall }, { refresh: true }) - } - }) - .fail(function (message, data) { - FnFileSystemDestroyFail({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }, { data: data, message: message }, { refresh: true }); - FnSambaStart(); - }); - } else { - $("#spinner-storagepool-filesystem-destroy-" + filesystem.id + " span").text("Destroying " + filesystem.type.toLowerCase() + "..."); - - if (filesystem.sharesmb && zfsmanager.configuration.samba.manage) { - FnFileSystemDestroyCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, force: filesystem.force, recursive: filesystem.recursive, recursiveall: filesystem.recursiveall }, { refresh: false }) - .done(function () { - $("#spinner-storagepool-filesystem-destroy-" + filesystem.id + " span").text("Destroying Samba share..."); - - FnSambaShareDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { name: filesystem.name, id: filesystem.id }, { restart: samba.restart }, { silent: true }) - .finally(function () { - $("#modal-storagepool-filesystem-destroy-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - }); - }); - } else { - FnFileSystemDestroyCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, force: filesystem.force, recursive: filesystem.recursive, recursiveall: filesystem.recursiveall }, { refresh: true }) - .finally(function () { - if (!filesystem.sharesmb || !zfsmanager.configuration.samba.manage) { - FnSambaStart(); - } - }); - } - } - }); - } else { - if ((filesystem.recursive || filesystem.recursiveall) && zfsmanager.configuration.samba.manage) { - $("#spinner-storagepool-filesystem-destroy-" + filesystem.id + " span").text("Retrieving Samba shares..."); - - FnSambaSharesGet({ name: pool.name, id: pool.id }, { name: filesystem.name, clones: [] }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Shares, Get:" })); - - let filesystems = { - id: data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) - }; - - $("#spinner-storagepool-filesystem-destroy-" + filesystem.id + " span").text("Destroying " + filesystem.type.toLowerCase() + "s..."); - - if (filesystems.id.length > 0) { - FnFileSystemDestroyCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, force: filesystem.force, recursive: filesystem.recursive, recursiveall: filesystem.recursiveall }, { refresh: false }) - .done(function () { - $("#spinner-storagepool-filesystem-destroy-" + filesystem.id + " span").text("Destroying Samba shares..."); - - FnSambaSharesDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { id: filesystems.id }, { restart: samba.restart }, { silent: true }) - .finally(function () { - $("#modal-storagepool-filesystem-destroy-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - }); - }); - } else { - FnFileSystemDestroyCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, force: filesystem.force, recursive: filesystem.recursive, recursiveall: filesystem.recursiveall }, { refresh: true }) - } - }) - .fail(function (message, data) { - FnFileSystemDestroyFail({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }, { data: data, message: message }, { refresh: true }); - }); - } else { - $("#spinner-storagepool-filesystem-destroy-" + filesystem.id + " span").text("Destroying " + filesystem.type.toLowerCase() + "..."); - - if (filesystem.sharesmb && zfsmanager.configuration.samba.manage) { - FnFileSystemDestroyCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, force: filesystem.force, recursive: filesystem.recursive, recursiveall: filesystem.recursiveall }, { refresh: false }) - .done(function () { - $("#spinner-storagepool-filesystem-destroy-" + filesystem.id + " span").text("Destroying Samba share..."); - - FnSambaShareDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { name: filesystem.name, id: filesystem.id }, { restart: samba.restart }, { silent: true }) - .finally(function () { - $("#modal-storagepool-filesystem-destroy-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - }); - }); - } else { - FnFileSystemDestroyCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, force: filesystem.force, recursive: filesystem.recursive, recursiveall: filesystem.recursiveall }, { refresh: true }) - } - } - } -} - -function FnFileSystemDestroyCommand(pool = { name, id }, filesystem = { name, id, force: false, recursive: false, recursiveall: false }, display = { refresh: true }) { - let process = { - command: ["/sbin/zfs", "destroy", filesystem.name] - }; - - if (filesystem.force) { - process.command.splice(2, 0, "-f"); - } - if (filesystem.recursive) { - process.command.splice(2, 0, "-r"); - } - if (filesystem.recursiveall) { - process.command.splice(2, 0, "-R"); - } - - FnConsole.log[1]("File Systems, Destroy: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "File System successfully destroyed", description: filesystem.name, breakword: false }, { name: "filesystem-destroy", id: filesystem.id, timeout: 4 }); - - FnConsole.log[1]("File Systems, Destroy: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - }) - .fail(function (message, data) { - FnFileSystemDestroyFail({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }, { data: data, message: message }, { refresh: false }); - - display.refresh = true; - }) - .finally(function () { - if (display.refresh) { - $("#modal-storagepool-filesystem-destroy-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - } - }); -} - -function FnFileSystemDestroyFail(pool = { name, id }, filesystem = { name, id }, process = { data, message }, display = { refresh: true }) { - FnDisplayAlert({ status: "danger", title: "File System could not be destroyed", description: filesystem.name, breakword: false }, { name: "filesystem-destroy", id: filesystem.id, timeout: 4 }); - - FnConsole.warn("File Systems, Destroy: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (process.data ? process.data : process.message)); - - if (display.refresh) { - $("#modal-storagepool-filesystem-destroy-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - } -} - -function FnFileSystemLock(pool = { name, id }, filesystem = { name, id, type }, display = { refresh: true }) { - let process = { - command: ["/sbin/zfs", "unload-key", filesystem.name] - }; - - FnConsole.log[2]("File Systems, Lock: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-storagepool-filesystem-lock-" + filesystem.id + " span").text("Locking " + filesystem.type.toLowerCase() + "..."); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "File System successfully locked", description: filesystem.name, breakword: false }, { name: "filesystem-lock", id: filesystem.id, timeout: 4 }); - - FnConsole.log[1]("File Systems, Lock: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - }) - .fail(function (message, data) { - FnDisplayAlert({ status: "danger", title: "File System could not be locked", description: filesystem.name, breakword: false }, { name: "filesystem-lock", id: filesystem.id, timeout: 4 }); - - FnConsole.warn("File Systems, Lock: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); - }) - .finally(function () { - if (display.refresh) { - $("#modal-storagepool-filesystem-lock-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - } - }); -} - -function FnFileSystemMount(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, overlay: true, type }, samba = { enable: false }, display = { refresh: true }) { - let process = { - command: ["/sbin/zfs", "mount", filesystem.name] - }; - - if (filesystem.overlay) { - process.command.splice(2, 0, "-O"); - } - - FnConsole.log[2]("File Systems, Mount: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-storagepool-filesystem-mount-" + filesystem.id + " span").text("Mounting " + filesystem.type.toLowerCase() + "..."); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "File System successfully mounted", description: filesystem.name, breakword: false }, { name: "filesystem-mount", id: filesystem.id, timeout: 4 }); - - FnConsole.log[1]("File Systems, Mount: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - - if (samba.enable) { - $("#spinner-storagepool-filesystem-mount-" + filesystem.id + " span").text("Enabling Samba share..."); - - if (zfsmanager.configuration.samba.manage) { - FnSambaShareEnableMountpointGet({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, sharesmb: false }, { silent: false }); - } else { - FnFileSystemShareSmbEnable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }); - } - } - }) - .fail(function (message, data) { - if (/filesystem already mounted/gi.test(data)) { - FnDisplayAlert({ status: "warning", title: "File System was already mounted", description: filesystem.name, breakword: false }, { name: "filesystem-mount", id: filesystem.id, timeout: 4 }); - } else { - FnDisplayAlert({ status: "danger", title: "File System could not be mounted", description: filesystem.name, breakword: false }, { name: "filesystem-mount", id: filesystem.id, timeout: 4 }); - } - - FnConsole.warn("File Systems, Mount: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); - }) - .finally(function () { - setTimeout(function () { - $("#modal-storagepool-filesystem-mount-" + filesystem.id).modal("hide"); - - if (display.refresh) { - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: false, status: false }); - }, 200); - } - }, (samba.enable ? 500 : 0)); - }); -} - -function FnFileSystemMountpointGet(pool = { name, id }, filesystem = { name, id }) { - let process = { - command: ["/sbin/zfs", "get", "mountpoint", "-H", "-o", "value", filesystem.name] - }; - - FnConsole.log[2]("File Systems, Mountpoint, Get: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function () { - FnConsole.log[1]("File Systems, Mountpoint, Get: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - }) - .fail(function (message, data) { - FnConsole.warn("File Systems, Mountpoint, Get: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); - }); -} - -function FnFileSystemPromote(pool = { name, id }, filesystem = { name, id, type }) { - let process = { - command: ["/sbin/zfs", "promote", filesystem.name] - }; - - FnConsole.log[2]("File Systems, Promote: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-storagepool-filesystem-promote-" + filesystem.id + " span").text("Promoting " + filesystem.type.toLowerCase() + "..."); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "File System successfully promoted", description: filesystem.name, breakword: false }, { name: "filesystem-promote", id: filesystem.id, timeout: 4 }); - - FnConsole.log[1]("File Systems, Promote: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - }) - .fail(function (message, data) { - FnDisplayAlert({ status: "danger", title: "File System could not be promoted", description: filesystem.name, breakword: false }, { name: "filesystem-promote", id: filesystem.id, timeout: 4 }); - - FnConsole.warn("File Systems, Promote: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); - }) - .finally(function () { - $("#modal-storagepool-filesystem-promote-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - }); -} - -function FnFileSystemRename(pool = { name, id, altroot: false }, filesystem = { name, id, createnonexistparents: false, force: false, namenew, parent, sharesmb: false, type }, samba = { restart: false }) { - if (samba.restart) { - FnSambaStop() - .finally(function () { - if (zfsmanager.configuration.samba.manage) { - $("#spinner-storagepool-filesystem-rename-" + filesystem.id + " span").text("Retrieving Samba shares..."); - - FnSambaSharesGet({ name: pool.name, id: pool.id }, { name: filesystem.name, clones: [] }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Shares, Get:" })); - - let filesystems = { - id: data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) - }; - - $("#spinner-storagepool-filesystem-rename-" + filesystem.id + " span").text("Renaming " + filesystem.type.toLowerCase() + "..."); - - if (filesystems.id.length > 0) { - FnFileSystemRenameCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, createnonexistparents: filesystem.createnonexistparents, force: filesystem.force, namenew: filesystem.namenew, parent: filesystem.parent }, { refresh: false }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Rename:" })); - - if (/dataset already exists/i.test(data) == false) { - $("#spinner-storagepool-filesystem-rename-" + filesystem.id + " span").text("Renaming Samba share" + (filesystems.id.length > 1 ? "s" : "") + "..."); - - FnSambaSharesRename({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, filesystems = { id: filesystems.id, parent: { name: filesystem.name, namenew: filesystem.namenew } }, { restart: samba.restart }, { silent: false }) - .finally(function () { - if (filesystem.createnonexistparents) { - FnFileSystemShareSmbInheritedDisable({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: filesystem.parent }, { disable: true }) - .finally(function () { - $("#modal-storagepool-filesystem-rename-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 500); - }); - } else { - $("#modal-storagepool-filesystem-rename-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 500); - } - }); - - } - }); - } else { - FnFileSystemRenameCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, createnonexistparents: filesystem.createnonexistparents, force: filesystem.force, namenew: filesystem.namenew, parent: filesystem.parent }, { refresh: (filesystem.createnonexistparents ? false : true) }) - .done(function () { - if (filesystem.createnonexistparents) { - $("#spinner-storagepool-filesystem-rename-" + filesystem.id + " span").text("Disabling Samba share inheritance..."); - - FnFileSystemShareSmbInheritedDisable({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: filesystem.parent }, { disable: true }) - .finally(function () { - $("#modal-storagepool-filesystem-rename-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 500); - - FnSambaStart(); - }); - } else { - FnSambaStart(); - } - }) - .fail(function () { - FnSambaStart(); - }); - } - }) - .fail(function (message, data) { - FnFileSystemRenameFail({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, createnonexistparents: filesystem.createnonexistparents, parent: filesystem.parent }, { data: data, message: message }, { refresh: true }); - FnSambaStart(); - }); - } else { - FnFileSystemRenameCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, createnonexistparents: filesystem.createnonexistparents, force: filesystem.force, namenew: filesystem.namenew, parent: filesystem.parent }, { refresh: true }) - .finally(function () { - FnSambaStart(); - }); - } - }); - } else { - if (zfsmanager.configuration.samba.manage) { - $("#spinner-storagepool-filesystem-rename-" + filesystem.id + " span").text("Retrieving Samba shares..."); - - FnSambaSharesGet({ name: pool.name, id: pool.id }, { name: filesystem.name, clones: [] }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Shares, Get:" })); - - let filesystems = { - id: data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) - }; - - $("#spinner-storagepool-filesystem-rename-" + filesystem.id + " span").text("Renaming " + filesystem.type.toLowerCase() + "..."); - - if (filesystems.id.length > 0) { - FnFileSystemRenameCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, createnonexistparents: filesystem.createnonexistparents, force: filesystem.force, namenew: filesystem.namenew, parent: filesystem.parent }, { refresh: false }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Rename:" })); - - if (/dataset already exists/i.test(data) == false) { - $("#spinner-storagepool-filesystem-rename-" + filesystem.id + " span").text("Renaming Samba share" + (filesystems.id.length > 1 ? "s" : "") + "..."); - - FnSambaSharesRename({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, filesystems = { id: filesystems.id, parent: { name: filesystem.name, namenew: filesystem.namenew } }, { restart: samba.restart }, { silent: false }) - .finally(function () { - if (filesystem.createnonexistparents) { - FnFileSystemShareSmbInheritedDisable({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: filesystem.parent }, { disable: true }) - .finally(function () { - $("#modal-storagepool-filesystem-rename-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 500); - }); - } else { - $("#modal-storagepool-filesystem-rename-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 500); - } - }); - } - }); - } else { - FnFileSystemRenameCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, createnonexistparents: filesystem.createnonexistparents, force: filesystem.force, namenew: filesystem.namenew, parent: filesystem.parent }, { refresh: (filesystem.createnonexistparents ? false : true) }) - .done(function () { - if (filesystem.createnonexistparents) { - $("#spinner-storagepool-filesystem-rename-" + filesystem.id + " span").text("Disabling Samba share inheritance..."); - - FnFileSystemShareSmbInheritedDisable({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: filesystem.parent }, { disable: true }) - .finally(function () { - $("#modal-storagepool-filesystem-rename-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 500); - }); - } - }); - } - }) - .fail(function (message, data) { - FnFileSystemRenameFail({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, createnonexistparents: filesystem.createnonexistparents, parent: filesystem.parent }, { data: data, message: message }, { refresh: true }); - }); - } else { - FnFileSystemRenameCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, createnonexistparents: filesystem.createnonexistparents, force: filesystem.force, namenew: filesystem.namenew, parent: filesystem.parent }, { refresh: true }); - } - } -} - -function FnFileSystemRenameCommand(pool = { name, id }, filesystem = { name, id, createnonexistparents: false, force: false, namenew, parent }, display = { refresh: true }) { - let process = { - command: ["/sbin/zfs", "rename", filesystem.name, filesystem.namenew] - }; - - if (filesystem.force) { - process.command.splice(2, 0, "-f"); - } - if (filesystem.createnonexistparents) { - process.command.splice(2, 0, "-p"); - } - - FnConsole.log[1]("File Systems, Rename: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function (data, message) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Rename:" })); - - if (/dataset already exists/i.test(data)) { - FnFileSystemRenameFail({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, createnonexistparents: filesystem.createnonexistparents, parent: filesystem.parent }, { data: data, message: message }, { refresh: true }); - return; - } - - FnDisplayAlert({ status: "success", title: "File System successfully renamed", description: filesystem.name, breakword: false }, { name: "filesystem-rename", id: filesystem.id, timeout: 4 }); - - FnConsole.log[1]("File Systems, Rename: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - - if (display.refresh) { - $("#modal-storagepool-filesystem-rename-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 500); - } - }) - .fail(function (message, data) { - FnFileSystemRenameFail({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, createnonexistparents: filesystem.createnonexistparents, parent: filesystem.parent }, { data: data, message: message }, { refresh: true }); - }); -} - -function FnFileSystemRenameFail(pool = { name, id }, filesystem = { name, id, createnonexistparents: false, parent }, process = { data, message }, display = { refresh: true }) { - let modal = { - hide: true - }; - - if (/dataset already exists/i.test(process.data)) { - modal.hide = false; - - $("#validationwrapper-storagepool-filesystem-rename-name-" + filesystem.id).addClass("has-error"); - $("#helpblock-storagepool-filesystem-rename-name-" + filesystem.id).addClass("has-error").removeClass("hidden").text("Name already exists."); - $("#input-storagepool-filesystem-rename-name-" + filesystem.id).focus(); - } else if (/parent does not exist/i.test(process.data)) { - modal.hide = false; - - $("#validationwrapper-storagepool-filesystem-rename-name-" + filesystem.id).addClass("has-error"); - $("#helpblock-storagepool-filesystem-rename-name-" + filesystem.id).addClass("has-error").removeClass("hidden").text("Parent file system does not exist."); - $("#input-storagepool-filesystem-rename-name-" + filesystem.id).focus(); - } - - if (!modal.hide) { - $("#spinner-storagepool-filesystem-rename-" + filesystem.id).addClass("hidden"); - $("#spinner-storagepool-filesystem-rename-" + filesystem.id + " span").text(""); - $("#btn-storagepool-filesystem-rename-apply-" + filesystem.id).prop("disabled", false); - } - - FnConsole.warn("File Systems, Rename: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (process.data ? process.data : process.message)); - - if (modal.hide) { - FnDisplayAlert({ status: "danger", title: "File System could not be renamed", description: filesystem.name, breakword: false }, { name: "filesystem-rename", id: filesystem.id, timeout: 4 }); - - $("#modal-storagepool-filesystem-rename-" + filesystem.id).modal("hide"); - - if (display.refresh) { - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - } - } -} - -function FnFileSystemSelinuxContextsSambaSet(pool = { name, id }, filesystem = { name }) { - let process = { - command: ["/sbin/zfs", "set", "context=system_u:object_r:samba_share_t:s0", "defcontext=system_u:object_r:samba_share_t:s0", "fscontext=system_u:object_r:samba_share_t:s0", "rootcontext=system_u:object_r:samba_share_t:s0", filesystem.name] - }; - - FnConsole.log[2]("File Systems, SELinux Contexts, Samba, Set: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnConsole.log[1]("File Systems, SELinux Contexts, Samba, Set: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - }) - .fail(function (message, data) { - FnConsole.warn("File Systems, SELinux Contexts, Samba, Set: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); - }) -} - -function FnFileSystemShareSmbDisable(pool = { name, id }, filesystem = { name, id }) { - let process = { - command: ["/sbin/zfs", "set", "sharesmb=off", filesystem.name] - }; - - FnConsole.log[2]("File Systems, Share SMB, Disable: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnConsole.log[1]("File Systems, Share SMB, Disable: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - }) - .fail(function (message, data) { - if (/property may be set/gi.test(data)) { //False error is generated when configuring filesystem - FnConsole.log[1]("File Systems, Share SMB, Disable: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - } else { - FnConsole.warn("File Systems, Share SMB, Disable: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); - } - }); -} - -function FnFileSystemShareSmbEnable(pool = { name, id }, filesystem = { name, id }) { - let process = { - command: ["/sbin/zfs", "set", "sharesmb=on", filesystem.name] - }; - - FnConsole.log[2]("File Systems, Share SMB, Enable: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnConsole.log[1]("File Systems, Share SMB, Enable: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - }) - .fail(function (message, data) { - if (/property may be set/gi.test(data)) { //False error is generated when configuring filesystem - FnConsole.log[1]("File Systems, Share SMB, Enable: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - } else { - FnConsole.warn("File Systems, Share SMB, Enable: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); - } - }); -} - -function FnFileSystemShareSmbInheritedDisable(pool = { name, id, altroot: false }, filesystem = { name }, force = { disable: false }) { - let process = { - command: ["/sbin/zfs", "get", "-H", "name,sharesmb", "-o", "property,value,source", "-r", "-t", "filesystem"], - promise: cockpit.defer() - }; - - if (filesystem.name) { - process.command.push(filesystem.name); - } else if (pool.name) { - process.command.push(pool.name); - } - - FnConsole.log[2]("File Systems, Share SMB, Inherited, Disable: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Share SMB, Inherited, Disable:" })); - - let filesystems = data.replace(/\nsharesmb/g, "\u22C5sharesmb").replace(/\t+/g, "\u22C5").split(/\n/g).filter(v => v && /\u22C5sharesmb\u22C5on\u22C5inherited from|\u22C5sharesmb\u22C5off\u22C5inherited from/gi.test(v)); - let promise = Promise.resolve(); - - if (filesystems.length > 0) { - filesystems.forEach((_value, _index) => { - _value = _value.split("\u22C5"); - - let filesystem = { - name: _value[1], - id: FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: _value[1], attribute: true }), - sharesmb: { - enabled: (_value[4].toLowerCase() == "on" ? true : false), - source: _value[5] - } - }; - let pool = { - name: filesystem.name.replace(/\/.*$/, ""), - id: FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: filesystem.name, attribute: true }) - }; - - promise = promise.then(_ => new Promise(resolve => - setTimeout(function () { - if (filesystem.sharesmb.enabled && !force.disable) { - FnFileSystemShareSmbEnable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }) - .finally(function () { - if (_index == (filesystems.length - 1)) { - FnConsole.log[1]("File Systems, Share SMB, Inherited, Disable: Success"); - - process.promise.resolve(); - } - }); - } else { - if (force.disable) { - FnSambaShareDisable({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { name: filesystem.name, id: filesystem.id }, { restart: false }, { modal: false, silent: true }); - - if (_index == (filesystems.length - 1)) { - setTimeout(function () { - FnConsole.log[1]("File Systems, Share SMB, Inherited, Disable: Success"); - - process.promise.resolve(); - }, 1000); - } - } else { - FnFileSystemShareSmbDisable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }) - .finally(function () { - if (_index == (filesystems.length - 1)) { - FnConsole.log[1]("File Systems, Share SMB, Inherited, Disable: Success"); - - process.promise.resolve(); - } - }); - } - } - - resolve(); - }, (force.disable ? 1000 : 500)) - )); - }); - } else { - FnConsole.log[1]("File Systems, Share SMB, Inherited, Disable: Success" + (pool.name ? ", Pool: " + pool.name : "")); - - process.promise.resolve(); - } - }) - .fail(function (message, data) { - FnConsole.warn("File Systems, Share SMB, Inherited, Disable: Failed" + ", Message: " + (data ? data : message)); - - process.promise.resolve(); - }); - - return process.promise.promise(); -} - -function FnFileSystemUnlock(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, mount: true, overlay: true, passphrase, type }, samba = { enable: false }, modal = { name, id }, display = { refresh: true }) { - let process = { - command: [] - }; - - modal.id = (modal.id ? "-" + modal.id : ""); - - //Escape percentage and single quote special character for printf - if (/\%/g.test(filesystem.passphrase)) { - filesystem.passphrase = filesystem.passphrase.replace(/\%/g, "\%\%"); - } - if (/\'/g.test(filesystem.passphrase)) { - filesystem.passphrase = filesystem.passphrase.replace(/\'/g, "\'\"\'\"\'"); - } - - process.command = ["/bin/sh", "-c", "printf '" + filesystem.passphrase + "' | /sbin/zfs load-key \"" + filesystem.name + "\""]; - - FnConsole.log[2]("File Systems, Unlock: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - if (display.refresh) { - $("#spinner-" + modal.name + modal.id + " span").text("Unlocking " + filesystem.type.toLowerCase() + "..."); - } - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function (data, message) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Unlock:" })); - - if (/error|Incorrect key/i.test(data)) { - FnFileSystemUnlockFail({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, type: filesystem.type }, { name: modal.name, id: modal.id }, { refresh: display.refresh }, { data: data, message: message }); - return; - } - - FnDisplayAlert({ status: "success", title: "File System successfully unlocked", description: filesystem.name, breakword: false }, { name: "filesystem-unlock", id: filesystem.id, timeout: 4 }); - - FnConsole.log[1]("File Systems, Unlock: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - - if (filesystem.mount) { - setTimeout(function () { - FnFileSystemMount({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, overlay: filesystem.overlay, type: filesystem.type }, { enable: samba.enable }, { refresh: display.refresh }) - .finally(function () { - if (display.refresh) { - $("#modal-" + modal.name + modal.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - } - }); - }, 200); - } else if (display.refresh) { - $("#modal-" + modal.name + modal.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - } - }) - .fail(function (message, data) { - if (/Key already loaded/i.test(data)) { - FnFileSystemUnlockWarn({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, mount: filesystem.mount, overlay: filesystem.overlay, type: filesystem.type }, { enable: samba.enable }, { name: modal.name, id: modal.id }, { refresh: display.refresh }, { data: data, message: message }); - } else { - FnFileSystemUnlockFail({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, type: filesystem.type }, { name: modal.name, id: modal.id }, { refresh: display.refresh }, { data: data, message: message }); - } - }); -} - -function FnFileSystemUnlockFail(pool = { name, id }, filesystem = { name, id, type }, modal = { name, id }, display = { refresh: true }, process = { data, message }) { - modal.hide = true; - - if (/Incorrect key provided/gi.test(process.data)) { - modal.hide = false; - - $("#validationwrapper-" + modal.name + "-passphrase" + modal.id).addClass("has-error"); - $("#helpblock-" + modal.name + "-passphrase" + modal.id).addClass("has-error").removeClass("hidden").text("Passphrase is incorrect."); - $("#input-" + modal.name + "-passphrase" + modal.id).focus(); - } - - if (!modal.hide && display.refresh) { - $("#spinner-" + modal.name + modal.id).addClass("hidden"); - $("#spinner-" + modal.name + modal.id + " span").text(""); - $("#btn-" + modal.name + "-apply" + modal.id).prop("disabled", false); - } - - if (modal.hide || !display.refresh) { - FnDisplayAlert({ status: "danger", title: "File System could not be unlocked", description: filesystem.name, breakword: false }, { name: "filesystem-unlock", id: filesystem.id, timeout: 4 }); - } - - if (modal.hide) { - if (display.refresh) { - $("#modal-" + modal.name + modal.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - } - } - - FnConsole.warn("File Systems, Unlock: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (process.data ? process.data : process.message)); -} - -function FnFileSystemUnlockWarn(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, mount: true, overlay: true, type }, samba = { enable: false }, modal = { name, id }, display = { refresh: true }, process = { data, message }) { - FnDisplayAlert({ status: "warning", title: "File System was already unlocked", description: filesystem.name, breakword: false }, { name: "filesystem-unlock", id: filesystem.id, timeout: 4 }); - - FnConsole.warn("File Systems, Unlock: Warning, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (process.data ? process.data : process.message)); - - if (filesystem.mount) { - setTimeout(function () { - FnFileSystemMount({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, overlay: filesystem.overlay, type: filesystem.type }, { enable: samba.enable }, { refresh: display.refresh }) - .finally(function () { - if (display.refresh) { - $("#modal-" + modal.name + modal.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - } - }); - }, 200); - } else if (display.refresh) { - $("#modal-" + modal.name + modal.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - } -} - -function FnFileSystemUnmount(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, force: false, lock: false, type }, samba = { disable: false, restart: false }) { - if (samba.restart) { - FnSambaStop() - .finally(function () { - $("#spinner-storagepool-filesystem-unmount-" + filesystem.id + " span").text("Unmounting " + filesystem.type.toLowerCase() + "..."); - - FnFileSystemUnmountCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, force: filesystem.force, lock: filesystem.lock }, { refresh: ((filesystem.lock || samba.disable) ? false : true) }) - .done(function () { - if (filesystem.lock) { - $("#spinner-storagepool-filesystem-unmount-" + filesystem.id + " span").text("Locking " + filesystem.type.toLowerCase() + "..."); - - FnFileSystemLock({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, type: filesystem.type }, { refresh: false }) - .finally(function () { - if (samba.disable) { - $("#spinner-storagepool-filesystem-unmount-" + filesystem.id + " span").text("Disabling Samba share..."); - - if (zfsmanager.configuration.samba.manage) { - FnSambaShareDisable({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id }, { restart: samba.restart }, { modal: false, silent: false }); - } else { - FnFileSystemShareSmbDisable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }); - } - } - - setTimeout(function () { - $("#modal-storagepool-filesystem-unmount-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - }, (samba.disable ? 1000 : 200)); - }); - } else { - if (samba.disable) { - $("#spinner-storagepool-filesystem-unmount-" + filesystem.id + " span").text("Disabling Samba share..."); - - if (zfsmanager.configuration.samba.manage) { - FnSambaShareDisable({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id }, { restart: samba.restart }, { modal: false, silent: false }); - } else { - FnFileSystemShareSmbDisable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }); - } - } - - setTimeout(function () { - $("#modal-storagepool-filesystem-unmount-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - }, (samba.disable ? 1000 : 200)); - } - }) - .finally(function () { - if (!samba.disable || !zfsmanager.configuration.samba.manage) { - FnSambaStart(); - } - }); - }); - } else { - $("#spinner-storagepool-filesystem-unmount-" + filesystem.id + " span").text("Unmounting " + filesystem.type.toLowerCase() + "..."); - - FnFileSystemUnmountCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, force: filesystem.force, lock: filesystem.lock }, { refresh: ((filesystem.lock || samba.disable) ? false : true) }) - .done(function () { - if (filesystem.lock) { - $("#spinner-storagepool-filesystem-unmount-" + filesystem.id + " span").text("Locking " + filesystem.type.toLowerCase() + "..."); - - FnFileSystemLock({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, type: filesystem.type }, { refresh: false }) - .finally(function () { - if (samba.disable) { - $("#spinner-storagepool-filesystem-unmount-" + filesystem.id + " span").text("Disabling Samba share..."); - - if (zfsmanager.configuration.samba.manage) { - FnSambaShareDisable({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id }, { restart: samba.restart }, { modal: false, silent: false }); - } else { - FnFileSystemShareSmbDisable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }); - } - } - - setTimeout(function () { - $("#modal-storagepool-filesystem-unmount-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - }, (samba.disable ? 1000 : 200)); - }); - } else { - if (samba.disable) { - $("#spinner-storagepool-filesystem-unmount-" + filesystem.id + " span").text("Disabling Samba share..."); - - if (zfsmanager.configuration.samba.manage) { - FnSambaShareDisable({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id }, { restart: samba.restart }, { modal: false, silent: false }); - } else { - FnFileSystemShareSmbDisable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }); - } - } - - setTimeout(function () { - $("#modal-storagepool-filesystem-unmount-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - }, (samba.disable ? 1000 : 200)); - } - }); - } -} - -function FnFileSystemUnmountCommand(pool = { name, id }, filesystem = { name, id, force: false, lock: false }, display = { refresh: true }) { - let process = { - command: ["/sbin/zfs", "unmount", filesystem.name] - }; - - if (filesystem.force) { - process.command.splice(2, 0, "-f"); - } - - FnConsole.log[2]("File Systems, Unmount: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "File System successfully unmounted", description: filesystem.name, breakword: false }, { name: "filesystem-unmount", id: filesystem.id, timeout: 4 }); - - FnConsole.log[1]("File Systems, Unmount: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - - if (display.refresh) { - $("#modal-storagepool-filesystem-unmount-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - } - }) - .fail(function (message, data) { - FnDisplayAlert({ status: "danger", title: "File System could not be unmounted", description: filesystem.name, breakword: false }, { name: "filesystem-unmount", id: filesystem.id, timeout: 4 }); - - FnConsole.warn("File Systems, Unmount: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); - - $("#modal-storagepool-filesystem-unmount-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - }); -} - -//#endregion - -//#region Snapshots - -function FnSnapshotsGet(pool = { name, id }) { - let process = { - command: ["/sbin/zfs", "list", "-H", "-o", "name,creation,used,refer,encryption,encryptionroot,keystatus,clones", "-r", "-p", "-t", "snapshot", pool.name] - }; - let snapshots = { - empty: true - }; - - pool.altroot = (($("#tr-storagepool-" + pool.id).attr("data-pool-altroot") == "true") ? true : false); - pool.readonly = (($("#tr-storagepool-" + pool.id).attr("data-pool-readonly") == "true") ? true : false); - - FnConsole.log[2]("Snapshots, Get: In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data, message) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Snapshots, Get:" })); - - if (data) { - snapshots.empty = false; - - FnSnapshotsGetCommand({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { data: data, message: message }); - } - - FnConsole.log[1]("Snapshots, Get: Success, Pool: " + pool.name); - }) - .fail(function (message, data) { - FnConsole.warn("Snapshots, Get: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); - }) - .finally(function () { - if (snapshots.empty) { - if (zfsmanager.configuration.zfs.snapshot.filesystemlist) { - $("#div-storagepool-snapshots-" + pool.id).empty(); - } - $("#tbody-storagepool-snapshots-" + pool.id).empty(); - $("#" + (zfsmanager.configuration.zfs.snapshot.filesystemlist ? "div" : "tbody") + "-storagepool-snapshots-" + pool.id).append((zfsmanager.configuration.zfs.snapshot.filesystemlist ? `` : ``) + `` + (zfsmanager.configuration.zfs.snapshot.filesystemlist ? `
    No snapshots found.
    ` : ``)); - $("#modals-storagepool-snapshots-" + pool.id).remove(); - $("#modals-storagepool-snapshot-" + pool.id).remove(); - $("#modals").append(`
    `); - - //Register snapshots modals - if (!pool.readonly) { - FnModalSnaphshotsCreate({ name: pool.name, id: pool.id }); - } - - $("#tr-storagepool-" + pool.id).attr("data-pool-refresh-snapshots", "true"); - - $("#spinner-storagepool-snapshots-" + pool.id).addClass("hidden"); - $("#paneltitle-storagepool-snapshots-" + pool.id).removeClass("hidden").text(FnDateTime()); - $("#btn-storagepool-snapshots-create-" + pool.id).prop("disabled", false); - $("#btn-storagepool-snapshots-refresh-" + pool.id).prop("disabled", false); - } - - FnStoragePoolSpinnerHide({ name: pool.name, id: pool.id }); - FnCockpitElementsUpdate(); - }); -} - -function FnSnapshotsGetCommand(pool = { name, id, altroot: false, readonly: false }, process = { data, message }) { - let snapshots = { - data: process.data.split(/\n/g).filter(v => v), - filesystemlist: { - count: 0, - name: "" - } - }; - - if (zfsmanager.configuration.zfs.snapshot.filesystemlist) { - $("#div-storagepool-snapshots-" + pool.id).empty(); - } - $("#tbody-storagepool-snapshots-" + pool.id).empty(); - $("#modals-storagepool-snapshots-" + pool.id).remove(); - $("#modals-storagepool-snapshot-" + pool.id).remove(); - $("#modals").append(`
    `); - $("#modals").append(`
    `); - - snapshots.data.forEach((_value, _index) => { - let snapshot = { - properties: _value.split(/\t/g).filter(v => v), - clones: [], - creation: "", - encryption: false, - encryptionroot: "", - id: "", - keystatus: "", - name: "", - actionsmenu: { - register: {} - } - }; - - if (!snapshot.properties[7]) { //Append clones property if not included after split - snapshot.properties[7] = ""; - } - - snapshot.filesystem = { - id: FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: snapshot.properties[0].replace(/^(.*)\@.*$/, "$1"), attribute: true }) - }; - - snapshot.output = ""; - - if (zfsmanager.configuration.zfs.snapshot.filesystemlist) { - if (_index == 0 || (snapshots.filesystemlist.name != "" && snapshots.filesystemlist.name != snapshot.properties[0].replace(/^(.*)\@.*$/, "$1"))) { - snapshot.output += ` - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#table-storagepool-snapshots-listing-` + snapshot.filesystem.id + ` > tbody > tr.listing-ct-item").on("click", function () { - if (!$(this).parent().hasClass("open")) { - $(this).parent().addClass("open"); - } else { - $(this).parent().removeClass("open"); - } - }); - \x3C/script> - - - - - - - - - -
    Name:` + snapshot.properties[0].replace(/^(.*)\@.*$/, "$1") + (zfsmanager.configuration.zfs.storagepool.count ? ` ` : ``) + `
    - - -
    -
    - `; + } + } +}); - $("#div-storagepool-snapshots-" + pool.id).append(snapshot.output); +//#endregion - snapshot.output = ""; - snapshots.filesystemlist.count = 0; - } - - snapshots.filesystemlist.count++; - $("#span-storagepool-snapshots-listing-" + snapshot.filesystem.id + "-count").html(snapshots.filesystemlist.count); - } - - snapshot.output += ``; - - snapshot.properties.forEach((__value, __index) => { - //0=name, 1=creation, 2=used, 3=refer, 4=encryption, 5=encryptionroot, 6=keystatus, 7=clones - - switch (__index) { - case 0: //0=name - snapshot.name = __value; - snapshot.id = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: snapshot.name, attribute: true }); - - snapshot.output += `Name:` + __value + ``; - break; - case 1: //1=creation - snapshot.creation = __value; - - snapshot.output += `Created:` + FnDateTimeEpoch({ date: __value }) + ``; - break; - case 2: //2=used - snapshot.output += `Used:` + FnFormatBytes({ base2: true, decimals: 2, value: __value }) + ``; - break; - case 3: //3=refer - snapshot.output += `Referenced:` + FnFormatBytes({ base2: true, decimals: 2, value: __value }) + ``; - break; - case 4: //4=encryption - if (__value.toLowerCase() != "off") { - snapshot.encryption = true; - } else { - snapshot.encryption = false; - } - break; - case 5: //5=encryptionroot - snapshot.encryptionroot = __value; - break; - case 6: //6=keystatus - snapshot.keystatus = __value; - break; - case 7: //7=clones - snapshot.clones = __value.split(",").filter(v => v).sort(); - - snapshot.output += `Clones:` + (snapshot.clones.length > 0 ? snapshot.clones.join(", ") : `None`) + ``; - break; - } - - //Add action menu at end of array - if (__index >= (snapshot.properties.length - 1)) { - snapshot.icons = { - keystatus: { - locked: ``, - unlocked: `` - } - }; - - snapshot.output += `Encrypted:` + (/available|unavailable/.test(snapshot.keystatus) ? `Yes` : `No`) + ``; - - if (snapshot.keystatus == "unavailable") { - snapshot.output += snapshot.icons.keystatus.locked; - } else if (snapshot.keystatus == "available") { - snapshot.output += snapshot.icons.keystatus.unlocked; - } - - snapshot.output += ``; - - //Actions menu - snapshot.actionsmenu.items = { - item: [], - itemdivider: function () { - if (this.item.length > 0 && this.itemdestroy.length > 0) { - this.item.push(this.divider); - } - }, - itemdestroy: [], - divider: `` - }; - snapshot.actionsmenu.display = function () { - if ((this.items.item.length + this.items.itemdestroy.length) > 0 || pool.readonly) { - this.items.itemdivider(); - - return this.header + this.items.item.join("\n") + this.items.itemdestroy.join("\n") + this.footer; - } else { - return ""; - } - }; - snapshot.actionsmenu.header = ` - - `; - - //Clone Snapshot - if (!pool.readonly) { - snapshot.actionsmenu.items.item.push(`
  • Clone Snapshot
  • `); - - snapshot.actionsmenu.register.clone = true; - } - - //Rename Snapshot - if (!pool.readonly && snapshot.name != pool.name) { - snapshot.actionsmenu.items.item.push(`
  • Rename Snapshot
  • `); - - snapshot.actionsmenu.register.rename = true; - } - - //Roll Back Snapshot - if (!pool.readonly) { - snapshot.actionsmenu.items.item.push(`
  • Roll Back Snapshot
  • `); - - snapshot.actionsmenu.register.rollback = true; - } - - //Destroy Snapshot - if (!pool.readonly) { - snapshot.actionsmenu.items.itemdestroy.push(`
  • Destroy Snapshot
  • `); - - snapshot.actionsmenu.register.destroy = true; - } - - snapshot.output += `` + snapshot.actionsmenu.display() + ``; - } - }); - - snapshot.output += ``; - - if (zfsmanager.configuration.zfs.snapshot.filesystemlist) { - $("#tbody-storagepool-snapshots-list-" + snapshot.filesystem.id).append(snapshot.output); - - snapshots.filesystemlist.name = snapshot.properties[0].replace(/^(.*)\@.*$/, "$1"); - } else { - $("#tbody-storagepool-snapshots-" + pool.id).append(snapshot.output); - } - - - //Register snapshot modals - if (snapshot.actionsmenu.register.clone) { - FnModalSnapshotClone({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: snapshot.name, id: snapshot.id, encryption: snapshot.encryption, encryptionroot: snapshot.encryptionroot }); - } - if (snapshot.actionsmenu.register.destroy) { - FnModalSnapshotDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: snapshot.name, id: snapshot.id, clones: snapshot.clones }); - } - if (snapshot.actionsmenu.register.rename) { - FnModalSnapshotRename({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, creation: snapshot.creation }); - } - if (snapshot.actionsmenu.register.rollback) { - FnModalSnapshotRollBack({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: snapshot.name, id: snapshot.id, creation: snapshot.creation }); - } - }); - - //Register snapshots modals - if (!pool.readonly) { - FnModalSnaphshotsCreate({ name: pool.name, id: pool.id }); - } - - $("#tr-storagepool-" + pool.id).attr("data-pool-refresh-snapshots", "true"); - - $("#spinner-storagepool-snapshots-" + pool.id).addClass("hidden"); - $("#paneltitle-storagepool-snapshots-" + pool.id).removeClass("hidden").html(FnDateTime() + (zfsmanager.configuration.zfs.storagepool.count ? ` ` + snapshots.data.length + `` : ``)); - $("#btn-storagepool-snapshots-create-" + pool.id).prop("disabled", false); - $("#btn-storagepool-snapshots-refresh-" + pool.id).prop("disabled", false); - - FnStoragePoolSpinnerHide({ name: pool.name, id: pool.id }); - FnCockpitElementsUpdate(); -} - -//#endregion - -//#region Snapshot - -function FnSnapshotChildFileSystemsGet(pool = { name, id }, snapshot = { name, id }, filesystems = { id: [] }, modal = { name, id }) { - let process = { - command: ["/sbin/zfs", "list", "-H", "-o", "name", "-r", "-t", "filesystem"] - }; - - filesystems.id.forEach(_value => _value && process.command.push(_value)); - - FnConsole.log[2]("Snapshots, Child, File Systems, Get: In Progress, Pool: " + pool.name + ", Snapshot: " + snapshot.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Snapshots, Child, File Systems, Get:" })); - - let filesystems = { - id: data.split(/\n/g).filter(v => v), - count: { - filesystems: 0 - } - }; - - if (filesystems.id.length > 0) { - filesystems.id.forEach((_value, _index) => { - if (_value != snapshot.name.replace(/^(.*)\@.*$/, "$1")) { - filesystems.count.filesystems++; - - $("#ul-" + modal.name + "-child-filesystems-" + modal.id).append("
  • " + _value + "
  • \n"); - } - }); - - $("#panelgroup-" + modal.name + "-" + modal.id).attr("data-snapshot-child-filesystems", filesystems.count.filesystems); - } - - FnConsole.log[1]("Snapshots, Child, File Systems, Get: Success, Pool: " + pool.name + ", Snapshot: " + snapshot.name); - }) - .fail(function (message, data) { - FnConsole.warn("Snapshots, Child, File Systems, Get: Failed, Pool: " + pool.name + ", Snapshot: " + snapshot.name + ", Message: " + (data ? data : message)); - }); -} - -function FnSnapshotChildSnapshotsGet(pool = { name, id }, snapshot = { name, id, exclude: false }, filesystems = { id: [] }, modal = { name, id }) { - let process = { - command: ["/sbin/zfs", "list", "-H", "-o", "name", "-r", "-t", "snapshot"] - }; - - if (!snapshot.exclude) { - process.command.push(snapshot.name.replace(/^(.*)\@.*$/, "$1")); - } - - filesystems.id.forEach(_value => _value && process.command.push(_value)); - - FnConsole.log[2]("Snapshots, Child, Snapshots, Get: In Progress, Pool: " + pool.name + ", Snapshot: " + snapshot.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Snapshots, Child, Snapshots, Get:" })); - - let snapshots = { - id: data.split(/\n/g).filter(v => v), - count: { - snapshots: 0, - snapshotswithclones: (snapshot.exclude ? $("#panelgroup-" + modal.name + "-" + modal.id).attr("data-snapshot-child-snapshotswithclones") : 0) //Exclude for Roll Back and append - } - }; - - if (snapshots.id.length > 0) { - snapshots.id.forEach((_value, _index) => { - if (_value != snapshot.name) { - //Recursive all will delete child file system snapshots with same name only. If clones are also found, all clone snapshots will be deleted - if (new RegExp("^" + snapshot.name.replace(/^(.*)\@.*$/, "$1") + "/.*@" + snapshot.name.replace(/^.*\@(.*)$/, "$1") + "$").test(_value)) { //Child file system snapshots with same name - if (!snapshot.exclude) { - snapshots.count.snapshots++; - - $("#ul-" + modal.name + "-child-snapshots-" + modal.id).append("
  • " + _value + "
  • \n"); - } - - snapshots.count.snapshotswithclones++; - - $("#ul-" + modal.name + "-child-snapshotswithclones-" + modal.id).append("
  • " + _value + "
  • \n"); - } else { - filesystems.id.forEach((__value, __index) => { - if (new RegExp("^" + __value.replace(/^(.*)\@.*$/, "$1") + "@").test(_value) || new RegExp("^" + __value.replace(/^(.*)\@.*$/, "$1") + "/.*@").test(_value)) { //Snapshots of clone file system - snapshots.count.snapshotswithclones++; - - $("#ul-" + modal.name + "-child-snapshotswithclones-" + modal.id).append("
  • " + _value + "
  • \n"); - } - }); - } - } - }); - - if (!snapshot.exclude) { - $("#panelgroup-" + modal.name + "-" + modal.id).attr("data-snapshot-child-snapshots", snapshots.count.snapshots); - } - $("#panelgroup-" + modal.name + "-" + modal.id).attr("data-snapshot-child-snapshotswithclones", snapshots.count.snapshotswithclones); - } - - FnConsole.log[1]("Snapshots, Child, Snapshots, Get: Success, Pool: " + pool.name + ", Snapshot: " + snapshot.name); - }) - .fail(function (message, data) { - FnConsole.warn("Snapshots, Child, Snapshots, Get: Failed, Pool: " + pool.name + ", Snapshot: " + snapshot.name + ", Message: " + (data ? data : message)); - }); -} - -function FnSnapshotClone(pool = { name, id, altroot: false }, snapshot = { name, id, clone: { name, createnonexistparents: false, parent } }) { - let process = { - command: ["/sbin/zfs", "clone", "-o", "sharenfs=off", "-o", "sharesmb=off", snapshot.name, snapshot.clone.name] - }; - - if (snapshot.clone.createnonexistparents) { - process.command.splice(2, 0, "-p"); - } - - FnConsole.log[2]("Snapshots, Clone: In Progress, Pool: " + pool.name + ", Snapshot: " + snapshot.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-storagepool-snapshot-clone-" + snapshot.id + " span").text("Cloning snapshot..."); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function (data, message) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Snapshots, Clone:" })); - - if (/dataset already exists/i.test(data)) { - FnSnapshotCloneFail({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id }, { data: data, message: message }); - return; - } - - FnDisplayAlert({ status: "success", title: "Snapshot successfully cloned", description: snapshot.name, breakword: false }, { name: "snapshot-clone", id: snapshot.id, timeout: 4 }); - - FnConsole.log[1]("Snapshots, Clone: Success, Pool: " + pool.name + ", Snapshot: " + snapshot.name); - - if (snapshot.clone.createnonexistparents && zfsmanager.configuration.samba.manage) { - $("#spinner-storagepool-snapshot-clone-" + snapshot.id + " span").text("Disabling Samba share inheritance..."); - - FnFileSystemShareSmbInheritedDisable({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: snapshot.clone.parent }, { disable: true }) - .finally(function () { - $("#modal-storagepool-snapshot-clone-" + snapshot.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - }); - } else { - $("#modal-storagepool-snapshot-clone-" + snapshot.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - } - }) - .fail(function (message, data) { - FnSnapshotCloneFail({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id }, { data: data, message: message }); - }); -} - -function FnSnapshotCloneFail(pool = { name, id }, snapshot = { name, id }, process = { data, message }) { - let modal = { - hide: true - }; - - if (/filesystem successfully created/gi.test(process.data)) { - FnDisplayAlert({ status: "warning", title: "Snapshot cloned with errors", description: snapshot.name, breakword: false }, { name: "snapshot-clone", id: snapshot.id, timeout: 4 }); - - FnConsole.warn("Snapshots, Clone: Warning, Pool: " + pool.name + ", Snapshot: " + snapshot.name + ", Message: " + (process.data ? process.data : process.message)); - } else { - if (/dataset already exists/i.test(process.data)) { - modal.hide = false; - - $("#validationwrapper-storagepool-snapshot-clone-name-" + snapshot.id).addClass("has-error"); - $("#helpblock-storagepool-snapshot-clone-name-" + snapshot.id).addClass("has-error").removeClass("hidden").text("Name already exists."); - $("#input-storagepool-snapshot-clone-name-" + snapshot.id).focus(); - } else if (/parent does not exist/i.test(process.data)) { - modal.hide = false; - - $("#validationwrapper-storagepool-snapshot-clone-name-" + snapshot.id).addClass("has-error"); - $("#helpblock-storagepool-snapshot-clone-name-" + snapshot.id).addClass("has-error").removeClass("hidden").text("Parent file system does not exist."); - $("#input-storagepool-snapshot-clone-name-" + snapshot.id).focus(); - } - - if (modal.hide) { - FnDisplayAlert({ status: "danger", title: "Snapshot could not be cloned", description: snapshot.name, breakword: false }, { name: "snapshot-clone", id: snapshot.id, timeout: 4 }); - } - - FnConsole.warn("Snapshots, Clone: Failed, Pool: " + pool.name + ", Snapshot: " + snapshot.name + ", Message: " + (process.data ? process.data : process.message)); - } - - if (!modal.hide) { - $("#spinner-storagepool-snapshot-clone-" + snapshot.id).addClass("hidden"); - $("#spinner-storagepool-snapshot-clone-" + snapshot.id + " span").text(""); - $("#btn-storagepool-snapshot-clone-apply-" + snapshot.id).prop("disabled", false); - } - - if (modal.hide) { - $("#modal-storagepool-snapshot-clone-" + snapshot.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - } -} - -function FnSnapshotCreate(pool = { name, id }, snapshot = { name, id, recursive: false }, modal = { name, id }) { - let process = { - command: ["/sbin/zfs", "snapshot", snapshot.name] - }; - - modal.hide = true; - - if (snapshot.recursive) { - process.command.splice(2, 0, "-r"); - } - - FnConsole.log[2]("Snapshots, Create: In Progress, Pool: " + pool.name + ", Snapshot: " + snapshot.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-" + modal.name + "-" + modal.id + " span").text("Creating snapshot" + (snapshot.recursive ? "s" : "") + "..."); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "Snapshot successfully created", description: snapshot.name, breakword: false }, { name: "snapshot-create", id: snapshot.id, timeout: 4 }); - - FnConsole.log[1]("Snapshots, Create: Success, Pool: " + pool.name + ", Snapshot: " + snapshot.name); - }) - .fail(function (message, data) { - if (/dataset already exists/gi.test(data)) { - modal.hide = false; - - $("#validationwrapper-" + modal.name + "-name-" + modal.id).addClass("has-error"); - $("#helpblock-" + modal.name + "-name-" + modal.id).addClass("has-error").removeClass("hidden").text("Name already exists."); - $("#input-" + modal.name + "-name-" + modal.id).focus(); - } - - if (!modal.hide) { - $("#spinner-" + modal.name + "-" + modal.id).addClass("hidden"); - $("#spinner-" + modal.name + "-" + modal.id + " span").text(""); - $("#btn-" + modal.name + "-apply-" + modal.id).prop("disabled", false); - } - - if (modal.hide) { - FnDisplayAlert({ status: "danger", title: "Snapshot could not be created", description: snapshot.name, breakword: false }, { name: "snapshot-create", id: snapshot.id, timeout: 4 }); - } - - FnConsole.warn("Snapshots, Create: Failed, Pool: " + pool.name + ", Snapshot: " + snapshot.name + ", Message: " + (data ? data : message)); - }) - .finally(function () { - if (modal.hide) { - setTimeout(function () { - $("#modal-" + modal.name + "-" + modal.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - }, 700); - } - }); -} - -function FnSnapshotCreateDateGet(pool = { name, id }, snapshot = { name, id, recursive: false }, modal = { name, id }) { - let process = { - command: ["/bin/date", "\+\%Y.\%m.\%d-\%H.\%M.\%S"] - }; - - snapshot.date = ""; - - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-" + modal.name + "-" + modal.id + " span").text("Creating snapshot" + (snapshot.recursive ? "s" : "") + "..."); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Snapshots, Create, Date, Get:" })); - - snapshot.date = data.replace(/[ \t\n]+/g, ""); - }) - .fail(function () { - snapshot.date = FnDateTimeSnapshot({ date: null }); - }) - .finally(function () { - snapshot.name = snapshot.name.replace(/^(.*)\@.*$/, "$1") + "@" + snapshot.date; - snapshot.id = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: snapshot.name, attribute: true }); - - $("#input-" + modal.name + "-name-" + modal.id).val(snapshot.date); - - FnSnapshotCreate({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, recursive: snapshot.recursive }, { name: modal.name, id: modal.id }); - }); -} - -function FnSnapshotDestroy(pool = { name, id, altroot: false, readonly: false }, snapshot = { name, id, clones: [], recursive: false, recursiveall: false }, samba = { restart: false }) { - if (samba.restart) { - FnSambaStop() - .finally(function () { - if (snapshot.recursiveall && snapshot.clones.length > 0 && zfsmanager.configuration.samba.manage) { - $("#spinner-storagepool-snapshot-destroy-" + snapshot.id + " span").text("Retrieving Samba shares..."); - - FnSambaSharesGet({ name: pool.name, id: pool.id }, { name: null, clones: snapshot.clones }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Shares, Get:" })); - - let filesystems = { - id: data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) - }; - - $("#spinner-storagepool-snapshot-destroy-" + snapshot.id + " span").text("Destroying snapshot..."); - - if (filesystems.id.length > 0) { - FnSnapshotDestroyCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: false }) - .done(function () { - $("#spinner-storagepool-snapshot-destroy-" + snapshot.id + " span").text("Destroying Samba shares..."); - - FnSambaSharesDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { id: filesystems.id }, { restart: samba.restart }, { silent: false }) - .finally(function () { - $("#modal-storagepool-snapshot-destroy-" + snapshot.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - }); - }); - } else { - $("#spinner-storagepool-snapshot-destroy-" + snapshot.id + " span").text("Destroying snapshot..."); - - FnSnapshotDestroyCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: true }) - .finally(function () { - FnSambaStart(); - }); - } - }) - .fail(function (message, data) { - FnSnapshotDestroyFail({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id }, { data: data, message: message }, { refresh: true }); - FnSambaStart(); - }); - } else { - $("#spinner-storagepool-snapshot-destroy-" + snapshot.id + " span").text("Destroying snapshot..."); - - FnSnapshotDestroyCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: true }) - .finally(function () { - FnSambaStart(); - }); - } - }); - } else { - if (snapshot.recursiveall && snapshot.clones.length > 0 && zfsmanager.configuration.samba.manage) { - $("#spinner-storagepool-snapshot-destroy-" + snapshot.id + " span").text("Retrieving Samba shares..."); - - FnSambaSharesGet({ name: pool.name, id: pool.id }, { name: null, clones: snapshot.clones }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Shares, Get:" })); - - let filesystems = { - id: data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) - }; - - $("#spinner-storagepool-snapshot-destroy-" + snapshot.id + " span").text("Destroying snapshot..."); - - if (filesystems.id.length > 0) { - FnSnapshotDestroyCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: false }) - .done(function () { - $("#spinner-storagepool-snapshot-destroy-" + snapshot.id + " span").text("Destroying Samba shares..."); - - FnSambaSharesDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { id: filesystems.id }, { restart: samba.restart }, { silent: false }) - .finally(function () { - $("#modal-storagepool-snapshot-destroy-" + snapshot.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - }); - }); - } else { - $("#spinner-storagepool-snapshot-destroy-" + snapshot.id + " span").text("Destroying snapshot..."); - - FnSnapshotDestroyCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: true }); - } - }) - .fail(function (message, data) { - FnSnapshotDestroyFail({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id }, { data: data, message: message }, { refresh: true }); - }); - } else { - $("#spinner-storagepool-snapshot-destroy-" + snapshot.id + " span").text("Destroying snapshot..."); - - FnSnapshotDestroyCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: true }); - } - } -} - -function FnSnapshotDestroyCommand(pool = { name, id }, snapshot = { name, id, recursive: false, recursiveall: false }, display = { refresh: true }) { - let process = { - command: ["/sbin/zfs", "destroy", snapshot.name] - }; - - if (snapshot.recursive) { - process.command.splice(2, 0, "-r"); - } - if (snapshot.recursiveall) { - process.command.splice(2, 0, "-R"); - } - - FnConsole.log[1]("Snapshots, Destroy: In Progress, Pool: " + pool.name + ", Snapshot: " + snapshot.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "Snapshot successfully destroyed", description: snapshot.name, breakword: false }, { name: "snapshot-destroy", id: snapshot.id, timeout: 4 }); - - FnConsole.log[1]("Snapshots, Destroy: Success, Pool: " + pool.name + ", Snapshot: " + snapshot.name); - }) - .fail(function (message, data) { - FnSnapshotDestroyFail({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id }, { data: data, message: message }, { refresh: false }); - - display.refresh = true; - }) - .finally(function () { - if (display.refresh) { - $("#modal-storagepool-snapshot-destroy-" + snapshot.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - } - }); -} - -function FnSnapshotDestroyFail(pool = { name, id }, snapshot = { name, id }, process = { data, message }, display = { refresh: true }) { - FnDisplayAlert({ status: "danger", title: "Snapshot could not be destroyed", description: snapshot.name, breakword: false }, { name: "snapshot-destroy", id: snapshot.id, timeout: 4 }); - - FnConsole.warn("Snapshots, Destroy: Failed, Pool: " + pool.name + ", Snapshot: " + snapshot.name + ", Message: " + (process.data ? process.data : process.message)); +//#region Helper Functions + +String.prototype.format = function () { + let args = arguments; + + return this.replace(/\{(\d+)\}/g, function (m, n) { + return args[n]; + }); +} - if (display.refresh) { - $("#modal-storagepool-snapshot-destroy-" + snapshot.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); +function FnAppendLeadingZeroes(data = { value }) { + if (data.value < 10) { + return "0" + data.value; } -} - -function FnSnapshotRename(pool = { name, id }, snapshot = { name, id, namenew, recursive: false }) { - let process = { - command: ["/sbin/zfs", "rename", snapshot.name, snapshot.namenew] - }; - let modal = { - hide: true - }; - - if (snapshot.recursive) { - process.command.splice(2, 0, "-r"); - } - - FnConsole.log[1]("Snapshots, Rename: In Progress, Pool: " + pool.name + ", Snapshot: " + snapshot.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-storagepool-snapshot-rename-" + snapshot.id + " span").text("Renaming snapshot..."); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "Snapshot successfully renamed", description: snapshot.name, breakword: false }, { name: "snapshot-rename", id: snapshot.id, timeout: 4 }); - - FnConsole.log[1]("Snapshots, Rename: Success, Pool: " + pool.name + ", Snapshot: " + snapshot.name); - }) - .fail(function (message, data) { - if (/dataset already exists|child dataset already has a snapshot with the new name/gi.test(data)) { - modal.hide = false; - - $("#validationwrapper-storagepool-snapshot-rename-name-" + snapshot.id).addClass("has-error"); - $("#helpblock-storagepool-snapshot-rename-name-" + snapshot.id).addClass("has-error").removeClass("hidden").text("Name already exists."); - $("#input-storagepool-snapshot-rename-name-" + snapshot.id).focus(); - } - - if (!modal.hide) { - $("#spinner-storagepool-snapshot-rename-" + snapshot.id).addClass("hidden"); - $("#spinner-storagepool-snapshot-rename-" + snapshot.id + " span").text(""); - $("#btn-storagepool-snapshot-rename-apply-" + snapshot.id).prop("disabled", false); - } - - FnConsole.warn("Snapshots, Rename: Failed, Pool: " + pool.name + ", Snapshot: " + snapshot.name + ", Message: " + (data ? data : message)); - - if (modal.hide) { - FnDisplayAlert({ status: "danger", title: "Snapshot could not be renamed", description: snapshot.name, breakword: false }, { name: "snapshot-rename", id: snapshot.id, timeout: 4 }); - } - }) - .finally(function () { - if (modal.hide) { - $("#modal-storagepool-snapshot-rename-" + snapshot.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - } - }); -} - -function FnSnapshotRollBack(pool = { name, id, altroot: false, readonly: false }, snapshot = { name, id, creation, force: false, recursive: false, recursiveall: false }, samba = { restart: false }) { - if (samba.restart) { - FnSambaStop() - .finally(function () { - if (snapshot.recursiveall && zfsmanager.configuration.samba.manage) { - FnSnapshotRollBackSnapshotsGet({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, creation: snapshot.creation }, { name: null, id: null }) - .done(function (data) { - let snapshots = { - id: data.split(/\n/g).filter(v => v), - clones: [] - }; - - if (snapshots.id.length > 0) { - snapshots.id.forEach((_value, _index) => { - _value = _value.split(/\t/g).filter(v => v); - - snapshots.properties = { - clones: (_value[2] ? _value[2].split(",").filter(v => v) : []), - creation: _value[1], - name: _value[0] - }; - - if (snapshots.properties.name != snapshot.name && snapshots.properties.creation > snapshot.creation && snapshots.properties.clones.length > 0) { - snapshots.properties.clones.forEach((_value, _index) => { - snapshots.clones.push(_value); - }); - } - }); - } - - if (snapshots.clones.length > 0) { - $("#spinner-storagepool-snapshot-rollback-" + snapshot.id + " span").text("Retrieving Samba shares..."); - - FnSambaSharesGet({ name: pool.name, id: pool.id }, { name: null, clones: snapshots.clones }) - .done(function (_data) { - FnConsole.log[4](FnConsoleVerbose({ data: _data, message: "Samba, Shares, Get:" })); - - let filesystems = { - id: _data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) - }; - - $("#spinner-storagepool-snapshot-rollback-" + snapshot.id + " span").text("Rolling back snapshot..."); - - if (filesystems.id.length > 0) { - FnSnapshotRollBackCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, force: snapshot.force, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: false }) - .done(function () { - $("#spinner-storagepool-snapshot-rollback-" + snapshot.id + " span").text("Destroying Samba shares..."); - - FnSambaSharesDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { id: filesystems.id }, { restart: samba.restart }, { silent: false }) - .finally(function () { - $("#modal-storagepool-snapshot-rollback-" + snapshot.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - }); - }); - } else { - $("#spinner-storagepool-snapshot-rollback-" + snapshot.id + " span").text("Rolling back snapshot..."); - - FnSnapshotRollBackCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, force: snapshot.force, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: true }) - .finally(function () { - FnSambaStart(); - }); - } - }) - .fail(function (_message, _data) { - FnSnapshotRollBackCommandFail({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id }, { data: _data, message: _message }, { refresh: true }); - FnSambaStart(); - }); - } else { - $("#spinner-storagepool-snapshot-rollback-" + snapshot.id + " span").text("Rolling back snapshot..."); - - FnSnapshotRollBackCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, force: snapshot.force, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: true }) - .finally(function () { - FnSambaStart(); - }); - } - }); - } else { - $("#spinner-storagepool-snapshot-rollback-" + snapshot.id + " span").text("Rolling back snapshot..."); - - FnSnapshotRollBackCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, force: snapshot.force, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: true }) - .finally(function () { - FnSambaStart(); - }); - } - }); - } else { - if (snapshot.recursiveall && zfsmanager.configuration.samba.manage) { - FnSnapshotRollBackSnapshotsGet({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, creation: snapshot.creation }, { name: null, id: null }) - .done(function (data) { - let snapshots = { - id: data.split(/\n/g).filter(v => v), - clones: [] - }; - - if (snapshots.id.length > 0) { - snapshots.id.forEach((_value, _index) => { - _value = _value.split(/\t/g).filter(v => v); - - snapshots.properties = { - clones: (_value[2] ? _value[2].split(",").filter(v => v) : []), - creation: _value[1], - name: _value[0] - }; - - if (snapshots.properties.name != snapshot.name && snapshots.properties.creation > snapshot.creation && snapshots.properties.clones.length > 0) { - snapshots.properties.clones.forEach((_value, _index) => { - snapshots.clones.push(_value); - }); - } - }); - } - - if (snapshots.clones.length > 0) { - $("#spinner-storagepool-snapshot-rollback-" + snapshot.id + " span").text("Retrieving Samba shares..."); - - FnSambaSharesGet({ name: pool.name, id: pool.id }, { name: null, clones: snapshots.clones }) - .done(function (_data) { - FnConsole.log[4](FnConsoleVerbose({ data: _data, message: "Samba, Shares, Get:" })); - - let filesystems = { - id: _data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) - }; - - $("#spinner-storagepool-snapshot-rollback-" + snapshot.id + " span").text("Rolling back snapshot..."); - - if (filesystems.id.length > 0) { - FnSnapshotRollBackCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, force: snapshot.force, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: false }) - .done(function () { - $("#spinner-storagepool-snapshot-rollback-" + snapshot.id + " span").text("Destroying Samba shares..."); - - FnSambaSharesDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { id: filesystems.id }, { restart: samba.restart }, { silent: false }) - .finally(function () { - $("#modal-storagepool-snapshot-rollback-" + snapshot.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - }); - }); - } else { - $("#spinner-storagepool-snapshot-rollback-" + snapshot.id + " span").text("Rolling back snapshot..."); - - FnSnapshotRollBackCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, force: snapshot.force, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: true }); - } - }) - .fail(function (_message, _data) { - FnSnapshotRollBackCommandFail({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id }, { data: _data, message: _message }, { refresh: true }); - }); - } else { - $("#spinner-storagepool-snapshot-rollback-" + snapshot.id + " span").text("Rolling back snapshot..."); - - FnSnapshotRollBackCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, force: snapshot.force, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: true }); - } - }); - } else { - $("#spinner-storagepool-snapshot-rollback-" + snapshot.id + " span").text("Rolling back snapshot..."); - - FnSnapshotRollBackCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, force: snapshot.force, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: true }); - } - } -} - -function FnSnapshotRollBackCommand(pool = { name, id }, snapshot = { name, id, force: false, recursive: false, recursiveall: false }, display = { refresh: true }) { - let process = { - command: ["/sbin/zfs", "rollback", snapshot.name] - }; - - if (snapshot.force) { - process.command.splice(2, 0, "-f"); - } - if (snapshot.recursive) { - process.command.splice(2, 0, "-r"); - } - if (snapshot.recursiveall) { - process.command.splice(2, 0, "-R"); - } - - FnConsole.log[1]("Snapshots, Roll Back: In Progress, Pool: " + pool.name + ", Snapshot: " + snapshot.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "Snapshot successfully rolled back", description: snapshot.name, breakword: false }, { name: "snapshot-rollback", id: snapshot.id, timeout: 4 }); - - FnConsole.log[1]("Snapshots, Roll Back: Success, Pool: " + pool.name + ", Snapshot: " + snapshot.name); - }) - .fail(function (message, data) { - FnSnapshotRollBackCommandFail({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id }, { data: data, message: message }, { refresh: false }); - - display.refresh = true; - }) - .finally(function () { - if (display.refresh) { - $("#modal-storagepool-snapshot-rollback-" + snapshot.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - } - }); -} - -function FnSnapshotRollBackCommandFail(pool = { name, id }, snapshot = { name, id }, process = { data, message }, display = { refresh: true }) { - FnDisplayAlert({ status: "danger", title: "Snapshot could not be rolled back", description: snapshot.name, breakword: false }, { name: "snapshot-rollback", id: snapshot.id, timeout: 4 }); - - FnConsole.warn("Snapshots, Roll Back: Failed, Pool: " + pool.name + ", Snapshot: " + snapshot.name + ", Message: " + (process.data ? process.data : process.message)); - - if (display.refresh) { - $("#modal-storagepool-snapshot-rollback-" + snapshot.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 200); - } -} - -function FnSnapshotRollBackSnapshotsGet(pool = { name, id }, snapshot = { name, id, creation }, modal = { name, id }) { - let process = { - command: ["/sbin/zfs", "list", "-H", "-o", "name,creation,clones", "-p", "-t", "snapshot"] - }; - - process.command.push(snapshot.name.replace(/^(.*)\@.*$/, "$1")); - - FnConsole.log[2]("Snapshots, Roll Back, Snapshots, Get: In Progress, Pool: " + pool.name + ", Snapshot: " + snapshot.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Snapshots, Roll Back, Snapshots, Get:" })); - - if (modal.name && modal.id) { - let snapshots = { - id: data.split(/\n/g).filter(v => v), - clones: [], - count: { - snapshots: 0, - snapshotswithclones: 0 - } - }; - - if (snapshots.id.length > 0) { - snapshots.id.forEach((_value, _index) => { - _value = _value.split(/\t/g).filter(v => v); - - snapshots.properties = { - clones: (_value[2] ? _value[2].split(",").filter(v => v) : []), - creation: _value[1], - name: _value[0] - }; - - if (snapshots.properties.name != snapshot.name && snapshots.properties.creation > snapshot.creation) { - snapshots.count.snapshots++; - snapshots.count.snapshotswithclones++; - - if (snapshots.properties.clones.length > 0) { - snapshots.properties.clones.forEach((_value, _index) => { - snapshots.clones.push(_value); - }); - } - - $("#ul-" + modal.name + "-snapshots-" + modal.id).append("
  • " + snapshots.properties.name + "
  • \n"); - $("#ul-" + modal.name + "-child-snapshotswithclones-" + modal.id).append("
  • " + snapshots.properties.name + "
  • \n"); - } - }); - - $("#panelgroup-" + modal.name + "-" + modal.id).attr("data-snapshot-snapshots", snapshots.count.snapshots); - $("#panelgroup-" + modal.name + "-" + modal.id).attr("data-snapshot-child-snapshotswithclones", snapshots.count.snapshotswithclones); - } - - if (snapshots.clones.length > 0) { - FnSnapshotChildFileSystemsGet({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id }, filesystems = { id: snapshots.clones }, { name: modal.name, id: modal.id }); - FnSnapshotChildSnapshotsGet({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, exclude: true }, { id: snapshots.clones }, { name: modal.name, id: modal.id }); - } - } - - FnConsole.log[1]("Snapshots, Roll Back, Snapshots, Get: Success, Pool: " + pool.name + ", Snapshot: " + snapshot.name); - }) - .fail(function (message, data) { - FnConsole.warn("Snapshots, Roll Back, Snapshots, Get: Failed, Pool: " + pool.name + ", Snapshot: " + snapshot.name + ", Message: " + (data ? data : message)); - }); -} - -//#endregion - -//#region Status - -function FnStatusErrorColors(status = { count }) { - if (!$.isNumeric(status.count)) { - return status.count; - } - - if (status.count >= 5 && status.count <= 20) { - return (`` + status.count + ``); - } else if (status.count >= 21) { - return (`` + status.count + ``); - } else { - return status.count; - } -} - -function FnStatusGet(pool = { name, id }) { - let process = { - command: ["/bin/sh", "-c", ((zfsmanager.user.name == "root" || !zfsmanager.user.name) ? "ZPOOL_SCRIPTS_AS_ROOT=1 " : "") + `/sbin/zpool status -p -t -c upath "` + pool.name + `"`] - }; - - pool.autotrim = ($("#tr-storagepool-" + pool.id).attr("data-pool-autotrim") == "true" ? true : false); - pool.boot = ($("#tr-storagepool-" + pool.id).attr("data-pool-boot") == "true" ? true : false); - pool.feature = { - allocation_classes: ($("#tr-storagepool-" + pool.id).attr("data-pool-feature-allocation_classes") == "true" ? true : false), - device_removal: ($("#tr-storagepool-" + pool.id).attr("data-pool-feature-device_removal") == "true" ? true : false), - resilver_defer: ($("#tr-storagepool-" + pool.id).attr("data-pool-feature-resilver_defer") == "true" ? true : false) - }; - pool.guid = $("#tr-storagepool-" + pool.id).attr("data-pool-guid"); - pool.readonly = ($("#tr-storagepool-" + pool.id).attr("data-pool-readonly") == "true" ? true : false); - pool.root = ($("#tr-storagepool-" + pool.id).attr("data-pool-root") == "true" ? true : false); - pool.status = { - empty: true - }; - pool.upgrade = ($("#tr-storagepool-" + pool.id).attr("data-pool-upgrade") == "true" ? true : false); - pool.version = $("#tr-storagepool-" + pool.id).attr("data-pool-version"); - - FnConsole.log[2]("Status, Get: In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data, message) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Status, Get:" })); - - FnDisksLsblkGet({ sizeraw: true }) - .done(function (_data) { - FnConsole.log[4](FnConsoleVerbose({ data: _data, message: "Disks, Lsblk, Get:" })); - - if (data) { - pool.status.empty = false; - - let disks = { - lsblkjson: JSON.parse(_data) - }; - - FnStatusGetCommand({ name: pool.name, id: pool.id, autotrim: pool.autotrim, boot: pool.boot, feature: { allocation_classes: pool.feature.allocation_classes, device_removal: pool.feature.device_removal, resilver_defer: pool.feature.resilver_defer }, guid: pool.guid, readonly: pool.readonly, root: pool.root, upgrade: pool.upgrade, version: pool.version }, { lsblk: disks.lsblkjson }, { data: data, message: message }); - } - - FnConsole.log[1]("Status, Get: Success, Pool: " + pool.name); - - if (pool.status.empty) { - $("#tbody-storagepool-status-messages-" + pool.id).empty(); - $("#tbody-storagepool-status-config-" + pool.id).empty(); - $("#tbody-storagepool-status-messages-" + pool.id).append(`Status not available`); - $("#modals-storagepool-status-" + pool.id).remove(); - $("#dynamics-storagepool-status-" + pool.id).remove(); - - $("#tr-storagepool-" + pool.id).attr("data-pool-refresh-status", "true"); - - $("#spinner-storagepool-status-" + pool.id).addClass("hidden"); - $("#paneltitle-storagepool-status-" + pool.id).removeClass("hidden").text(FnDateTime()); - $("#btn-storagepool-status-refresh-" + pool.id).prop("disabled", false); - $("#btn-storagepool-status-refresh-auto-" + pool.id).prop("disabled", false); - } - - FnStoragePoolSpinnerHide({ name: pool.name, id: pool.id }); - FnCockpitElementsUpdate(); - }) - .fail(function (_message, _data) { - FnConsole.warn("Status, Get: Failed, Pool: " + pool.name + ", Message: " + (_data ? _data : _message)); - - FnStatusGetFail({ name: pool.name, id: pool.id, status: { empty: pool.status.empty } }); - }); - }) - .fail(function (message, data) { - FnConsole.warn("Status, Get: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); - - FnStatusGetFail({ name: pool.name, id: pool.id, status: { empty: pool.status.empty } }); - }); -} - -function FnStatusGetCommand(pool = { name, id, autotrim: false, boot: false, feature: { allocation_classes: true, device_removal: true, resilver_defer: true }, guid, readonly: false, root: false, upgrade: false, version }, disks = { lsblk: {} }, process = { data, message }) { - process.data = process.data.replace(/\n\t+/g, "[TAB1]").split(/\n/g).filter(v => v); //Replace new line with [TAB1] for multi line messages and config - - pool.status = { - state: "", - status: "", - action: "", - see: "", - scan: "", - remove: "", - memory: "", - errors: "", - upgrade: false, - resilver: { - started: false - }, - scrub: { - started: false, - paused: false - }, - trim: { - started: false, - suspended: false - }, - disks: { - count: 0, - ssd: false, - trim: { - unsupportedcount: 0 - } - }, - config: { - items: [], - regexp: {}, - replacement: {}, - tier: { - count: 0, - nametier0: "", - nametier1: "", - nametier2: "", - nametier3: "" - }, - virtualdevice: { - count: 0 - } - } - }; - - $("#modals-storagepool-status-" + pool.id).remove(); - $("#modals").append(`
    `); - $("#dynamics-storagepool-status-" + pool.id).remove(); - $("#dynamics").append(`
    `); - - pool.status.output = `Pool: ` + pool.name + ``; - - process.data.forEach((_value, _index) => { - if (/^(?: )+pool:/g.test(_value)) { - _value = ""; - } - if (/^(?: )+state:/g.test(_value)) { - pool.status.state = _value.replace(/\[TAB1\]/g, " ").replace(/^(?: )+state:/g, "").trim(); - _value = ""; - - pool.status.output += `State: ` + (pool.status.state ? ` ` + pool.status.state : ``) + ``; - } - if (/^status:/g.test(_value)) { - pool.status.status = _value.replace(/\[TAB1\]/g, " ").replace(/^status:/g, "").trim(); - _value = ""; - - if (/currently being resilvered/gi.test(pool.status.status)) { - pool.status.resilver.started = true; - } - - pool.status.output += `Status: ` + pool.status.status + ``; - } - if (/^action:/g.test(_value)) { - pool.status.action = _value.replace(/\[TAB1\]/g, " ").replace(/^action:/g, "").trim(); - pool.status.upgrade = ((pool.upgrade || /Upgrade the pool|zpool upgrade/gi.test(pool.status.action)) && !pool.boot ? true : false); - _value = ""; - - if (/Upgrade the pool|zpool upgrade/gi.test(pool.status.action) && !pool.boot) { //Hide upgrade message for boot pool. Upgrading version may cause an unbootable system - pool.status.output += `Action: ` + pool.status.action + ``; - } - } - if (/^(?: )+see:/g.test(_value)) { - pool.status.see = _value.replace(/\[TAB1\]/g, " ").replace(/^(?: )+see:(?: )+/g, "").trim(); - _value = ""; - - if (/http/g.test(pool.status.see)) { - pool.status.see = `` + pool.status.see + ``; - } - - pool.status.output += `See: ` + pool.status.see + ``; - } - if (/^(?: )+scan:/g.test(_value)) { - pool.status.scan = _value.replace(/\[TAB1\]/g, " ").replace(/^(?: )+scan:/g, "").trim(); - _value = ""; - - if (/scrub in progress/gi.test(pool.status.scan)) { - pool.status.scrub.started = true; - } else if (/scrub paused/gi.test(pool.status.scan)) { - pool.status.scrub.paused = true; - } - - if (/resilver in progress/gi.test(pool.status.scan)) { - pool.status.resilver.started = true; - } - - pool.status.output += `Scan: ` + pool.status.scan + ``; - } - if (/^remove:/g.test(_value)) { - pool.status.remove = _value.replace(/\[TAB1\]/g, " ").replace(/^remove:/g, "").trim(); - _value = ""; - - pool.status.output += `Remove: ` + pool.status.remove + ``; - } - if (/memory used for/g.test(_value)) { - pool.status.memory = ". " + _value.replace(/\[TAB1\]/g, " ").trim(); - _value = ""; - } - if (/^config:/g.test(_value)) { - _value = ""; - } - if (/^errors:/g.test(_value)) { - pool.status.errors = _value.replace(/\[TAB1\]/g, " ").replace(/^errors:/g, "").trim(); - _value = ""; - - pool.status.output += `Errors: ` + pool.status.errors + ``; - } - if (/\[TAB1\]NAME/g.test(_value)) { //Config header row - _value = _value.split("upath").slice(1).join("."); //Remove config header row (and any previous text if exists) - - pool.status.config.regexp.tabspace = new RegExp("^\\[TAB1\\]" + pool.name); - - if (pool.status.config.regexp.tabspace.test(_value)) { //Confirm config rows - pool.status.config.items = _value.split("[TAB1]").filter(v => v); - } - - if (/trimmed, started|trimmed started/i.test(pool.status.config.items.join(" "))) { //Storage pool contains a disk with TRIM started - pool.status.trim.started = true; - } else if (/trimmed, suspended|trimmed suspended/i.test(pool.status.config.items.join(" "))) { //Storage pool contains a disk with TRIM suspended - pool.status.trim.suspended = true; - } - } - }); - - pool.status.output += ``; - pool.status.output += ``; - - $("#tbody-storagepool-status-messages-" + pool.id).html(pool.status.output); - $("#td-storagepool-status-messages-remove-" + pool.id).append(pool.status.memory); - - pool.status.config.output = ` - - Name - State - Read - Write - Checksum - Message - Product - - - - `; - - $("#tbody-storagepool-status-config-" + pool.id).html(pool.status.config.output); - - pool.status.config.items.forEach((_value, _index) => { - pool.status.config.disk = false; - pool.status.config.tier.level = (_value.match(/^\s*/g)[0].length / 2); - pool.status.config.tier.cache = false; - pool.status.config.tier.dedup = false; - pool.status.config.tier.logs = false; - pool.status.config.tier.pool = false; - pool.status.config.tier.spares = false; - pool.status.config.tier.special = false; - pool.status.config.tier.replacing = false; - pool.status.config.output = ""; - - pool.status.disks.disk = { - ssd: false, - trim: { - started: false, - suspended: false, - unsupported: false - }, - replacing: false, - messages: [], - upath: "" - } - - if (_index == 0 && /[ ]/g.test(pool.name)) { //Fix for storage pool name if it contains whitespace - pool.status.config.regexp.poolname = new RegExp("^" + pool.name, "g"); - _value = _value.replace(pool.status.config.regexp.poolname, "[POOLNAME]"); - } - - _value = _value.replace(/ +/g, "\u22C5").replace(/^\u22C5/, "").split("\u22C5").filter(v => v); - - if (_index == 0 && _value[0] == "[POOLNAME]") { - _value[0] = pool.name; - } - - switch (pool.status.config.tier.level) { - case 0: //Pool / Cache / Dedup / Log / Spares / Special tier - pool.status.config.tier.nametier0 = _value[0].trim(); - break; - case 1: //Virtual device tier - pool.status.config.tier.nametier1 = _value[0]; - - if (pool.status.config.tier.nametier0 == pool.name) { - pool.status.config.virtualdevice.count++; - } - break; - case 2: //Drive tier - pool.status.config.tier.nametier2 = _value[0]; - break; - case 3: //Action tier - pool.status.config.tier.nametier3 = _value[0]; - break; - case 4: //Action Drive tier - break; - } - - if (pool.status.config.tier.level == 0) { //1= Pool, 2+= / Cache / Dedup / Log / Spares / Special - pool.status.config.tier.count++; - } - - if (pool.status.config.tier.level > 0) { - if (pool.status.config.tier.nametier0 == pool.name && pool.status.config.tier.count == 1) { //Virtual Device / Disk is member of pool - pool.status.config.tier.pool = true; - } - if (/^cache/g.test(pool.status.config.tier.nametier0) && pool.status.config.tier.count > 1) { //Virtual Device / Disk is member of cache - pool.status.config.tier.cache = true; - } - if (/^dedup/g.test(pool.status.config.tier.nametier0) && pool.status.config.tier.count > 1) { //Virtual Device / Disk is member of dedup - pool.status.config.tier.dedup = true; - } - if (/^logs/g.test(pool.status.config.tier.nametier0) && pool.status.config.tier.count > 1) { //Virtual Device / Disk is member of logs - pool.status.config.tier.logs = true; - } - if (/^spares/g.test(pool.status.config.tier.nametier0) && pool.status.config.tier.count > 1) { //Virtual Device / Disk is member of spares - pool.status.config.tier.spares = true; - } - if (/^special/g.test(pool.status.config.tier.nametier0) && pool.status.config.tier.count > 1) { //Virtual Device / Disk is member of special - pool.status.config.tier.special = true; - } - } - - pool.status.config.tier.virtualdevice = ((pool.status.config.tier.level == 0 && /^cache|^dedup|^logs|^spares|^special/g.test(pool.status.config.tier.nametier0) && pool.status.config.tier.count > 1) ? true : false); - - if (pool.status.config.tier.level == 0 && /^special/g.test(pool.status.config.tier.nametier0) && pool.status.config.tier.count > 1) { - $("#tr-storagepool-" + pool.id).attr("data-pool-special", true); - } - - if (/^\/dev\/nvme|^\/dev\/sd/gi.test(_value[5])) { //upath - pool.status.disks.disk.upath = _value[5]; - _value[5] = ""; - } else if ($.isNumeric(_value[0]) && _value[5] == "was") { //upath appears after was device path message - pool.status.disks.disk.upath = _value[7]; - _value[7] = ""; - } else if (!$.isNumeric(_value[0]) && _value[5] != "was") { //upath appears after error messages and before trim messages - for (let i = 5; i < _value.length; i++) { //Collect messages - if (/^\/dev\/nvme|^\/dev\/sd/gi.test(_value[i])) { - pool.status.disks.disk.upath = _value[i]; - _value[i] = ""; - } - } - } - - if ((/^\/dev\/nvme|^\/dev\/sd/gi.test(pool.status.disks.disk.upath) || /^nvme-nvme/gi.test(_value[0]) || /^wwn-/gi.test(_value[0]) || $.isNumeric(_value[0])) && pool.status.config.tier.level > 0) { - pool.status.config.disk = true; - pool.status.disks.count++; - } - - if (pool.status.config.disk && (pool.status.config.tier.level == 2 && /^replacing-/g.test(pool.status.config.tier.nametier1) || pool.status.config.tier.level == 3 && /^replacing-/g.test(pool.status.config.tier.nametier2) || pool.status.config.tier.level == 4 && /^replacing-/g.test(pool.status.config.tier.nametier3))) { - pool.status.disks.disk.replacing = true; - } - - if (pool.status.config.tier.level > 0 && /^replacing-/g.test(_value[0])) { - pool.status.config.tier.replacing = true; - } - - pool.status.config.output += ``; - pool.status.config.output += `` + (pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name ? `Pool` : (pool.status.config.disk ? `Disk` : `Virtual Device`)) + `:` + _value[0] + ``; //Pool / Virtual Device / Disk - pool.status.config.output += `State:` + (_value[1] ? ` ` + _value[1] : ``) + ``; //State - - if (_value[2] && /^spares/g.test(pool.status.config.tier.nametier0)) { //Read - pool.status.disks.disk.messages.push(_value[2]); - - pool.status.config.output += ``; - } else { - pool.status.config.output += `` + (_value[2] ? `Read:` + (zfsmanager.configuration.zfs.status.errorcolors ? FnStatusErrorColors({ count: _value[2] }) : _value[2]) : ``) + ``; - } - - if (_value[3] && /^spares/g.test(pool.status.config.tier.nametier0)) { //Write - pool.status.disks.disk.messages.push(_value[3]); - - pool.status.config.output += ``; - } else { - pool.status.config.output += `` + (_value[3] ? `Write:` + (zfsmanager.configuration.zfs.status.errorcolors ? FnStatusErrorColors({ count: _value[3] }) : _value[3]) : ``) + ``; - } - - if (/^spares/g.test(pool.status.config.tier.nametier0)) { //Checksum - if (_value[4]) { - pool.status.disks.disk.messages.push(_value[4]); - } - - pool.status.config.output += ``; - } else { - pool.status.config.output += `` + (_value[4] ? `Checksum:` + (zfsmanager.configuration.zfs.status.errorcolors ? FnStatusErrorColors({ count: _value[4] }) : _value[4]) : ``) + ``; - } - - for (let i = 5; i < _value.length; i++) { //Collect messages - if (_value[i]) { - pool.status.disks.disk.messages.push(_value[i]); - } - } - - pool.status.disks.disk.messages = pool.status.disks.disk.messages.join(" "); //Join Messages for output - - if (pool.status.config.disk && /\(trim unsupported\)/gi.test(pool.status.disks.disk.messages)) { - pool.status.disks.disk.trim.unsupported = true; - pool.status.disks.trim.unsupportedcount++; - } - - if (!zfsmanager.configuration.zfs.status.trimunsupported) { - pool.status.disks.disk.messages = pool.status.disks.disk.messages.replace(/\(trim unsupported\)/gi, ""); - } - if (pool.status.config.tier.cache || pool.status.config.tier.spares) { //Cache and spare disks can not be trimmed - pool.status.disks.disk.messages = pool.status.disks.disk.messages.replace(/\(untrimmed\)/gi, ""); - } - - pool.status.config.replacement.messages = [ - { pattern: /^\(/g, replacement: "" }, - { pattern: /\)$/g, replacement: "" }, - { pattern: / \(/g, replacement: ", " }, - { pattern: /\),/g, replacement: "," }, - { pattern: /\) /g, replacement: " " } - ]; - - pool.status.config.output += `Message:` + pool.status.config.replacement.messages.reduce((m, r) => m.replace(r.pattern, r.replacement), pool.status.disks.disk.messages) + ``; //Message - - if (pool.status.config.disk) { - if (/trimmed, started|trimmed started/i.test(pool.status.disks.disk.messages)) { - pool.status.disks.disk.trim.started = true; - - if (!pool.status.trim.started) { //Storage pool contains a disk with TRIM started - pool.status.trim.started = true; - } - } else if (/trimmed, suspended|trimmed suspended/i.test(pool.status.disks.disk.messages)) { - pool.status.disks.disk.trim.suspended = true; - - if (!pool.status.trim.suspended) { //Storage pool contains a disk with TRIM suspended - pool.status.trim.suspended = true; - } - } - } - - pool.status.config.output += `Product:`; //Product - - if (pool.status.config.disk) { - disks.lsblk.blockdevices.forEach((__value, __index) => { - if (__value.type == "disk") { - if (pool.status.disks.disk.upath.replace(/^\/dev\//gi, "") == __value.name || "nvme-" + __value.wwn == _value[0] || "wwn-" + __value.wwn == _value[0]) { - if (__value.rota == 0 || __value.rota === "false") { - pool.status.disks.disk.ssd = true; - - if (!pool.status.ssd) { //Storage pool contains an SSD - pool.status.disks.ssd = true; - } - } - - pool.status.config.output += FnFormatBytes({ base2: zfsmanager.configuration.disks.base2, decimals: 2, value: __value.size }) + " " + __value.model + (__value.serial ? " (" + __value.serial + ")" : ""); - } - } - }); - } - - pool.status.config.output += ``; - - //Actions Menu - pool.status.config.actionsmenu = { - items: { - storagepool: [], - storagepooldivider: function () { - if (this.storagepool.length > 0 && (this.virtualdevice.length > 0 || this.disk.length > 0)) { - this.storagepool.push(this.divider); - } - }, - virtualdevice: [], - virtualdevicedivider: function () { - if (this.virtualdevice.length > 0 && this.disk.length > 0) { - this.virtualdevice.push(this.divider); - } - }, - disk: [], - divider: `` - }, - display: function () { - if ((this.items.virtualdevice.length + this.items.virtualdevice.length + this.items.disk.length) > 0 || pool.readonly) { - this.items.storagepooldivider(); - this.items.virtualdevicedivider(); - return this.header + this.items.storagepool.join("\n") + this.items.virtualdevice.join("\n") + this.items.disk.join("\n") + this.footer; - } else { - return ""; - } - } - } - pool.status.config.actionsmenu.header = ` - - `; - pool.status.config.actionsmenu.register = { - storagepool: { - scrub: {}, - trim: {} - }, - virtualdevice: {}, - disk: { - trim: {} - } - }; - - //Clear storage pool errors - if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name) { - pool.status.config.actionsmenu.items.storagepool.push(`
  • Clear Storage Pool Errors
  • `); - - pool.status.config.actionsmenu.register.storagepool.clear = true; - } - - //Resilver Storage Pool - if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name && pool.feature.resilver_defer) { - pool.status.config.actionsmenu.items.storagepool.push(`
  • Resilver Storage Pool
  • `); - - pool.status.config.actionsmenu.register.storagepool.resilver = true; - } - - //Start Storage Pool Scrub - if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name && !pool.status.scrub.started && !pool.status.scrub.paused) { - pool.status.config.actionsmenu.items.storagepool.push(`
  • Scrub Storage Pool
  • `); - - pool.status.config.actionsmenu.register.storagepool.scrub.start = true; - } - - //Resume Storage Pool Scrub - if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name && pool.status.scrub.paused) { - pool.status.config.actionsmenu.items.storagepool.push(`
  • Resume Storage Pool Scrub
  • `); - - pool.status.config.actionsmenu.register.storagepool.scrub.resume = true; - } - - //Pause Storage Pool Scrub - if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name && pool.status.scrub.started) { - pool.status.config.actionsmenu.items.storagepool.push(`
  • Pause Storage Pool Scrub
  • `); - - pool.status.config.actionsmenu.register.storagepool.scrub.pause = true; - } - - //Stop Storage Pool Scrub - if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name && (pool.status.scrub.started || pool.status.scrub.paused)) { - pool.status.config.actionsmenu.items.storagepool.push(`
  • Stop Storage Pool Scrub
  • `); - - pool.status.config.actionsmenu.register.storagepool.scrub.stop = true; - } - - //TRIM Storage Pool - if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name && !pool.status.trim.started && !pool.status.trim.suspended) { - pool.status.config.actionsmenu.items.storagepool.push(`
  • TRIM Storage Pool
  • `); - - pool.status.config.actionsmenu.register.storagepool.trim.start = true; - } - - //Resume Storage Pool TRIM - if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name && pool.status.trim.suspended) { - pool.status.config.actionsmenu.items.storagepool.push(`
  • Resume Storage Pool TRIM
  • `); - - pool.status.config.actionsmenu.register.storagepool.trim.resume = true; - } - - //Suspend Storage Pool TRIM - if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name && pool.status.trim.started) { - pool.status.config.actionsmenu.items.storagepool.push(`
  • Suspend Storage Pool TRIM
  • `); - - pool.status.config.actionsmenu.register.storagepool.trim.suspend = true; - } - - //Cancel Storage Pool TRIM - if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name && (pool.status.trim.started || pool.status.trim.suspended)) { - pool.status.config.actionsmenu.items.storagepool.push(`
  • Cancel Storage Pool TRIM
  • `); - - pool.status.config.actionsmenu.register.storagepool.trim.cancel = true; - } - - //Upgrade Storage Pool - if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name && pool.status.upgrade) { - pool.status.config.actionsmenu.items.storagepool.push(`
  • Upgrade Storage Pool
  • `); - - pool.status.config.actionsmenu.register.storagepool.upgrade = true; - } - - //Regenerate Storage Pool GUID - if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name) { - pool.status.config.actionsmenu.items.storagepool.push(`
  • Regenerate Storage Pool GUID
  • `); - - pool.status.config.actionsmenu.register.storagepool.regenerateguid = true; - } - - //Clear Virtual Device Errors - if (!pool.readonly && pool.status.config.tier.level > 0 && !pool.status.config.disk) { - pool.status.config.actionsmenu.items.virtualdevice.push(`
  • Clear Virtual Device Errors
  • `); - - pool.status.config.actionsmenu.register.virtualdevice.clear = true; - } - - //Add Virtual Device - if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name) { - pool.status.config.actionsmenu.items.virtualdevice.push(`
  • Add Virtual Device
  • `); - - pool.status.config.actionsmenu.register.virtualdevice.add = true; - } - - //Remove Virtual Device - if (!pool.readonly && pool.status.config.tier.level == 1 && !pool.status.config.tier.replacing && (pool.feature.device_removal || pool.status.config.tier.spares)) { - pool.status.config.actionsmenu.items.virtualdevice.push(`
  • Remove Virtual Device
  • `); - - pool.status.config.actionsmenu.register.virtualdevice.remove = true; - } - - //Clear Disk Errors - if (!pool.readonly && pool.status.config.tier.level > 0 && !pool.status.config.tier.spares && pool.status.config.disk) { - pool.status.config.actionsmenu.items.disk.push(`
  • Clear Disk Errors
  • `); - - pool.status.config.actionsmenu.register.disk.clear = true; - } - - //Attach Disk: Disk and Mirror virtual devices only - if (!pool.readonly && pool.status.config.tier.level == 1 && !pool.status.config.tier.cache && !pool.status.config.tier.spares && (/^mirror-/g.test(_value[0]) || pool.status.config.disk)) { - pool.status.config.actionsmenu.items.disk.push(`
  • Attach Disk
  • `); - - pool.status.config.actionsmenu.register.disk.attach = true; - } - - //Detach Disk: Disk and Mirror virtual devices only - if (!pool.readonly && (pool.status.config.tier.level == 2 && /^spare-/g.test(_value[0]) == false || pool.status.config.tier.level == 3) && /^mirror-/g.test(pool.status.config.tier.nametier1) && pool.status.config.disk) { - pool.status.config.actionsmenu.items.disk.push(`
  • Detach Disk
  • `); - - pool.status.config.actionsmenu.register.disk.detach = true; - } - - if (!pool.readonly && pool.status.config.tier.level > 0 && pool.status.config.disk) { - //Online Disk / Offline Disk - if (_value[1] == "OFFLINE" || _value[1] == "UNAVAIL" || _value[1] == "FAULTED") { - pool.status.config.actionsmenu.items.disk.push(`
  • Online Disk
  • `); - - pool.status.config.actionsmenu.register.disk.online = true; - } else if ((_value[1] == "ONLINE" || _value[1] == "DEGRADED") && (pool.status.config.tier.level > 1 || pool.status.config.tier.level == 1 && (pool.status.config.tier.cache || pool.status.config.tier.logs))) { //Do not show offline disk if virtual device is Disk in Pool and Dedup - pool.status.config.actionsmenu.items.disk.push(`
  • Offline Disk
  • `); - - pool.status.config.actionsmenu.register.disk.offline = true; - } - - //Replace Disk - if (!pool.status.config.tier.spares) { - pool.status.config.actionsmenu.items.disk.push(`
  • Replace Disk
  • `); - - pool.status.config.actionsmenu.register.disk.replace = true; - } - - if (pool.status.disks.disk.ssd && !pool.status.disks.disk.trim.unsupported && !pool.status.config.tier.cache && !pool.status.config.tier.spares) { - //TRIM Disk - if (!pool.status.disks.disk.trim.started && !pool.status.disks.disk.trim.suspended) { - pool.status.config.actionsmenu.items.disk.push(`
  • TRIM Disk
  • `); - - pool.status.config.actionsmenu.register.disk.trim.start = true; - } - - //Resume Disk TRIM - if (pool.status.disks.disk.trim.suspended) { - pool.status.config.actionsmenu.items.disk.push(`
  • Resume Disk TRIM
  • `); - - pool.status.config.actionsmenu.register.disk.trim.resume = true; - } - - //Suspend Disk TRIM - if (pool.status.disks.disk.trim.started) { - pool.status.config.actionsmenu.items.disk.push(`
  • Suspend Disk TRIM
  • `); - - pool.status.config.actionsmenu.register.disk.trim.suspend = true; - } - - //Cancel Disk TRIM - if (pool.status.disks.disk.trim.started || pool.status.disks.disk.trim.suspended) { - pool.status.config.actionsmenu.items.disk.push(`
  • Cancel Disk TRIM
  • `); - - pool.status.config.actionsmenu.register.disk.trim.cancel = true; - } - } - } - - pool.status.config.output += ``; - pool.status.config.output += `` + pool.status.config.actionsmenu.display() + ``; - pool.status.config.output += ``; - - $("#tbody-storagepool-status-config-" + pool.id).append(pool.status.config.output); - - //Register status modals - if (pool.status.config.actionsmenu.register.disk.attach) { - FnModalStatusDiskAttach({ name: pool.name, id: pool.id, status: { config: { items: { index: _index }, tier: { name: pool.status.config.tier.nametier0, dedup: pool.status.config.tier.dedup, logs: pool.status.config.tier.logs, special: pool.status.config.tier.special } } } }, { id: _value[0], disk: pool.status.config.disk }); - } - if (pool.status.config.actionsmenu.register.disk.clear) { - FnModalStatusDiskClear({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }, { id: _value[0] }); - } - if (pool.status.config.actionsmenu.register.disk.detach) { - FnModalStatusDiskDetach({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }, { id: _value[0] }); - } - if (pool.status.config.actionsmenu.register.disk.offline) { - FnModalStatusDiskOffline({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }, { id: _value[0] }); - } - if (pool.status.config.actionsmenu.register.disk.online) { - FnModalStatusDiskOnline({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }, { id: _value[0] }); - } - if (pool.status.config.actionsmenu.register.disk.replace) { - FnModalStatusDiskReplace({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }, { id: _value[0] }); - } - if (pool.status.config.actionsmenu.register.storagepool.clear) { - FnModalStatusStoragePoolClear({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }); - } - if (pool.status.config.actionsmenu.register.storagepool.regenerateguid) { - FnModalStatusStoragePoolRegenerateGuid({ name: pool.name, id: pool.id, guid: pool.guid, status: { config: { items: { index: _index } } } }); - } - if (pool.status.config.actionsmenu.register.storagepool.resilver) { - FnModalStatusStoragePoolResilver({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } }, resilver: { started: pool.status.resilver.started } } }); - } - if (pool.status.config.actionsmenu.register.storagepool.trim.start) { - FnModalStatusStoragePoolTrimStart({ name: pool.name, id: pool.id, autotrim: pool.autotrim, status: { config: { items: { index: _index } } } }); - } - if (pool.status.config.actionsmenu.register.storagepool.upgrade) { - FnModalStatusStoragePoolUpgrade({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } }, version: pool.version }); - } - if (pool.status.config.actionsmenu.register.virtualdevice.add) { - FnModalStatusVirtualDeviceAdd({ name: pool.name, id: pool.id, feature: { allocation_classes: pool.feature.allocation_classes }, status: { config: { items: { index: _index } } } }); - } - if (pool.status.config.actionsmenu.register.virtualdevice.clear) { - FnModalStatusVirtualDeviceClear({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }, { id: _value[0] }); - } - if (pool.status.config.actionsmenu.register.virtualdevice.remove) { - FnModalStatusVirtualDeviceRemove({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }, { id: _value[0], disk: pool.status.config.disk }); - } - - //Register status dynamics - if (pool.status.config.actionsmenu.register.disk.trim.cancel) { - FnDynamicStatusDiskTrimCancel({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }, { id: _value[0] }); - } - if (pool.status.config.actionsmenu.register.disk.trim.resume) { - FnDynamicStatusDiskTrimResume({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }, { id: _value[0] }); - } - if (pool.status.config.actionsmenu.register.disk.trim.start) { - FnModalStatusDiskTrimStart({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }, { id: _value[0] }); - } - if (pool.status.config.actionsmenu.register.disk.trim.suspend) { - FnDynamicStatusDiskTrimSuspend({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }, { id: _value[0] }); - } - if (pool.status.config.actionsmenu.register.storagepool.scrub.pause) { - FnDynamicStatusStoragePoolScrubPause({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }); - } - if (pool.status.config.actionsmenu.register.storagepool.scrub.resume) { - FnDynamicStatusStoragePoolScrubResume({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }); - } - if (pool.status.config.actionsmenu.register.storagepool.scrub.start) { - FnDynamicStatusStoragePoolScrubStart({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }); - } - if (pool.status.config.actionsmenu.register.storagepool.scrub.stop) { - FnDynamicStatusStoragePoolScrubStop({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }); - } - if (pool.status.config.actionsmenu.register.storagepool.trim.cancel) { - FnDynamicStatusStoragePoolTrimCancel({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }); - } - if (pool.status.config.actionsmenu.register.storagepool.trim.resume) { - FnDynamicStatusStoragePoolTrimResume({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }); - } - if (pool.status.config.actionsmenu.register.storagepool.trim.suspend) { - FnDynamicStatusStoragePoolTrimSuspend({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }); - } - }); - - //Hide Storage Pool TRIM actions menu items if there is no SSD in the storage pool or all disks are TRIM unsupported - if (!pool.status.disks.ssd || pool.status.disks.trim.unsupportedcount == pool.status.disks.count) { - $("#btn-storagepool-status-trim-start-0-" + pool.id).addClass("hidden"); - $("#btn-storagepool-status-trim-resume-0-" + pool.id).addClass("hidden"); - $("#btn-storagepool-status-trim-suspend-0-" + pool.id).addClass("hidden"); - $("#btn-storagepool-status-trim-cancel-0-" + pool.id).addClass("hidden"); - } - - //Hide Remove Virtual Device actions menu item is there is only one in the storage pool - if (pool.status.config.virtualdevice.count < 2) { - $("[id^=btn-storagepool-status-virtualdevice-remove-][id$='" + pool.id + "'].pool-virtualdevice").addClass("hidden"); - $("[id^=divider-storagepool-status-][id$=" + pool.id + "].pool-virtualdevice").addClass("hidden"); - } - - $("#tr-storagepool-" + pool.id).attr("data-pool-refresh-status", "true"); - - $("#spinner-storagepool-status-" + pool.id).addClass("hidden"); - $("#paneltitle-storagepool-status-" + pool.id).removeClass("hidden").text(FnDateTime()); - $("#btn-storagepool-status-refresh-" + pool.id).prop("disabled", false); - $("#btn-storagepool-status-refresh-auto-" + pool.id).prop("disabled", false); - - FnStoragePoolSpinnerHide({ name: pool.name, id: pool.id }); - FnCockpitElementsUpdate(); -} - -function FnStatusGetFail(pool = { name, id, status: { empty: true } }) { - if (pool.status.empty) { - $("#tbody-storagepool-status-messages-" + pool.id).empty(); - $("#tbody-storagepool-status-config-" + pool.id).empty(); - $("#tbody-storagepool-status-messages-" + pool.id).append(`Status not available`); - $("#modals-storagepool-status-" + pool.id).remove(); - $("#dynamics-storagepool-status-" + pool.id).remove(); - - $("#tr-storagepool-" + pool.id).attr("data-pool-refresh-status", "true"); - - $("#spinner-storagepool-status-" + pool.id).addClass("hidden"); - $("#paneltitle-storagepool-status-" + pool.id).removeClass("hidden").text(FnDateTime()); - $("#btn-storagepool-status-refresh-" + pool.id).prop("disabled", false); - $("#btn-storagepool-status-refresh-auto-" + pool.id).prop("disabled", false); - } - - FnStoragePoolSpinnerHide({ name: pool.name, id: pool.id }); - FnCockpitElementsUpdate(); -} - -//#endregion - -//#region System - -function FnSystemHostIdGet(modal = { name, id }) { - let process = { - command: ["/bin/sh", "-c", "/bin/cat /etc/hostid 2> /dev/null && echo response true || echo response false"] - }; - - FnConsole.log[2]("System, Host ID, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "System, Host ID, Get:" })); - - data = data.replace(/\n+/g, "").replace(/^.+response /, "").replace("response ", ""); - - if (data == "false") { - if (modal.name) { - if ($("#switch-" + modal.name + "-multihost-" + modal.id + " input").prop("checked")) { - $("#btnspan-" + modal.name + "-hostid-" + modal.id).text("Use Lib C Generated Host ID").attr("data-field-value", "libc"); - $("#dropdown-" + modal.name + "-hostid-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-hostid-" + modal.id + " li[value='libc']").addClass("active"); - - $("#controllabel-" + modal.name + "-hostid-" + modal.id).removeClass("hidden"); - $("#validationwrapper-" + modal.name + "-hostid-" + modal.id).removeClass("hidden"); - } else { - $("#btnspan-" + modal.name + "-hostid-" + modal.id).text("Use Lib C Generated Host ID").attr("data-field-value", "missing"); - $("#dropdown-" + modal.name + "-hostid-" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-" + modal.name + "-hostid-" + modal.id + " li[value='libc']").addClass("active"); - } - } - - FnConsole.warn("System, Host ID, Get: Warning, Message: Host ID does not exist"); - } else { - FnConsole.log[1]("System, Host ID, Get: Success"); - } - }) - .fail(function (message, data) { - FnConsole.warn("System, Host ID, Get: Failed, Message: " + (data ? data : message)); - }); -} - -function FnSystemHostIdSet(system = { hostid }) { - let process = { - command: ["/bin/sh", "-c", "[ -x /usr/" + (/Debian/.test(zfsmanager.system.operatingsystem) ? "s" : "") + "bin/zgenhostid ] && /usr/" + (/Debian/.test(zfsmanager.system.operatingsystem) ? "s" : "") + "bin/zgenhostid" + (system.hostid ? " " + system.hostid : "") + " || zgenhostid " + (system.hostid ? " " + system.hostid : "")] - }; - - FnConsole.log[2]("System, Host ID, Set: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "System Host ID successfully configured", description: null, breakword: false }, { name: "system-hostid-set", id: null, timeout: 4 }); - - FnConsole.log[1]("System, Host ID, Set: Success"); - }) - .fail(function (message, data) { - FnConsole.warn("System, Host ID, Set: Failed, Message: " + (data ? data : message)); - }); -} - -function FnSystemNfsVersionGet(modal = { alert: { id } }) { - let process = { - command: ["/usr/sbin/nfsstat", "--version"] - }; - - FnConsole.log[2]("System, NFS, Version, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "System, NFS, Version, Get:" })); - - modal.alert.id.addClass("hidden"); - - FnConsole.log[1]("System, NFS, Version, Get: Success"); - }) - .fail(function () { - modal.alert.id.removeClass("hidden"); - - FnConsole.warn("System, NFS, Version, Get: Failed, Message: NFS is not installed."); - }); -} - -function FnSystemOperatingSystemGet() { - let process = { - command: ["/bin/sh", "-c", "/usr/bin/hostnamectl status | /bin/grep 'Operating System'"] - }; - - FnConsole.log[2]("System, Operating System, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "System, Operating System, Get:" })); - - data = data.replace(/\n+/g, "").replace(/^(?: +)Operating System: /, ""); - - if (data) { - zfsmanager.system.operatingsystem = data; - } - - FnConsole.log[2]("System, Operating System, Get: Success"); - }) - .fail(function (message, data) { - FnConsole.warn("System, Operating System, Get: Failed, Message: " + (data ? data : message)); - }); -} - -//#endregion - -//#region Disks - -function FnDisksAvailableGet(modal = { name, id, default: true }) { - disks = { - attached: [], - id: { - device: [], - path: [], - vdev: [] - }, - importable: [], - importableconfig: [], - importableconfigok: false, - storagepools: [], - storagepoolsconfig: [] - - }; - modal.id = (modal.id ? "-" + modal.id : ""); - - $("#listgroup-" + modal.name + modal.id).empty(); - $("#listgroup-" + modal.name + modal.id).append(`
  • `); - - FnDisksStoragePoolsAttachedGet({ name: null, id: null }, { id: { blockdevice: true } }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Disks, Storage Pools, Attached, Get:" })); - - disks.storagepools = data.replace(/\n\t+/g, "[TAB1]").split(/\n/g).filter(v => v); - - disks.storagepools.forEach((_value, _index) => { - if (/\[TAB1\]NAME/g.test(_value)) { //Config header row - _value = _value.split("upath").slice(1).join("."); //Remove config header row (and any previous text if exists) - - if (new RegExp("^\\[TAB1\\]").test(_value)) { //Confirm config rows - _value.split("[TAB1]").filter(v => v && disks.storagepoolsconfig.push(v)); - } - } - }); - - disks.storagepoolsconfig.forEach((_value, _index) => { - let config = { - disk: { - upath: "" - }, - tier: { - level: (_value.match(/^\s*/g)[0].length / 2) - } - }; - - _value = _value.replace(/ +/g, "\u22C5").replace(/^\u22C5/, "").split("\u22C5").filter(v => v); - - if (/^\/dev\/nvme|^\/dev\/sd/gi.test(_value[5])) { //upath - config.disk.upath = _value[5]; - } else if (!$.isNumeric(_value[0]) && _value[5] != "was") { //upath appears after error messages and before trim messages - for (let i = 5; i < _value.length; i++) { - if (/^\/dev\/nvme|^\/dev\/sd/gi.test(_value[i])) { - config.disk.upath = _value[i]; - } - } - } - - if (config.tier.level > 0) { - if (/^\/dev\/nvme|^\/dev\/sd/gi.test(config.disk.upath)) { //Block Device via upath - disks.attached.push(config.disk.upath.replace(/^\/dev\//gi, "")); - } else if (/^\/dev\/nvme|^\/dev\/sd/gi.test(_value[0])) { //Block Device - if (/^\/dev\/nvme\d+n\d+p\d+$/gi.test(_value[0])) { - disks.attached.push(_value[0].replace(/^\/dev\//gi, "").replace(/p\d+$/, "")); - } else if (/^\/dev\/sd.*\d+$/gi.test(_value[0])) { - disks.attached.push(_value[0].replace(/^\/dev\//gi, "").replace(/\d+$/, "")); - } else { - disks.attached.push(_value[0]); - } - } else if (/^nvme-nvme/gi.test(_value[0]) || /^wwn-/gi.test(_value[0])) { //WWN - if (/^nvme-nvme.*-part\d+$/gi.test(_value[0])) { - disks.attached.push(_value[0].replace(/-part\d+$/, "")); - } else if (/^wwn-.*-part\d+$/gi.test(_value[0])) { - disks.attached.push(_value[0].replace(/-part\d+$/, "")); - } else { - disks.attached.push(_value[0]); - } - } - } - }); - - disks.attached.sort(); - - FnDisksStoragePoolsImportableAttachedGet() - .done(function (_data) { - FnConsole.log[4](FnConsoleVerbose({ data: _data, message: "Disks, Storage Pools, Importable, Attached, Get:" })); - - disks.importable = _data.replace(/\n\t+/g, "[TAB1]").split(/\n/g).filter(v => v); - - disks.importable.forEach((_value, _index) => { - if (/config:/g.test(_value)) { //Config header row - disks.importableconfigok = true; - } - - if (new RegExp("^\\[TAB1\\]").test(_value) && disks.importableconfigok) { //Confirm config rows - _value.split("[TAB1]").filter(v => v && disks.importableconfig.push(v)); - } - }); - - disks.importableconfig.forEach((_value, _index) => { - let config = { - tier: { - level: (_value.match(/^\s*/g)[0].length / 2) - } - }; - - _value = _value.replace(/ +/g, "\u22C5").replace(/^\u22C5/, "").split("\u22C5").filter(v => v); - - if (config.tier.level > 0) { - if (/^nvme|^sd/gi.test(_value[0])) { //Block Device - if (/^nvme\d+n\d+p\d+$/gi.test(_value[0])) { - disks.attached.push(_value[0].replace(/p\d+$/, "")); - } else if (/^sd.*\d+$/gi.test(_value[0])) { - disks.attached.push(_value[0].replace(/\d+$/, "")); - } else { - disks.attached.push(_value[0]); - } - } else if (/^\/dev\/nvme|^\/dev\/sd/gi.test(_value[0])) { //Block Device - if (/^\/dev\/nvme\d+n\d+p\d+$/gi.test(_value[0])) { - disks.attached.push(_value[0].replace(/^\/dev\//gi, "").replace(/p\d+$/, "")); - } else if (/^\/dev\/sd.*\d+$/gi.test(_value[0])) { - disks.attached.push(_value[0].replace(/^\/dev\//gi, "").replace(/\d+$/, "")); - } else { - disks.attached.push(_value[0]); - } - } else if (/^nvme-nvme/gi.test(_value[0]) || /^wwn-/gi.test(_value[0])) { //WWN - if (/^nvme-nvme.*-part\d+$/gi.test(_value[0])) { - disks.attached.push(_value[0].replace(/-part\d+$/, "")); - } else if (/^wwn-.*-part\d+$/gi.test(_value[0])) { - disks.attached.push(_value[0].replace(/-part\d+$/, "")); - } else { - disks.attached.push(_value[0]); - } - } - } - }); - - disks.attached.sort(); - - FnDisksLsblkGet({ sizeraw: true }) - .done(function (__data) { - FnConsole.log[4](FnConsoleVerbose({ data: __data, message: "Disks, Lsblk, Get:" })); - - disks.lsblkjson = __data; - - FnDisksBlkidGet() - .done(function (___data) { - FnConsole.log[4](FnConsoleVerbose({ data: ___data, message: "Disks, Blkid, Get:" })); - - let replacement = { - regexp: [ - { pattern: /"/g, replacement: "" }, - { pattern: /: LABEL=/g, replacement: ",LABEL=" }, - { pattern: / UUID=/g, replacement: ",UUID=" }, - { pattern: / UUID_SUB=/g, replacement: ",UUID_SUB=" }, - { pattern: / TYPE=/g, replacement: ",TYPE=" }, - { pattern: / PARTLABEL=/g, replacement: ",PARTLABEL=" }, - { pattern: / PARTUUID=/g, replacement: ",PARTUUID=" } - ] - }; - - disks.blkid = replacement.regexp.reduce((d, r) => d.replace(r.pattern, r.replacement), ___data).split(/\n/g).filter(v => v); - - FnDisksIdentifierDiskGet() - .done(function (____data) { - FnConsole.log[4](FnConsoleVerbose({ data: ____data, message: "Disks, Identifier, Disk / WWN, Get:" })); - disks.id.device = ____data.replace(/\t+/g, "\u22C5").replace(/..\/..\//g, "").split(/\n/g).filter(v => v && v != "\u22C5"); + return data.value; +} - FnDisksIdentifierHardwarePathGet() - .done(function (_____data) { - FnConsole.log[4](FnConsoleVerbose({ data: _____data, message: "Disks, Identifier, Hardware Path, Get:" })); +function FnFormatBytes(data = { base2: true, decimals: 0, value }) { + if (data.value == 0) { + return "0 B"; + } - disks.id.path = _____data.replace(/\t+/g, "\u22C5").replace(/..\/..\//g, "").split(/\n/g).filter(v => v && v != "\u22C5"); + data.bytes = (data.base2 ? 1024 : 1000); + data.sizes = (data.base2 ? ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB"] : ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB"]); + data.integer = Math.floor(Math.log(data.value) / Math.log(data.bytes)); + data.decimals = (data.decimals <= 0 ? 0 : data.decimals); - FnDisksIdentifierVirtualDeviceMappingGet() - .done(function (______data) { - FnConsole.log[4](FnConsoleVerbose({ data: ______data, message: "Disks, Identifier, Virtual Device Mapping, Get:" })); + data.sizefriendly = parseFloat((data.value / Math.pow(data.bytes, data.integer)).toFixed(data.decimals)).toString() + " " + data.sizes[data.integer]; - disks.id.vdev = ______data.replace(/\t+/g, "\u22C5").replace(/..\/..\//g, "").split(/\n/g).filter(v => v && v != "\u22C5"); + if (data.sizefriendly == "NaN undefined") { + data.sizefriendly = "-"; + } - FnDisksAvailableGetCommand({ attached: disks.attached, blkid: disks.blkid, id: { device: disks.id.device, path: disks.id.path, vdev: disks.id.vdev }, lsblkjson: disks.lsblkjson }, { name: modal.name, id: modal.id, default: modal.default }); - }) - .fail(function (______message, ______data) { - FnConsole.warn("Disks, Available, Get: Failed, Message: " + (______data ? ______data : ______message)); - - FnDisksAvailableGetFail({ name: modal.name, id: modal.id }, { data: ______data, message: ______message }); - }); - }) - .fail(function (_____message, _____data) { - FnConsole.warn("Disks, Available, Get: Failed, Message: " + (_____data ? _____data : _____message)); - - FnDisksAvailableGetFail({ name: modal.name, id: modal.id }, { data: _____data, message: _____message }); - }); - }) - .fail(function (____message, ____data) { - FnConsole.warn("Disks, Available, Get: Failed, Message: " + (____data ? ____data : ____message)); - - FnDisksAvailableGetFail({ name: modal.name, id: modal.id }, { data: ____data, message: ____message }); - }); - }) - .fail(function (___message, ___data) { - FnConsole.warn("Disks, Available, Get: Failed, Message: " + (___data ? ___data : ___message)); - - FnDisksAvailableGetFail({ name: modal.name, id: modal.id }, { data: ___data, message: ___message }); - }); - }) - .fail(function (__message, __data) { - FnConsole.warn("Disks, Available, Get: Failed, Message: " + (__data ? __data : __message)); - - FnDisksAvailableGetFail({ name: modal.name, id: modal.id }, { data: __data, message: __message }); - }); - }) - .fail(function (_message, _data) { - FnConsole.warn("Disks, Available, Get: Failed, Message: " + (_data ? _data : _message)); - - FnDisksAvailableGetFail({ name: modal.name, id: modal.id }, { data: _data, message: _message }); - }); - }) - .fail(function (message, data) { - FnConsole.warn("Disks, Available, Get: Failed, Message: " + (data ? data : message)); - - FnDisksAvailableGetFail({ name: modal.name, id: modal.id }, { data: data, message: message }); - }); -} - -function FnDisksAvailableGetCommand(disks = { attached: [], blkid: [], id: { device: [], path: [], vdev: [] }, lsblkjson }, modal = { name, id, default: true }) { - disks.lsblk = JSON.parse(disks.lsblkjson); - disks.regexp = {}; - - disks.lsblk.blockdevices.forEach((_value, _index) => { - if (_value.type == "disk") { - let disk = { - id: { - blockdevice: "", - disk: "", - path: "", - vdev: "", - wwn: "" - }, - allow: true, - zfsmember: false, - warning: "", - warningicon: "", - }; - - disks.attached.forEach((__value, __index) => { - if (_value.name == __value || _value.wwn == __value || "nvme-" + _value.wwn == __value || "wwn-" + _value.wwn == __value) { //Do not allow if block device or WWN identifier match - disk.allow = false; - return; - } - }); - - if (_value.children && disk.allow) { - _value.children.forEach((__value, __index) => { - if (__value.mountpoint) { //Do not allow if partition of disk is mounted - disk.allow = false; - return; - } - }); - } - - if (disk.allow) { - disks.blkid.forEach((__value, __index) => { - disks.regexp.name = new RegExp("^\/dev\/" + _value.name, "gi"); - - if (disks.regexp.name.test(__value)) { - if (/,TYPE=zfs_member/gi.test(__value)) { - disk.zfsmember = true; - return; - } - } - }); - - if (disk.zfsmember) { - disk.warningicon = ` `; - - $("#helpblock-" + modal.name + "-zfsmemberwarning" + modal.id).html("One or more disks used to be a member of a Storage Pool." + disk.warningicon); - } - - disk.id.blockdevice = _value.name; - - if (!_value.wwn) { - disk.id.wwn = ""; - disk.warning = "One or more disks is missing a WWN identifier."; - - $("#helpblock-" + modal.name + "-identifierwarning" + modal.id).removeClass("hidden").text(disk.warning); - } else { - if (/^nvme/gi.test(_value.wwn)) { - disk.id.wwn = "nvme-" + _value.wwn; - } else { - disk.id.wwn = "wwn-" + _value.wwn; - } - } - - disks.id.device.forEach((_value, _index) => { - _value = _value.split("\u22C5"); - - if (_value[1] == disk.id.blockdevice) { - if (/^nvme-nvme|^wwn-/gi.test(_value[0])) { - return; - } else { - disk.id.disk = _value[0]; - return; - } - } - }); - - disks.id.path.forEach((_value, _index) => { - _value = _value.split("\u22C5"); - - if (_value[1] == disk.id.blockdevice) { - disk.id.path = _value[0]; - - return; - } - }); - - disks.id.vdev.forEach((_value, _index) => { - _value = _value.split("\u22C5"); - - if (_value[1] == disk.id.blockdevice) { - disk.id.vdev = _value[0]; - - return; - } - }); - - disks.output = ` - - `; - - $("#listgroup-" + modal.name + modal.id).append(disks.output); - } - } - }); - - setTimeout(function () { - $("#spinner-" + modal.name + modal.id).remove(); - $("#listgroup-" + modal.name + modal.id + " > li").removeClass("hidden"); - - if ($("#helpblock-" + modal.name + "-identifierwarning" + modal.id).text) { - $("#helpblock-" + modal.name + "-identifierwarning" + modal.id).removeClass("hidden"); - } - if ($("#helpblock-" + modal.name + "-zfsmemberwarning" + modal.id).text()) { - $("#helpblock-" + modal.name + "-zfsmemberwarning" + modal.id).removeClass("hidden"); - } - - if ($("#listgroup-" + modal.name + modal.id + " > li").length == 1 && modal.default) { //Change Virtual Device dropdown to Disk if there is only 1 disk available - if (modal.name == "storagepools-create-disks") { - $("#btnspan-storagepools-create-virtualdevice").text("Disk").attr("data-field-value", "disk"); - $("#dropdown-storagepools-create-virtualdevice li").siblings().removeClass("active"); - $("#dropdown-storagepools-create-virtualdevice li[value='disk']").addClass("active"); - } else if (modal.name == "storagepool-status-virtualdevice-add-disks") { - $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice" + modal.id).text("Disk").attr("data-field-value", "disk"); - $("#dropdown-storagepool-status-virtualdevice-add-virtualdevice" + modal.id + " li").siblings().removeClass("active"); - $("#dropdown-storagepool-status-virtualdevice-add-virtualdevice" + modal.id + " li[value='disk']").addClass("active"); - } - } - - if ($("#listgroup-" + modal.name + modal.id + " > li").length == 0) { - disks.output = ` -
  • - -
  • - `; - - $("#listgroup-" + modal.name + modal.id).append(disks.output); - } - }, 200); - - FnConsole.log[1]("Disks, Available, Get: Success"); -} - -function FnDisksAvailableGetFail(modal = { name, id }, process = { data, message }) { - setTimeout(function () { - $("#spinner-" + modal.name + modal.id).remove(); - $("#listgroup-" + modal.name + modal.id + " > li").removeClass("hidden"); - - if ($("#listgroup-" + modal.name + modal.id + " > li").length == 0) { - let disks = { - output: "" - }; - - disks.output = ` -
  • - -
  • - `; - - $("#listgroup-" + modal.name + modal.id).append(disks.output); - } - }, 200); -} - -function FnDisksBlkidGet() { - let process = { - command: ["/bin/sh", "-c", "/sbin/blkid -o full | /bin/grep -E '/dev/nvme\|/dev/sd'"] - }; - - FnConsole.log[2]("Disks, Blkid, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnConsole.log[2]("Disks, Blkid, Get: Success"); - }) - .fail(function (message, data) { - FnConsole.warn("Disks, Blkid, Get: Failed, Message: " + (data ? data : message)); - }); -} - -function FnDisksIdentifierDiskGet() { - let process = { - command: ["/bin/sh", "-c", `ls -lF /dev/disk/by-id | awk '{ print $9"\t"$11 }'`] - }; - - FnConsole.log[2]("Disks, Identifier, Disk / WWN, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnConsole.log[2]("Disks, Identifier, Disk / WWN, Get: Success"); - }) - .fail(function (message, data) { - FnConsole.warn("Disks, Identifier, Disk / WWN, Get: Failed, Message: " + (data ? data : message)); + return data.sizefriendly; +} + +function FnGenerateId(character = { at: false, colon: false, forwardslash: false, period: false, underscore: false, whitespace: false }, data = { name, attribute: true }) { + let replacement = { + character: (data.attribute ? "\u22C5" : "_"), + regexp: [] + }; + + if (character.underscore) { + replacement.regexp.push({ pattern: /[_]/g, replacement: (data.attribute ? replacement.character + "u" + replacement.character : replacement.character) }) + } + if (character.at) { + replacement.regexp.push({ pattern: /[@]/g, replacement: (data.attribute ? replacement.character + "a" + replacement.character : replacement.character) }) + } + if (character.colon) { + replacement.regexp.push({ pattern: /[:]/g, replacement: (data.attribute ? replacement.character + "c" + replacement.character : replacement.character) }) + } + if (character.forwardslash) { + replacement.regexp.push({ pattern: /[/]/g, replacement: (data.attribute ? replacement.character + "f" + replacement.character : replacement.character) }) + } + if (character.period) { + replacement.regexp.push({ pattern: /[.]/g, replacement: (data.attribute ? replacement.character + "p" + replacement.character : replacement.character) }) + } + if (character.whitespace) { + replacement.regexp.push({ pattern: /[ ]/g, replacement: (data.attribute ? replacement.character + "w" + replacement.character : replacement.character) }) + } + + return replacement.regexp.reduce((n, r) => n.replace(r.pattern, r.replacement), data.name); +} + +function FnGenerateShareFileName(data = { name }) { + replacement = { + character: "_", + regexp: [] + }; + + replacement.regexp.push({ pattern: /[/]/g, replacement: replacement.character }); + + return replacement.regexp.reduce((n, r) => n.replace(r.pattern, r.replacement), data.name); +} + +function FnGenerateShareName(character = { at: false, colon: false, period: false, whitespace: false }, data = { name }) { + let replacement = { + character: "_", + regexp: [] + }; + + replacement.regexp.push({ pattern: /[/]/g, replacement: replacement.character }); + + if (character.at) { + replacement.regexp.push({ pattern: /[@]/g, replacement: replacement.character }) + } + if (character.colon || zfsmanager.configuration.samba.windowscompatibility) { + replacement.regexp.push({ pattern: /[:]/g, replacement: replacement.character }) + } + if (character.period) { + replacement.regexp.push({ pattern: /[.]/g, replacement: replacement.character }) + } else if (zfsmanager.configuration.samba.windowscompatibility) { + replacement.regexp.push({ pattern: /[.]$/g, replacement: replacement.character }) + } + if (character.whitespace) { + replacement.regexp.push({ pattern: /[ ]/g, replacement: replacement.character }) + } + + return replacement.regexp.reduce((n, r) => n.replace(r.pattern, r.replacement), data.name); +} + +function FnRound(data = { decimals: 0, value }) { + data.multiplier = Math.pow(10, data.decimals); + + return Math.round(data.value * data.multiplier) / data.multiplier; +} + +//#endregion + +//#region Date/Time + +function FnDateTime() { + return (new Date).toLocaleString(zfsmanager.cockpit.datelocale, { day: "numeric", month: "numeric", year: "numeric", hour: "numeric", minute: "numeric", second: "numeric", hour12: true }); +} + +function FnDateTimeEpoch(data = { date }) { + return (new Date(data.date * 1000)).toLocaleString(zfsmanager.cockpit.datelocale, { hour12: true }); +} + +function FnDateTimeSnapshot(data = { date }) { + if (!data.date) { + data.date = new Date(); + } + + return data.date.getFullYear() + "." + FnAppendLeadingZeroes({ value: data.date.getMonth() + 1 }) + "." + FnAppendLeadingZeroes({ value: data.date.getDate() }) + "-" + FnAppendLeadingZeroes({ value: data.date.getHours() }) + "." + FnAppendLeadingZeroes({ value: data.date.getMinutes() }) + "." + FnAppendLeadingZeroes({ value: data.date.getSeconds() }); +} + +//#endregion + +//#region Display Alert + +function FnDisplayAlert(notification = { status, title, description, breakword: false }, toast = { name, id, timeout: 4 }) { + if (zfsmanager.cockpit.legacy) { //Dirty way of handling alerts for PF3 and PF4 + FnDisplayAlertLegacy({ status: notification.status, title: notification.title, description: notification.description, breakword: notification.breakword }, { name: toast.name, id: toast.id, timeout: toast.timeout }); + + return; + } + + toast.timeout = ($.isNumeric(toast.timeout) ? toast.timeout : 4); + toast.uniqueid = (new Date).getTime() + "-" + Math.round(Math.random() * 20); + + switch (notification.status) { + case "danger": + toast.icon = "fa fa-exclamation-circle"; + toast.statusaria = "Danger"; + break; + case "info": + toast.icon = "fa fa-info-circle"; + toast.statusaria = "Information"; + break; + case "success": + toast.icon = "fa fa-check-circle"; + toast.statusaria = "Success"; + break; + case "warning": + toast.icon = "fa fa-exclamation-triangle"; + toast.statusaria = "Warning"; + break; + default: + notification.status = ""; + toast.icon = "fa fa-bell"; + toast.statusaria = "Default"; + break; + } + + notification.output = ` +
  • +
    +
    + +
    +

    ` + toast.statusaria + ` alert:` + notification.title + `

    + ` + (notification.description ? `

    ` + notification.description + `

    ` : ``) + ` +
    + +
    +
    + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#alert-` + toast.name + (toast.id ? `-` + toast.id : ``) + `-` + toast.uniqueid + ` .pf-c-alert__action").on("click",".pf-c-button",function(){ + $("#alert-` + toast.name + (toast.id ? `-` + toast.id : ``) + `-` + toast.uniqueid + `").fadeTo(150, 0).slideUp(150, function () { + $(this).remove(); + }); + }); + + setTimeout(function () { + $("#alert-` + toast.name + (toast.id ? `-` + toast.id : ``) + `-` + toast.uniqueid + `").fadeTo(500, 0).slideUp(500, function () { + $(this).remove(); + }); + }, ` + toast.timeout + `000); + \x3C/script> +
  • + `; + + $("#alerts-notifications").append(notification.output); +} + +function FnDisplayAlertLegacy(notification = { status, title, description, breakword: false }, toast = { name, id, timeout: 4 }) { + toast.timeout = ($.isNumeric(toast.timeout) ? toast.timeout : 4); + toast.uniqueid = (new Date).getTime() + "-" + Math.round(Math.random() * 20); + + switch (notification.status) { + case "danger": + toast.icon = "pficon pficon-error-circle-o"; + break; + case "success": + toast.icon = "pficon pficon-ok"; + break; + case "warning": + toast.icon = "pficon pficon-warning-triangle-o"; + break; + default: + notification.status = "info"; + toast.icon = "pficon pficon-info"; + break; + } + + notification.output = ` +
    + + + ` + notification.title + (notification.description ? `:` : ``) + ` ` + (notification.description ? notification.description : ``) + ` + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + setTimeout(function () { + $("#toast-` + toast.name + (toast.id ? `-` + toast.id : ``) + `-` + toast.uniqueid + `").fadeTo(500, 0).slideUp(500, function () { + $(this).remove(); + }); + }, ` + toast.timeout + `000); + \x3C/script> +
    + `; + + $("#alerts-notifications-legacy").append(notification.output); +} + +function FnDisplayInlineAlert(notification = { status, title, description }, inline = { name, id, hidden: false }) { + if (zfsmanager.cockpit.legacy) { //Dirty way of handling alerts for PF3 and PF4 + return FnDisplayInlineAlertLegacy({ status: notification.status, title: notification.title, description: notification.description }, { name: inline.name, id: inline.id, hidden: inline.hidden }); + } + + switch (notification.status) { + case "danger": + inline.icon = "fa fa-exclamation-circle"; + inline.statusaria = "Danger"; + break; + case "info": + inline.icon = "fa fa-info-circle"; + inline.statusaria = "Information"; + break; + case "success": + inline.icon = "fa fa-check-circle"; + inline.statusaria = "Success"; + break; + case "warning": + inline.icon = "fa fa-exclamation-triangle"; + inline.statusaria = "Warning"; + break; + default: + notification.status = ""; + inline.icon = "fa fa-bell"; + inline.statusaria = "Default"; + break; + } + + notification.output = ` +
    +
    + +
    +

    ` + inline.statusaria + ` inline alert:` + notification.title + `

    + ` + (notification.description ? `

    ` + notification.description + `

    ` : ``) + ` +
    + `; + + return notification.output; +} + +function FnDisplayInlineAlertLegacy(notification = { status, title, description }, inline = { name, id, hidden: false }) { + switch (notification.status) { + case "danger": + inline.icon = "pficon pficon-error-circle-o"; + break; + case "success": + inline.icon = "pficon pficon-ok"; + break; + case "warning": + inline.icon = "pficon pficon-warning-triangle-o"; + break; + default: + notification.status = "info"; + inline.icon = "pficon pficon-info"; + break; + } + + notification.output = ` +
    ` + notification.title + (notification.description ? `: ` + notification.description : ``) + `
    + `; + + return notification.output; +} + +//#endregion + +//#region Console Logging + +let FnConsole = () => { }; + +function FnConsoleCommand(process = { command: [] }) { + return JSON.stringify(process.command.join(" ")); +} + +function FnConsoleInitialize() { + FnConsole = (() => { + let time = () => { }; + + time.toString = () => { + return (new Date).toLocaleString(zfsmanager.cockpit.datelocale, { hour: "numeric", minute: "numeric", second: "numeric", hour12: true }) + ":"; + }; + + return { + error: console.error.bind(console, "%s", time), + log: { + 1: (zfsmanager.configuration.loglevel >= 1 ? console.log.bind(console, "%s", time) : FnConsoleNull), + 2: (zfsmanager.configuration.loglevel >= 2 ? console.log.bind(console, "%s", time) : FnConsoleNull), + 3: (zfsmanager.configuration.loglevel >= 3 ? console.log.bind(console, "%c%s Command: %s", "color: #0066CC", time) : FnConsoleNull), + 4: (zfsmanager.configuration.loglevel == 4 ? console.log.bind(console, "%c%s %s", "color: #486B00", time) : FnConsoleNull) + }, + warn: console.warn.bind(console, "%s", time) + } + })(); +} + +function FnConsoleNull() { + //Do not display console message +} + +function FnConsoleVerbose(process = { data, message }) { + return process.message + " Verbose\n" + process.data; +} + +//#endregion + +//#region Cockpit ZFS Manager + +function FnConfigurationGet() { + FnConsole.log[2]("Cockpit ZFS Manager, Configuration, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: [`cockpit.file("/etc/cockpit/zfs/config.json").read()`] })); + + return cockpit.file("/etc/cockpit/zfs/config.json").read() + .done(function (user) { + FnConsole.log[4](FnConsoleVerbose({ data: user, message: "Cockpit ZFS Manager, Configuration, Get:" })); + + try { + user = JSON.parse(user, (key, value) => { + if (/^#[0-9]/.test(key) == false) { + return value; + } + }); + + user.cockpit = (user.cockpit === undefined ? zfsmanager.configuration.cockpit : user.cockpit); + user.cockpit.manage = (user.cockpit.manage === undefined ? zfsmanager.configuration.cockpit.manage : user.cockpit.manage); + + user.disks = (user.disks === undefined ? zfsmanager.configuration.disks : user.disks); + user.disks.base2 = (user.disks.base2 === undefined ? zfsmanager.configuration.disks.base2 : user.disks.base2); + + user.loglevel = (user.loglevel === undefined ? zfsmanager.configuration.loglevel : user.loglevel); + + user.samba = (user.samba === undefined ? zfsmanager.configuration.samba : user.samba); + user.samba.manage = (user.samba.manage === undefined ? zfsmanager.configuration.samba.manage : user.samba.manage); + user.samba.windowscompatibility = (user.samba.windowscompatibility === undefined ? zfsmanager.configuration.samba.windowscompatibility : user.samba.windowscompatibility); + + user.updates = (user.updates === undefined ? zfsmanager.configuration.updates : user.updates); + user.updates.check = (user.updates.check === undefined ? zfsmanager.configuration.updates.check : user.updates.check); + + user.zfs = (user.zfs === undefined ? zfsmanager.configuration.zfs : user.zfs); + user.zfs.filesystem = (user.zfs.filesystem === undefined ? zfsmanager.configuration.zfs.filesystem : user.zfs.filesystem); + user.zfs.filesystem.snapshotactions = (user.zfs.filesystem.snapshotactions === undefined ? zfsmanager.configuration.zfs.filesystem.snapshotactions : user.zfs.filesystem.snapshotactions); + user.zfs.filesystem.cloneorigin = (user.zfs.filesystem.cloneorigin === undefined ? zfsmanager.configuration.zfs.filesystem.cloneorigin : user.zfs.filesystem.cloneorigin); + user.zfs.filesystem.quotarestrict = (user.zfs.filesystem.quotarestrict === undefined ? zfsmanager.configuration.zfs.filesystem.quotarestrict : user.zfs.filesystem.quotarestrict); + user.zfs.filesystem.readonlylockdown = (user.zfs.filesystem.readonlylockdown === undefined ? zfsmanager.configuration.zfs.filesystem.readonlylockdown : user.zfs.filesystem.readonlylockdown); + user.zfs.snapshot = (user.zfs.snapshot === undefined ? zfsmanager.configuration.zfs.snapshot : user.zfs.snapshot); + user.zfs.snapshot.filesystemlist = (user.zfs.snapshot.filesystemlist === undefined ? zfsmanager.configuration.zfs.snapshot.filesystemlist : user.zfs.snapshot.filesystemlist); + user.zfs.status = (user.zfs.status === undefined ? zfsmanager.configuration.zfs.status : user.zfs.status); + user.zfs.status.errorcolors = (user.zfs.status.errorcolors === undefined ? zfsmanager.configuration.zfs.status.errorcolors : user.zfs.status.errorcolors); + user.zfs.status.trimunsupported = (user.zfs.status.trimunsupported === undefined ? zfsmanager.configuration.zfs.status.trimunsupported : user.zfs.status.trimunsupported); + user.zfs.storagepool = (user.zfs.storagepool === undefined ? zfsmanager.configuration.zfs.storagepool : user.zfs.storagepool); + user.zfs.storagepool.activetab = (user.zfs.storagepool.activetab === undefined ? zfsmanager.configuration.zfs.storagepool.activetab : user.zfs.storagepool.activetab); + user.zfs.storagepool.count = (user.zfs.storagepool.count === undefined ? zfsmanager.configuration.zfs.storagepool.count : user.zfs.storagepool.count); + user.zfs.storagepool.boot = (user.zfs.storagepool.boot === undefined ? zfsmanager.configuration.zfs.storagepool.boot : user.zfs.storagepool.boot); + user.zfs.storagepool.bootlockdown = (user.zfs.storagepool.bootlockdown === undefined ? zfsmanager.configuration.zfs.storagepool.bootlockdown : user.zfs.storagepool.bootlockdown); + user.zfs.storagepool.root = (user.zfs.storagepool.root === undefined ? zfsmanager.configuration.zfs.storagepool.root : user.zfs.storagepool.root); + user.zfs.storagepool.refreshall = (user.zfs.storagepool.refreshall === undefined ? zfsmanager.configuration.zfs.storagepool.refreshall : user.zfs.storagepool.refreshall); + + zfsmanager.configuration = user; + zfsmanager.user.configuration = true; + + FnConsole.log[1]("Cockpit ZFS Manager, Configuration, Get: Success"); + + FnConsoleInitialize(); + } + catch (error) { + FnConsole.warn("Cockpit ZFS Manager, Configuration, Get: Failed, Message: Configuration does not exist. Using defaults."); + }; + }) + .fail(function (message) { + FnConsole.warn("Cockpit ZFS Manager, Configuration, Get: Failed, Message: Configuration does not exist. Using defaults."); + }); +}; + +function FnConfigure(user = { cockpit: { manage: true }, disks: { base2: false }, loglevel: 1, samba: { manage: true, windowscompatibility: true }, updates: { check: true }, zfs: { filesystem: { cloneorigin: false, quotarestrict: true, readonlylockdown: true, snapshotactions: true }, snapshot: { filesystemlist: true }, status: { errorcolors: true, trimunsupported: false }, storagepool: { activetab: 1, boot: true, bootlockdown: true, count: true, refreshall: false, root: true } } }, modal = { name, welcome: false }) { + let process = { + command: ["/bin/sh", "-c", "echo '" + JSON.stringify(user, null, " ").replace(/^\{\n/, `{\n "#1": "COCKPIT ZFS MANAGER",\n "#2": "WARNING: DO NOT EDIT, AUTO-GENERATED CONFIGURATION",\n`) + "' > /etc/cockpit/zfs/config.json"] + }; + + FnConsole.log[2]("Cockpit ZFS Manager, Configure: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-" + modal.name + " span").text("Saving configuration..."); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function (data) { + FnDisplayAlert({ status: "success", title: "Configuration successfully updated", description: null, breakword: false }, { name: modal.name, id: null, timeout: 4 }); + + FnConsole.log[1]("Cockpit ZFS Manager, Configure: Success"); + }) + .fail(function (message, data) { + FnDisplayAlert({ status: "danger", title: "Configuration could not be updated", description: null, breakword: false }, { name: modal.name, id: null, timeout: 4 }); + + FnConsole.warn("Cockpit ZFS Manager, Configure: Failed, Message: " + (data ? data : message)); + }) + .finally(function () { + if ((modal.welcome || !modal.welcome && zfsmanager.configuration.samba.manage) && !user.samba.manage) { + FnSambaSharesDestroyAll({ restart: false }, { silent: true }, { name: modal.name }) + .finally(function () { + FnConfigureFinally({ name: modal.name, welcome: modal.welcome }); + }); + } else if ((modal.welcome || !modal.welcome && !zfsmanager.configuration.samba.manage) && user.samba.manage) { + FnSambaSharesEnableAll({ restart: false }, { silent: false }, { name: modal.name }) + .finally(function () { + FnConfigureFinally({ name: modal.name, welcome: modal.welcome }); + }); + } else { + FnConfigureFinally({ name: modal.name, welcome: modal.welcome }); + } + }); +} + +function FnConfigureFinally(modal = { name, welcome: false }) { + $("#spinner-" + modal.name + " span").text("Reloading Cockpit ZFS Manager..."); + + setTimeout(function () { + location.reload(true); + }, 2000); +} + +function FnConfigurationDirectoryCreate() { + let process = { + command: ["/bin/sh", "-c", `[ ! -d /etc/cockpit/zfs ] || [ ! -d /etc/cockpit/zfs/shares ] || [ ! -d /etc/cockpit/zfs/snapshots ] && /bin/mkdir -p /etc/cockpit/zfs/shares /etc/cockpit/zfs/snapshots || printf "Skipped"`] + }; + + FnConsole.log[2]("Cockpit ZFS Manager, Configuration Directory, Create: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Cockpit ZFS Manager, Configuration Directory, Create:" })); + + if (data == "Skipped") { + FnConsole.log[2]("Cockpit ZFS Manager, Configuration Directory, Create: Skipped"); + } else { + FnConsole.log[1]("Cockpit ZFS Manager, Configuration Directory, Create: Success"); + } + }) + .fail(function (message, data) { + FnConsole.warn("Cockpit ZFS Manager, Configuration Directory, Create: Failed, Message: " + (data ? data : message)); + }); +} + +function FnConfigurationDirectoryRuntimeCreate() { + let process = { + command: ["/bin/sh", "-c", `[ ! -d /run/cockpit/zfs/shares ] && /bin/mkdir -p /run/cockpit/zfs/shares || printf "Skipped"`] + }; + + FnConsole.log[2]("Cockpit ZFS Manager, Runtime Configuration Directory, Create: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Cockpit ZFS Manager, Runtime Configuration Directory, Create:" })); + + if (data == "Skipped") { + FnConsole.log[2]("Cockpit ZFS Manager, Runtime Configuration Directory, Create: Skipped"); + } else { + FnConsole.log[1]("Cockpit ZFS Manager, Runtime Configuration Directory, Create: Success"); + } + }) + .fail(function (message, data) { + FnConsole.warn("Cockpit ZFS Manager, Runtime Configuration Directory, Create: Failed, Message: " + (data ? data : message)); + }); +} + +function FnConfigurationLegacyGet() { + let process = { + command: ["/bin/sh", "-c"] + }; + + FnCockpitPackagePathGet({ sosreport: false }) + .done(function (data) { + let path = data.replace(/\s +/g, "\u22C5").replace(/\/$/, "").replace(/\n/, "").split("\u22C5")[2]; + + if (!path || /\/cockpit\/zfs/.test(path) == false) { + path = "/usr/share/cockpit/zfs" + } + + process.command.push(`[ -e '` + path + `/config.json' ] && printf "true" || printf "false"`); + + FnConsole.log[2]("Cockpit ZFS Manager, Configuration, Legacy, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + cockpit.spawn(process.command, { err: "out" }) + .done(function (_data) { + FnConsole.log[4](FnConsoleVerbose({ data: _data, message: "Cockpit ZFS Manager, Configuration, Legacy, Get:" })); + + if (_data == "true") { + FnConsole.log[1]("Cockpit ZFS Manager, Configuration, Legacy, Get: Success"); + + FnModalUpdateContent({ id: $("#modal-update") }); + + $("#modal-update").modal("show"); + $("#spinner-update span").text("Relocating configuration file..."); + + FnConfigurationLegacyRelocate({ path: path }) + .done(function () { + $("#spinner-update span").text("Reloading Cockpit ZFS Manager..."); + + setTimeout(function () { + location.reload(true); + }, 2000); + }) + .fail(function () { + FnModalWelcomeContent({ id: $("#modal-welcome") }); + + $("#modal-update").modal("hide"); + $("#modal-welcome").modal("show"); + }); + } else { + FnConsole.log[2]("Cockpit ZFS Manager, Configuration, Legacy, Get: " + (_data == "false" ? "Skipped" : "Failed")); + + FnModalWelcomeContent({ id: $("#modal-welcome") }); + + $("#modal-welcome").modal("show"); + } + }) + .fail(function (_message, _data) { + FnConsole.warn("Cockpit ZFS Manager, Configuration, Legacy, Get: Failed, Message: " + (_data ? _data : _message)); + + FnModalWelcomeContent({ id: $("#modal-welcome") }); + + $("#modal-welcome").modal("show"); + }); + }) + .fail(function () { + FnModalWelcomeContent({ id: $("#modal-welcome") }); + + $("#modal-welcome").modal("show"); + }); +} + +function FnConfigurationLegacyRelocate(legacy = { path }) { + let process = { + command: ["/bin/sh", "-c", `/bin/mv -f ` + legacy.path + `/config.json /etc/cockpit/zfs/config.json`] + }; + + FnConsole.log[2]("Cockpit ZFS Manager, Configuration, Legacy, Relocate: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Cockpit ZFS Manager, Configuration, Legacy, Relocate:" })); + + FnConsole.log[1]("Cockpit ZFS Manager, Configuration, Legacy, Relocate: Success"); + }) + .fail(function (message, data) { + FnConsole.warn("Cockpit ZFS Manager, Configuration, Legacy, Relocate: Failed, Message: " + (data ? data : message)); + }); +} + +function FnUpdatesCheck(display = { alert: true }) { + FnConsole.log[2]("Cockpit ZFS Manager, Updates, Check: In Progress"); + + $.ajax({ url: "https://api.github.com/repos/optimans/cockpit-zfs-manager/releases", dataType: "json", cache: false }) + .done(function (data) { + if (data[0].name) { + if (FnUpdatesVersionCompare({ installed: zfsmanager.version, latest: data[0].name }) < 0) { + setTimeout(function () { + $("#alert-about-update").removeClass("hidden"); + $("#span-about-update-version").html(`` + data[0].name + ` ` + (data[0].prerelease === true ? `(Pre-release)` : `(Release)`) + ``); + + if (display.alert) { + FnDisplayAlert({ status: "info", title: "A new version of Cockpit ZFS Manager is now available", description: ` ` + data[0].name + ` ` + (data[0].prerelease === true ? `(Pre-release)` : `(Release)`) + ``, breakword: true }, { name: "update", id: null, timeout: 30 }); + } + }, 500); + } + + FnConsole.log[2]("Cockpit ZFS Manager, Updates, Check: Success"); + } else { + FnConsole.warn("Cockpit ZFS Manager, Updates, Check: Failed, Message: Unable to retrieve release information."); + } + }) + .fail(function (message) { + FnConsole.warn("Cockpit ZFS Manager, Updates, Check: Failed, Message: " + message); + }); +} + +function FnUpdatesVersionCompare(version = { installed, latest }) { + version.installed = version.installed.replace(/[^0-9.-]/g, "").replace(/\s+/g, "").replace(/-/g, ".").split("."); + version.latest = version.latest.replace(/[^0-9.-]/g, "").replace(/\s+/g, "").replace(/-/g, ".").split("."); + + let min = Math.min(version.installed.length, version.latest.length); + + for (let i = 0; i < min; ++i) { + version.installed[i] = parseInt(version.installed[i], 10); + version.latest[i] = parseInt(version.latest[i], 10); + + if (version.installed[i] > version.latest[i]) { + return 1; + } + if (version.installed[i] < version.latest[i]) { + return -1; + } + } + + return version.installed.length == (version.latest.length ? 0 : (version.installed.length < version.latest.length ? -1 : 1)); +} + +function FnVersionWarning() { + if (/alpha|beta|dev|internal|pre|rc/gi.test(zfsmanager.version)) { + FnDisplayAlert({ status: "warning", title: "Pre-release version of Cockpit ZFS Manager is installed", description: zfsmanager.version + ` is an unstable build and features may not work as intended`, breakword: true }, { name: "version-warning", id: null, timeout: 60 }); + } +} + +//#endregion + +//#region Cockpit + +function FnCockpitElementsDisable() { + let message = `The user ` + zfsmanager.user.name + ` is not permitted to`; + + //Disable buttons + $("#btn-configure").addClass("disabled"); + $("#btn-storagepools-filesystems-unlock").addClass("disabled"); + $("#btn-storagepools-create").prop("title", message + " create a storage pool").attr("data-placement", "auto bottom").attr("data-toggle", "tooltip").addClass("disabled"); + $("#btn-storagepools-import").prop("title", message + " import a storage pool").attr("data-placement", "auto bottom").attr("data-toggle", "tooltip").addClass("disabled"); + $("[id^=btn-storagepool-filesystems-create-]").prop("title", message + " create a file system").attr("data-placement", "auto top").attr("data-toggle", "tooltip").addClass("disabled"); + $("[id^=btn-storagepool-snapshots-create-]").prop("title", message + " create a snapshot").attr("data-placement", "auto top").attr("data-toggle", "tooltip").addClass("disabled"); + $("[id^=btn-storagepool-snapshot-dropdown-]").prop("title", message + " manage this snapshot").attr("data-placement", "auto left").attr("data-toggle", "tooltip").addClass("disabled"); + $("[id^=btn-storagepool-status-dropdown-]").prop("title", message + " manage this storage pool").attr("data-placement", "auto left").attr("data-toggle", "tooltip").addClass("disabled"); + + //Disable privileged items + $(".privileged").addClass("disabled"); + + //Disable privileged modal items + $(".privileged-modal").prop("disabled", true); + $(".privileged-modal button").prop("disabled", true); + $(".privileged-modal input").prop("disabled", true); + + //Disable sliders + $("#validationwrapper-storagepools-create-refreservation .slider-pf .slider *").addClass("disabled"); + $("#slider-storagepools-create-refreservation").slider("disable"); + $("[id^=validationwrapper-storagepool-filesystems-create-quota-] .slider-pf .slider *").addClass("disabled"); + $("[id^=slider-storagepool-filesystems-create-quota-]").slider("disable"); + $("[id^=validationwrapper-storagepool-filesystem-configure-quota-] .slider-pf .slider *").addClass("disabled"); + $("[id^=slider-storagepool-filesystem-configure-quota-]").slider("disable"); + $("[id^=validationwrapper-storagepool-filesystem-configure-refreservation-] .slider-pf .slider *").addClass("disabled"); + $("[id^=slider-storagepool-filesystem-configure-refreservation-]").slider("disable"); + + //Remove primary color from unlock file system menu item + $("[id^=btn-storagepool-filesystem-unlock-] > strong").removeClass("text-ct-locked"); + $("[id^=btn-storagepool-filesystem-unlock-icon-]").removeClass("pficon-ct-locked"); +} + +function FnCockpitElementsUpdate() { + if (!zfsmanager.user.admin) { + FnCockpitElementsDisable(); + } +} + +function FnCockpitManage() { + if (zfsmanager.user.admin) { + FnCockpitPackageSosReportDelete(); //SOS Report package will cause ZFS storage drives to appear offline when performing a diagnostic report + } +} + +function FnCockpitPackagePathGet(package = { sosreport: false }) { + let process = { + command: ["/bin/sh", "-c", `cockpit-bridge --packages | /bin/grep -m1 '/cockpit/` + (package.sosreport ? `sosreport` : `zfs`) + `$' || printf "false"`] //printf fix for Debian + }; + + FnConsole.log[2]("Cockpit, " + (package.sosreport ? "SOS Report" : "Cockpit ZFS Manager") + " Package Path, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Cockpit, " + (package.sosreport ? "SOS Report" : "Cockpit ZFS Manager") + " Package Path, Get:" })); + + let path = data.replace(/\s +/g, "\u22C5").replace(/\/$/, "").replace(/\n/, "").split("\u22C5")[2]; + + FnConsole.log[1]("Cockpit, " + (package.sosreport ? "SOS Report" : "Cockpit ZFS Manager") + " Package Path, Get: " + (path ? "Success" : "Failed")); + }) + .fail(function (message, data) { + FnConsole.warn("Cockpit, " + (package.sosreport ? "SOS Report" : "Cockpit ZFS Manager") + " Package Path, Get: Failed, Message: " + (data ? data : message)); + }); +} + +function FnCockpitPackageSosReportDelete() { + let process = { + command: ["/bin/sh", "-c"] + }; + + FnCockpitPackagePathGet({ sosreport: true }) + .done(function (data) { + let path = data.replace(/\s +/g, "\u22C5").replace(/\/$/, "").replace(/\n/, "").split("\u22C5")[2]; + + if (!path || /\/cockpit\/sosreport$/.test(path) == false) { + path = "/usr/share/cockpit/sosreport" + } + + process.command.push(`[ -e '` + path + `' ] && /bin/rm -rf ` + path + ` || printf "Skipped"`); + + FnConsole.log[2]("Cockpit, Package, SOS Report, Delete: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function (_data) { + FnConsole.log[4](FnConsoleVerbose({ data: _data, message: "Cockpit, Package, SOS Report, Delete:" })); + + if (_data == "Skipped") { + FnConsole.log[2]("Cockpit, Package, SOS Report, Delete: Skipped"); + } else { + FnConsole.log[1]("Cockpit, Package, SOS Report, Delete: Success"); + } + }) + .fail(function (_message, _data) { + FnConsole.warn("Cockpit, Package, SOS Report, Delete: Failed, Message: " + (_data ? _data : _message)); + }); }); -} - -function FnDisksIdentifierHardwarePathGet() { - let process = { - command: ["/bin/sh", "-c", `ls -lF /dev/disk/by-path | awk '{ print $9"\t"$11 }'`] - }; - - FnConsole.log[2]("Disks, Identifier, Hardware Path, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnConsole.log[2]("Disks, Identifier, Hardware Path, Get: Success"); - }) - .fail(function (message, data) { - FnConsole.warn("Disks, Identifier, Hardware Path, Get: Failed, Message: " + (data ? data : message)); +} + +function FnCockpitPermissionsGet() { + FnConsole.log[2]("Cockpit, Permissions, Get: In Progress"); + + zfsmanager.cockpit.permission = cockpit.permission({ admin: true }); + + $(zfsmanager.cockpit.permission).on("changed", function () { + zfsmanager.user.admin = zfsmanager.cockpit.permission.allowed; + zfsmanager.user.name = (zfsmanager.cockpit.permission.user ? zfsmanager.cockpit.permission.user.name : ""); + + if (zfsmanager.user.admin) { + FnConsole.log[2]("Cockpit, Permissions, Get: Success"); + + FnFirstStepsPrivileged(); + } else { + FnConsole.warn("Cockpit, Permissions, Get: Warning, Message: " + zfsmanager.user.name + " does not have administrator permissions"); + + FnCockpitElementsDisable(); + } + }); +} + +//#endregion + +//#region ZFS + +function FnZfsVersionCompare(version = { installed, threshold }) { + version.installed = version.installed.replace(/[^0-9.-]/g, "").replace(/\s+/g, "").replace(/-/g, ".").split("."); + version.threshold = version.threshold.replace(/\s+/g, "").replace(/-/g, ".").split("."); + + if (!version.installed[0]) { + return -1; + } + + let min = Math.min(version.installed.length, version.threshold.length); + + for (let i = 0; i < min; ++i) { + version.installed[i] = parseInt(version.installed[i], 10); + version.threshold[i] = parseInt(version.threshold[i], 10); + + if (version.installed[i] > version.threshold[i]) { + return 1; + } + if (version.installed[i] < version.threshold[i]) { + return -1; + } + } + + return version.installed.length == (version.threshold.length ? 0 : (version.installed.length < version.threshold.length ? -1 : 1)); +} + +function FnZfsVersionGet() { + let process = { + command: ["/bin/cat", "/sys/module/zfs/version"] + }; + let zfs = { + success: false, + threshold: "0.8" + }; + + FnConsole.log[2]("ZFS, Version, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data, message) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "ZFS, Version, Get:" })); + + if (data) { + zfsmanager.zfs.version = data.replace(/\s+/g, ""); + } + + if (!data || FnZfsVersionCompare({ installed: zfsmanager.zfs.version, threshold: zfs.threshold }) < 0) { + FnConsole.error("ZFS, Version, Get: Failed, Message: Version " + (zfsmanager.zfs.version ? zfsmanager.zfs.version : "0") + " < " + zfs.threshold); + } else { + zfs.success = true; + + FnConsole.log[1]("ZFS, Version, Get: Success, Version: " + (data ? data : message)); + } + }) + .fail(function (message, data) { + FnConsole.error("ZFS, Version, Get: Failed, Message: " + (data ? data : message)); + }) + .finally(function () { + if (!zfs.success) { + zfs.message = ` +
    + +
    +

    This package requires ZFS version ` + zfs.threshold + ` or later

    +

    If ZFS is installed, check the module is loaded into the kernel.

    +
    + +
    + `; + + $("#alerts-requirements").removeClass("hidden").html(zfs.message); + $("#container").addClass("hidden"); + } else { + if (!zfsmanager.configuration.samba.manage) { + $("#alerts-requirements").empty().addClass("hidden"); + $("#container").removeClass("hidden"); + } + } }); -} - -function FnDisksIdentifierVirtualDeviceMappingGet() { - let process = { - command: ["/bin/sh", "-c", `[ -d /dev/disk/by-vdev ] && ls -lF /dev/disk/by-vdev | awk '{ print $9"\t"$11 }' || printf ""`] - }; - - FnConsole.log[2]("Disks, Identifier, Virtual Device Mapping, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnConsole.log[2]("Disks, Identifier, Virtual Device Mapping, Get: Success"); - }) - .fail(function (message, data) { - FnConsole.warn("Disks, Identifier, Virtual Device Mapping, Get: Failed, Message: " + (data ? data : message)); +} + +function FnZfsVersionWarnings() { + zfsmanager.zfs.warnings.nvmevdev = (FnZfsVersionCompare({ installed: zfsmanager.zfs.version, threshold: "0.8.3" }) < 0 ? true : false); //GitHub Issue #9730 +} + +//#endregion + +//#region Storage Pools + +function FnStoragePoolsGet() { + let process = { + command: ["/sbin/zpool", "list", "-H", "-o", "name,guid,health,size,alloc,free,fragmentation,readonly,altroot,autotrim,version,feature@allocation_classes,feature@async_destroy,feature@bookmark_v2,feature@bookmarks,feature@device_removal,feature@edonr,feature@embedded_data,feature@empty_bpobj,feature@enabled_txg,feature@encryption,feature@extensible_dataset,feature@filesystem_limits,feature@hole_birth,feature@large_blocks,feature@large_dnode,feature@lz4_compress,feature@multi_vdev_crash_dump,feature@obsolete_counts,feature@project_quota,feature@resilver_defer,feature@sha512,feature@skein,feature@spacemap_histogram,feature@spacemap_v2,feature@userobj_accounting,feature@zpool_checkpoint", "-p"] + }; + let pools = { + empty: true + }; + + //Disable storage pool status auto refresh + zfsmanager.zfs.storagepool.refreshid.forEach((_value, _index) => { + clearInterval(_value); + }); + zfsmanager.zfs.storagepool.refreshid = []; + + $("#btn-storagepools-refresh").prop("disabled", true); + $("#table-storagepools > tbody").remove(); + $("[id^=modals-storagepool-]").remove(); + $("[id^=dynamics-storagepool-]").remove(); + $("#spinner-storagepools").removeClass("hidden"); + + FnConsole.log[2]("Storage Pools, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + FnStoragePoolsSystemReservedGet() + .finally(function () { + cockpit.spawn(process.command, { err: "out" }) + .done((data, message) => { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Storage Pools, Get:" })); + + if (data) { + pools.empty = false; + + FnStoragePoolsGetCommand({ data: data, message: message }); + } + + FnConsole.log[1]("Storage Pools, Get: Success"); + }) + .fail((message, data) => { + FnConsole.warn("Storage Pools, Get: Failed, Message: " + (data ? data : message)); + }) + .finally(function () { + if ($("#table-storagepools > tbody").length == 0) { + pools.empty = true; + } + + if (pools.empty) { + $("#table-storagepools").append(`No storage pools found.`); + } + + setTimeout(function () { + $("#spinner-storagepools").addClass("hidden"); + $("#table-storagepools > tbody").removeClass("hidden"); + }, 200); + + $("#btn-storagepools-refresh").prop("disabled", false); + + FnCockpitElementsUpdate(); + }); }); -} - -function FnDisksLsblkGet(disks = { sizeraw: true }) { - let process = { - command: ["/bin/sh", "-c", "/bin/lsblk -o label,model,mountpoint,name,partuuid,phy-sec,rota,serial,size,type,uuid,vendor,wwn -J" + (disks.sizeraw ? " -b" : "")] - }; - - FnConsole.log[2]("Disks, Lsblk, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function () { - FnConsole.log[2]("Disks, Lsblk, Get: Success"); - }) - .fail(function (message, data) { - FnConsole.warn("Disks, Lsblk, Get: Failed, Message: " + (data ? data : message)); - }); -} - -function FnDisksStoragePoolsAttachedGet(pool = { name, id }, disks = { id: { blockdevice: true } }) { - let process = { - command: ["/bin/sh", "-c", ((zfsmanager.user.name == "root" || !zfsmanager.user.name) ? "ZPOOL_SCRIPTS_AS_ROOT=1 " : "") + "/sbin/zpool status -P " + (disks.id.blockdevice ? "-L " : "") + "-c upath" + (pool.name ? ` "` + pool.name + `"` : "")] - }; - - FnConsole.log[2]("Disks, Storage Pools, Attached, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function () { - FnConsole.log[2]("Disks, Storage Pools, Attached, Get: Success"); - }) - .fail(function (message, data) { - FnConsole.warn("Disks, Storage Pools, Attached, Get: Failed, Message: " + (data ? data : message)); - }); -} - -function FnDisksStoragePoolsImportableAttachedGet() { - let process = { - command: ["/sbin/zpool", "import", "-d", "/dev"] - }; - - FnConsole.log[2]("Disks, Storage Pools, Importable, Attached, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnConsole.log[2]("Disks, Storage Pools, Importable, Attached, Get: Success"); - }) - .fail(function (message, data) { - FnConsole.warn("Disks, Storage Pools, Importable, Attached, Get: Failed, Message: " + (data ? data : message)); - }); -} - -function FnDisksStoragePoolsImportableGet() { - let process = { - command: ["/bin/sh", "-c", "/sbin/zpool import | /bin/grep -E 'pool:\| id:' | tr '\\\n' ','"] - }; - - FnConsole.log[2]("Disks, Importable Storage Pools, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnConsole.log[2]("Disks, Importable Storage Pools, Get: Success"); - }) - .fail(function (message, data) { - if (/no pools available to import/gi.test(data) == false) { - FnConsole.warn("Disks, Importable Storage Pools, Get: Failed, Message: " + (data ? data : message)); - } - }); -} - -//#endregion - -//#region Samba - -function FnSambaConfigurationReload() { - let process = { - command: ["/usr/bin/smbcontrol", "all", "reload-config"] - }; - - FnConsole.log[2]("Samba, Configuration, Reload: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnConsole.log[1]("Samba, Configuration, Reload: Success"); - }) - .fail(function (message, data) { - FnConsole.warn("Samba, Configuration, Reload: Failed, Message: " + (data ? data : message)); - }); -} - -function FnSambaConfigurationZfsSharesEnable() { - let process = { - command: ["/bin/sh", "-c", `[ -s /etc/samba/smb.conf ] && /usr/bin/awk -v k='\n\t# COCKPIT ZFS MANAGER\n\t# WARNING: DO NOT EDIT, AUTO-GENERATED CONFIGURATION\n\tinclude = /etc/cockpit/zfs/shares.conf\n\tinclude = /run/cockpit/zfs/shares.conf\n' '($1=="[global]"||x&&/^\\[/)&&!(x=!x){print k} END{if(x)print k}1' /etc/samba/smb.conf > /etc/samba/smb.tmp && /bin/mv -f /etc/samba/smb.tmp /etc/samba/smb.conf \|\| { echo '/etc/samba/smb.conf file does not exist or is empty.' ; exit 1; }`] - }; - - FnConsole.log[2]("Samba, Configuration, ZFS Shares, Enable: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnConsole.log[1]("Samba, Configuration, ZFS Shares, Enable: Success"); - - FnSambaConfigurationReload(); - }) - .fail(function (message, data) { - FnConsole.warn("Samba, Configuration, ZFS Shares, Enable: Failed, Message: " + (data ? data : message)); - }); -} - -function FnSambaConfigurationZfsSharesGet() { - let process = { - command: ["/bin/sh", "-c", "/bin/grep -Pzoq '(?s)include = /etc/cockpit/zfs/shares.conf.*/run/cockpit/zfs/shares.conf' /etc/samba/smb.conf && echo true || echo false"] - }; - - FnConsole.log[2]("Samba, Configuration, ZFS Shares, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data, message) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Configuration, ZFS Shares, Get:" })); - - data = data.replace(/\n+/g, ""); - - if (data == "false") { - FnSambaConfigurationZfsSharesEnable(); - } else if (data == "true") { - FnConsole.log[2]("Samba, Configuration, ZFS Shares, Get: Success"); - } else { - FnConsole.warn("Samba, Configuration, ZFS Shares, Get: Failed, Message: " + (data ? data : message)); - } - }) - .fail(function (message, data) { - FnConsole.warn("Samba, Configuration, ZFS Shares, Get: Failed, Message: " + (data ? data : message)); - }); -} - -function FnSambaManage() { - if (zfsmanager.user.admin) { - FnSambaConfigurationZfsSharesGet(); - } -} - -function FnSambaRestart() { - let process = { - command: ["/bin/systemctl", "restart"] - }; - - if (/Debian|Ubuntu/i.test(zfsmanager.system.operatingsystem)) { - process.command.splice(2, 0, "smbd"); - } else { - process.command.splice(2, 0, "smb"); - } - - FnConsole.log[2]("Samba, Restart: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnConsole.log[1]("Samba, Restart: Success"); - }) - .fail(function (message, data) { - FnConsole.warn("Samba, Restart: Failed, Message: " + (data ? data : message)); - }); -} - -function FnSambaShareDestroy(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id }, samba = { restart: false }, display = { silent: false }) { - let process = { - promise: cockpit.defer() - }; - - FnSambaZfsShareDisable({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id }) - .done(function () { - FnSambaZfsSharesConfigurationReload() - .done(function () { - setTimeout(function () { - if (samba.restart) { - FnSambaRestart() - .finally(function () { - if (!display.silent) { - FnDisplayAlert({ status: "success", title: "Samba share successfully destroyed", description: filesystem.name, breakword: false }, { name: "samba-destroy", id: filesystem.id, timeout: 4 }); - } - - FnConsole.log[1]("Samba, Share, Destroy: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - - process.promise.resolve(); - }); - } else { - FnSambaConfigurationReload() - .finally(function () { - if (!display.silent) { - FnDisplayAlert({ status: "success", title: "Samba share successfully destroyed", description: filesystem.name, breakword: false }, { name: "samba-destroy", id: filesystem.id, timeout: 4 }); - } - - FnConsole.log[1]("Samba, Share, Destroy: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - - process.promise.resolve(); - }); - } - }, 500); - }) - }) - .fail(function () { - process.promise.resolve(); - }); - - return process.promise.promise(); -} - -function FnSambaShareDisable(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id }, samba = { restart: false }, display = { modal: true, silent: false }) { - if (display.modal) { - $("#spinner-storagepool-filesystem-samba-disable-" + filesystem.id + " span").text("Disabling Samba share..."); - } - - if (!pool.readonly) { - FnFileSystemShareSmbDisable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }) - .done(function () { - FnSambaShareDisableCommand({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id }, { restart: samba.restart }, { modal: display.modal, silent: display.silent }); - }) - .fail(function (message, data) { - if (/property may be set/gi.test(data)) { //False error is generated when configuring filesystem - FnSambaShareDisableCommand({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id }, { restart: samba.restart }, { modal: display.modal, silent: display.silent }); - } else { - if (!display.silent) { - FnDisplayAlert({ status: "danger", title: "Samba share could not be disabled", description: filesystem.name, breakword: false }, { name: "samba-disable", id: filesystem.id, timeout: 4 }); - } - - if (display.modal) { - $("#modal-storagepool-filesystem-samba-disable-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: false, status: false }); - }, 200); - } - } - }); - } else { - FnSambaShareDisableCommand({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id }, { restart: samba.restart }, { modal: display.modal, silent: display.silent }); - } -} - -function FnSambaShareDisableCommand(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id }, samba = { restart: false }, display = { modal: true, silent: false }) { - FnSambaZfsShareDisable({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id }) - .done(function () { - FnSambaZfsSharesConfigurationReload() - .done(function () { - setTimeout(function () { - if (samba.restart) { - FnSambaRestart() - .finally(function () { - if (!display.silent) { - FnDisplayAlert({ status: "success", title: "Samba share successfully disabled", description: filesystem.name, breakword: false }, { name: "samba-disable", id: filesystem.id, timeout: 4 }); - } - - if (display.modal) { - $("#modal-storagepool-filesystem-samba-disable-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: false, status: false }); - }, 200); - } - }); - } else { - FnSambaConfigurationReload() - .finally(function () { - if (!display.silent) { - FnDisplayAlert({ status: "success", title: "Samba share successfully disabled", description: filesystem.name, breakword: false }, { name: "samba-diable", id: filesystem.id, timeout: 4 }); - } - - if (display.modal) { - $("#modal-storagepool-filesystem-samba-disable-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: false, status: false }); - }, 200); - } - }); - } - }, 500); - }) - .fail(function () { - FnFileSystemShareSmbEnable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }); - }); - }) - .fail(function () { - FnFileSystemShareSmbEnable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }); - }); -} - -function FnSambaShareEnable(pool = { name, id, readonly: false }, filesystem = { name, id, mounted: false, mountpoint }, samba = { share: { additional: [], administrative: false, browseable: true, guestok: false, name, comment, readonly: false, temporary: false } }, display = { silent: false }) { - let modal = { - hide: true - }; - - $("#spinner-storagepool-filesystem-samba-enable-" + filesystem.id + " span").text("Enabling Samba share..."); - - FnSambaShareNamesGet({ zfsonly: false }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Share, Names, Get:" })); - - samba.share.nameunique = true; - samba.share.errormessage = "Share name is already in use."; - - if (data.replace(/\n/g, "") != "$empty") { //$empty response is received if share names list is empty - samba.shares = data.split(/\n/g).filter(v => v); - - samba.shares.forEach((_value, _index) => { - if (_value.replace(/^\[/, "").replace(/\]$/, "").toLowerCase() == samba.share.name.toLowerCase() + (samba.share.administrative ? "$" : "")) { - samba.share.nameunique = false; - - return; - } - }); - } - - if (/^global$|^homes$|^printers$/gi.test(samba.share.name)) { - samba.share.nameunique = false; - samba.share.errormessage = "Share name can not be a restricted name."; - } - - if (!samba.share.nameunique) { - modal.hide = false; - - $("#validationwrapper-storagepool-filesystem-samba-enable-name-" + filesystem.id).addClass("has-error"); - $("#helpblock-storagepool-filesystem-samba-enable-name-" + filesystem.id).addClass("has-error").removeClass("hidden").text(samba.share.errormessage); - $("#input-storagepool-filesystem-samba-enable-name-" + filesystem.id).focus(); - - if (!modal.hide) { - $("#spinner-storagepool-filesystem-samba-enable-" + filesystem.id).addClass("hidden"); - $("#spinner-storagepool-filesystem-samba-enable-" + filesystem.id + " span").text(""); - $("#btn-storagepool-filesystem-samba-enable-apply-" + filesystem.id).prop("disabled", false); - - FnConsole.warn("Samba, Share, Enable: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + samba.share.errormessage); - } - } else { - FnSambaShareEnableCommand({ name: pool.name, id: pool.id, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, force: false, mounted: filesystem.mounted, mountpoint: filesystem.mountpoint, sharesmb: false }, { reload: true, share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary } }, { refresh: true, silent: display.silent }); - - $("#modal-storagepool-filesystem-samba-enable-" + filesystem.id).modal("hide"); - } - }); -} - -function FnSambaShareEnableAutoGenerateName(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, force: false, mounted: false, mountpoint, sharesmb: false }, samba = { reload: true }, display = { refresh: true, silent: false }) { - FnSambaShareNamesGet({ zfsonly: false }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Share, Names, Get:" })); - - samba.share = { - name: "", - nameunique: true, - temporary: (pool.altroot || pool.readonly ? true : false) - };; - - if (data.replace(/\n/g, "") != "$empty") { //$empty response is received if share names list is empty - samba.shares = data.split(/\n/g).filter(v => v); - - samba.shares.forEach((_value, _index) => { - if (_value.replace(/^\[/, "").replace(/\]$/, "").toLowerCase() == filesystem.name.replace(/^.*\/(.*)$/, "$1").toLowerCase()) { - samba.share.nameunique = false; - - return; - } - }); - } - - if (/^global$|^homes$|^printers$/gi.test(samba.share.name)) { - samba.share.nameunique = false; - } - - if (!samba.share.nameunique) { - samba.share.name = FnGenerateShareName({ at: false, colon: false, period: false, whitespace: false }, { name: filesystem.name }); - - if (filesystem.name == pool.name) { - samba.share.name = "StoragePool-" + samba.share.name; - } - - FnSambaShareEnableCommand({ name: pool.name, id: pool.id, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, force: false, mounted: filesystem.mounted, mountpoint: filesystem.mountpoint, sharesmb: filesystem.sharesmb }, { reload: samba.reload, share: { additional: [], administrative: false, browseable: true, guestok: false, name: samba.share.name, comment: null, readonly: null, temporary: samba.share.temporary } }, { refresh: display.refresh, silent: display.silent }); - } else { - FnSambaShareEnableCommand({ name: pool.name, id: pool.id, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, force: false, mounted: filesystem.mounted, mountpoint: filesystem.mountpoint, sharesmb: filesystem.sharesmb }, { reload: samba.reload, share: { additional: [], administrative: false, browseable: true, guestok: false, name: null, comment: null, readonly: null, temporary: samba.share.temporary } }, { refresh: display.refresh, silent: display.silent }); - } - }); -} - -function FnSambaShareEnableCommand(pool = { name, id, readonly: false }, filesystem = { name, force: false, id, mounted: false, mountpoint, sharesmb: false }, samba = { reload: true, share: { additional: [], administrative: false, browseable: true, guestok: false, name, comment, readonly: false, temporary: false } }, display = { refresh: true, silent: false }) { - if (!pool.readonly && (!filesystem.sharesmb || filesystem.sharesmb && filesystem.force)) { //Force to disable inheritance - FnFileSystemShareSmbEnable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }) - .done(function () { - FnSambaShareEnableCommandFinally({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, mounted: filesystem.mounted, mountpoint: filesystem.mountpoint }, { reload: samba.reload, share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary } }, { refresh: display.refresh, silent: display.silent }); - }) - .fail(function (message, data) { - if (/property may be set/gi.test(data)) { //False error is generated when configuring filesystem - FnSambaShareEnableCommandFinally({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, mounted: filesystem.mounted, mountpoint: filesystem.mountpoint }, { share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary } }, { refresh: display.refresh, silent: display.silent }); - } else { - if (!display.silent) { - FnDisplayAlert({ status: "danger", title: "Samba share could not be enabled", description: filesystem.name, breakword: false }, { name: "samba-enable", id: filesystem.id, timeout: 4 }); - } - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: false, status: false }); - }, 200); - } - }); - } else { - FnSambaShareEnableCommandFinally({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, mounted: filesystem.mounted, mountpoint: filesystem.mountpoint }, { reload: samba.reload, share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary } }, { refresh: display.refresh, silent: display.silent }); - } -} - -function FnSambaShareEnableCommandFinally(pool = { name, id }, filesystem = { name, id, mounted: false, mountpoint }, samba = { reload: true, share: { additional: [], administrative: false, browseable: true, guestok: false, name, comment, readonly: false, temporary: false } }, display = { refresh: true, silent: false }) { - FnSambaZfsShareEnable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, mountpoint: filesystem.mountpoint }, { share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary } }) - .done(function () { - if (!display.silent) { - FnDisplayAlert({ status: "success", title: "Samba share successfully enabled", description: filesystem.name, breakword: false }, { name: "samba-enable", id: filesystem.id, timeout: 4 }); - } - - if (samba.reload) { - FnSambaZfsSharesConfigurationReload() - .done(function () { - setTimeout(function () { - FnSambaConfigurationReload() - .finally(function () { - if (display.refresh) { - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: false, status: false }); - }, 200); - } - }); - }, 500); - }) - .fail(function () { - FnFileSystemShareSmbDisable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }); - }); - } else { - if (display.refresh) { - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: false, status: false }); - }, 200); - } - } - }) - .fail(function () { - FnFileSystemShareSmbDisable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }); - }); -} - -function FnSambaShareEnableMountpointGet(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, sharesmb: false }, display = { silent: false }) { - let process = { - command: ["/sbin/zfs", "list", "-H", "-o", "mounted,mountpoint", "-t", "filesystem", filesystem.name] - }; - - FnConsole.log[2]("File Systems, Mountpoint, Get: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data, message) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Mountpoint, Get:" })); - - data = data.replace(/\n/g, "").replace(/\t/g, "\u22C5").split("\u22C5"); - - filesystem.mounted = data[0]; - filesystem.mountpoint = data[1]; - - if (/^\//.test(filesystem.mountpoint)) { - FnConsole.log[1]("File Systems, Mountpoint, Get: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - - FnSambaShareEnableAutoGenerateName({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, force: false, mounted: filesystem.mounted, mountpoint: filesystem.mountpoint, sharesmb: filesystem.sharesmb }, { reload: true }, { refresh: true, silent: display.silent }); - } else { - FnConsole.warn("File Systems, Mountpoint, Get: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); - } - }) - .fail(function (message, data) { - FnConsole.warn("File Systems, Mountpoint, Get: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); - - FnFileSystemShareSmbDisable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }); - }); -} - -function FnSambaShareNamesGet(samba = { zfsonly: false }) { - let process = { - command: ["/bin/sh", "-c", `/bin/cat /etc/cockpit/zfs/shares/*.conf /run/cockpit/zfs/shares/*.conf ` + (!samba.zfsonly ? `/etc/samba/smb.conf ` : ``) + `2> /dev/null | /bin/grep "^\\\[.*\\\]$" || echo \\\$empty`] - }; - - FnConsole.log[2]("Samba, Share, Names, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function () { - FnConsole.log[1]("Samba, Share, Names, Get: Success"); - }) - .fail(function (message, data) { - FnConsole.warn("Samba, Share, Names, Get: Failed, Message: " + (data ? data : message)); - }); -} - -function FnSambaSharesDestroy(pool = { name, id, altroot: false, readonly: false }, filesystems = { id: [] }, samba = { restart: false }, display = { silent: true }) { - let process = { - promise: cockpit.defer() - }; - let promise = Promise.resolve(); - - FnConsole.log[1]("Samba, Shares, Destroy: In Progress, Pool: " + pool.name); - - if (filesystems.id.length > 0) { - filesystems.id.forEach((_value, _index) => { - let filesystem = { - properties: _value.split(/\t/g).filter(v => v) - }; - - filesystem.name = filesystem.properties[0]; - filesystem.id = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: filesystem.properties[0], attribute: true }); - filesystem.mounted = filesystem.properties[1]; - filesystem.mountpoint = filesystem.properties[2]; - filesystem.sharesmb = filesystem.properties[3]; - - promise = promise.then(_ => new Promise(resolve => - setTimeout(function () { - if (_index <= (filesystems.id.length - 1)) { - if (filesystem.sharesmb == "on") { - FnSambaZfsShareDisable({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id }); - } - } - - if (_index == (filesystems.id.length - 1)) { - setTimeout(function () { - if (!display.silent) { - FnDisplayAlert({ status: "success", title: "Samba shares successfully destroyed", description: pool.name, breakword: false }, { name: "samba-destroy", id: pool.id, timeout: 4 }); - } - - FnConsole.log[1]("Samba, Shares, Destroy: Success, Pool: " + pool.name); - - FnSambaZfsSharesConfigurationReload() - .done(function () { - setTimeout(function () { - if (samba.restart) { - FnSambaRestart() - .finally(function () { - process.promise.resolve(); - }); - } else { - FnSambaConfigurationReload() - .finally(function () { - process.promise.resolve(); - }); - } - }, 300); - }); - }, 500); - } - - resolve(); - }, 500) - )); - }); - } else { - if (!display.silent) { - FnDisplayAlert({ status: "success", title: "Samba shares successfully destroyed", description: pool.name, breakword: false }, { name: "samba-destroy", id: pool.id, timeout: 4 }); - } - - FnConsole.log[1]("Samba, Shares, Destroy: Success, Pool: " + pool.name); - - process.promise.resolve(); - } - - return process.promise.promise(); -} - -function FnSambaSharesDestroyAll(samba = { restart: false }, display = { silent: false }, modal = { name }) { - let process = { - command: ["/bin/sh", "-c", "echo '# COCKPIT ZFS MANAGER\n# WARNING: DO NOT EDIT, AUTO-GENERATED CONFIGURATION' > /etc/cockpit/zfs/shares.conf && echo '# COCKPIT ZFS MANAGER\n# WARNING: DO NOT EDIT, AUTO-GENERATED CONFIGURATION' > /run/cockpit/zfs/shares.conf && /bin/rm -rf /etc/cockpit/zfs/shares/*.conf && /bin/rm -rf /run/cockpit/zfs/shares/*.conf"], - promise: cockpit.defer() - }; - - FnConsole.log[1]("Samba, Shares, Destroy All: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - $("#spinner-" + modal.name + " span").text("Destroying Samba shares..."); - - cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - if (!display.silent) { - FnDisplayAlert({ status: "success", title: "Samba shares successfully destroyed", description: null, breakword: false }, { name: "samba-destroy-all", id: null, timeout: 4 }); - } - - FnConsole.log[1]("Samba, Shares, Destroy All: Success"); - - if (samba.restart) { - FnSambaRestart() - .finally(function () { - process.promise.resolve(); - }); - } else { - FnSambaConfigurationReload() - .finally(function () { - process.promise.resolve(); - }); - } - }) - .fail(function (message, data) { - if (!display.silent) { - FnDisplayAlert({ status: "danger", title: "Samba shares could not be destroyed", description: null, breakword: false }, { name: "samba-destroy-all", id: null, timeout: 4 }); - } - - FnConsole.warn("Samba, Shares, Destroy All: Failed, Message: " + (data ? data : message)); - - process.promise.resolve(); - }); - - return process.promise.promise(); -} - -function FnSambaSharesEnable(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, force: false }, samba = { restart: false }, display = { refresh: false, silent: true }) { - let process = { - command: ["/sbin/zfs", "list", "-H", "-o", "name,mounted,mountpoint,sharesmb", "-r", "-t", "filesystem"], - promise: cockpit.defer() - }; - - if (filesystem.name) { - process.command.push(filesystem.name); - } else { - process.command.push(pool.name); - } - - FnConsole.log[1]("Samba, Shares, Enable: In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Shares, Enable:" })); - - let filesystems = { - id: data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) - }; - let promise = Promise.resolve(); - - if (filesystems.id.length > 0) { - filesystems.id.forEach((_value, _index) => { - let filesystem = { - properties: _value.split(/\t/g).filter(v => v) - }; - - filesystem.name = filesystem.properties[0]; - filesystem.id = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: filesystem.properties[0], attribute: true }); - filesystem.mounted = filesystem.properties[1]; - filesystem.mountpoint = filesystem.properties[2]; - filesystem.sharesmb = filesystem.properties[3]; - - promise = promise.then(_ => new Promise(resolve => - setTimeout(function () { - if (_index <= (filesystems.id.length - 1)) { - if (filesystem.sharesmb == "on") { - FnSambaShareEnableAutoGenerateName({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, force: filesystem.force, mounted: filesystem.mounted, mountpoint: filesystem.mountpoint, sharesmb: true }, { reload: false }, { refresh: false, silent: true }); - } - } - - if (_index == (filesystems.id.length - 1)) { - setTimeout(function () { - if (!display.silent) { - FnDisplayAlert({ status: "success", title: "Samba shares successfully enabled", description: pool.name, breakword: false }, { name: "samba-enable", id: pool.id, timeout: 4 }); - } - - FnConsole.log[1]("Samba, Shares, Enable: Success, Pool: " + pool.name); - - FnSambaZfsSharesConfigurationReload() - .done(function () { - setTimeout(function () { - if (samba.restart) { - FnSambaRestart() - .finally(function () { - if (display.refresh) { - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 500); - } - - process.promise.resolve(); - }); - } else { - FnSambaConfigurationReload() - .finally(function () { - if (display.refresh) { - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 500); - } - - process.promise.resolve(); - }); - } - }, 300); - }); - }, 500); - } - - resolve(); - }, 500) - )); - }); - } else { - if (!display.silent) { - FnDisplayAlert({ status: "success", title: "Samba shares successfully enabled", description: pool.name, breakword: false }, { name: "samba-enable", id: pool.id, timeout: 4 }); - } - - FnConsole.log[1]("Samba, Shares, Enable: Success, Pool: " + pool.name); - - process.promise.resolve(); - } - }) - .fail(function (message, data) { - if (!display.silent) { - FnDisplayAlert({ status: "danger", title: "Samba shares could not enabled", description: pool.name, breakword: false }, { name: "samba-enable", id: pool.id, timeout: 4 }); - } - - FnConsole.warn("Samba, Shares, Enable: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); - - if (display.refresh) { - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 500); - } - - process.promise.resolve(); - }); - - return process.promise.promise(); -} - -function FnSambaSharesEnableAll(samba = { restart: false }, display = { silent: false }, modal = { name }) { - let process = { - command: ["/sbin/zfs", "list", "-H", "-o", "name,mounted,mountpoint,sharesmb", "-r", "-t", "filesystem"], - promise: cockpit.defer() - }; - - FnConsole.log[1]("Samba, Shares, Enable All: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - FnStoragePoolsTemporaryGet() - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Storage Pools, Temporary, Get:" })); - - $("#spinner-" + modal.name + " span").text("Disabling Samba share inheritance..."); - - FnFileSystemShareSmbInheritedDisable({ name: null, id: null, altroot: null }, { name: null }, { disable: false }) - .finally(function () { - $("#spinner-" + modal.name + " span").text("Creating Samba shares..."); - - cockpit.spawn(process.command, { err: "out" }) - .done(function (_data) { - FnConsole.log[4](FnConsoleVerbose({ data: _data, message: "Samba, Shares, Enable All:" })); - - let filesystems = { - id: _data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) - }; - let promise = Promise.resolve(); - - if (filesystems.id.length > 0) { - filesystems.id.forEach((_value, _index) => { - let filesystem = { - properties: _value.split(/\t/g).filter(v => v) - }; - let pool = { - name: filesystem.properties[0].replace(/\/.*$/, ""), - id: FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: filesystem.properties[0].replace(/\/.*$/, ""), attribute: true }) - }; - - filesystem.name = filesystem.properties[0]; - filesystem.id = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: filesystem.properties[0], attribute: true }); - filesystem.mounted = filesystem.properties[1]; - filesystem.mountpoint = filesystem.properties[2]; - filesystem.sharesmb = filesystem.properties[3]; - - promise = promise.then(_ => new Promise(resolve => - setTimeout(function () { - if (_index <= (filesystems.id.length - 1)) { - if (filesystem.sharesmb == "on") { - - pool.properties = data.split(/\n/g).filter(v => v && new RegExp("^" + pool.name + "\t").test(v))[0].split(/\t/g).filter(v => v); - - if (pool.properties[0] == pool.name) { - pool.altroot = (pool.properties[2] && pool.properties[2] != "-" ? true : false); - pool.readonly = (pool.properties[1].toLowerCase() == "on" ? true : false); - - FnSambaShareEnableAutoGenerateName({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, force: false, mounted: filesystem.mounted, mountpoint: filesystem.mountpoint, sharesmb: true }, { reload: false }, { refresh: false, silent: true }); - } - } - } - - if (_index == (filesystems.id.length - 1)) { - setTimeout(function () { - if (!display.silent) { - FnDisplayAlert({ status: "success", title: "Samba shares successfully enabled", description: null, breakword: false }, { name: "samba-enable-all", id: null, timeout: 4 }); - } - - FnConsole.log[1]("Samba, Shares, Enable All: Success"); - - FnSambaZfsSharesConfigurationReload() - .done(function () { - setTimeout(function () { - if (samba.restart) { - FnSambaRestart() - .finally(function () { - process.promise.resolve(); - }); - } else { - FnSambaConfigurationReload() - .finally(function () { - process.promise.resolve(); - }); - } - }, 300); - }); - }, 500); - } - - resolve(); - }, 500) - )); - }); - } else { - if (!display.silent) { - FnDisplayAlert({ status: "success", title: "Samba shares successfully enabled", description: null, breakword: false }, { name: "samba-enable-all", id: null, timeout: 4 }); - } - - FnConsole.log[1]("Samba, Shares, Enable All: Success"); - - process.promise.resolve(); - } - }) - .fail(function (message, data) { - if (!display.silent) { - FnDisplayAlert({ status: "danger", title: "Samba shares could not be enabled", description: null, breakword: false }, { name: "samba-enable-all", id: null, timeout: 4 }); - } - - FnConsole.warn("Samba, Shares, Enable All: Failed, Message: " + (data ? data : message)); - - process.promise.resolve(); - }); - }); - }) - .fail(function (message, data) { - if (!display.silent) { - FnDisplayAlert({ status: "danger", title: "Samba shares could not be enabled", description: null, breakword: false }, { name: "samba-enable-all", id: null, timeout: 4 }); - } - - FnConsole.warn("Samba, Shares, Enable All: Failed, Message: " + (data ? data : message)); - - process.promise.resolve(); - }); - - return process.promise.promise(); -} - -function FnSambaSharesGet(pool = { name, id }, filesystem = { name, clones: [] }) { - let process = { - command: ["/sbin/zfs", "list", "-H", "-o", "name,mounted,mountpoint,sharesmb", "-r", "-t", "filesystem"] - }; - - if (filesystem.name) { - process.command.push(filesystem.name); - } else if (filesystem.clones.length > 0) { - filesystem.clones.forEach(_value => _value && process.command.push(_value)); - } else { - process.command.push(pool.name); - } - - FnConsole.log[2]("Samba, Shares, Get: In Progress, Pool: " + pool.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function () { - FnConsole.log[1]("Samba, Shares, Get: Success, Pool: " + pool.name); - }) - .fail(function (message, data) { - FnConsole.warn("Samba, Shares, Get: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); - }); -} - -function FnSambaSharesRename(pool = { name, id, altroot: false, readonly: false }, filesystems = { id: [], parent: { name, namenew } }, samba = { restart: false }, display = { silent: true }) { - let process = { - promise: cockpit.defer() - }; - let promise = Promise.resolve(); - - FnConsole.log[1]("Samba, Shares, Rename: In Progress, Pool: " + pool.name); - - if (filesystems.id.length > 0) { - filesystems.id.forEach((_value, _index) => { - let filesystem = { - properties: _value.split(/\t/g).filter(v => v) - }; - - filesystem.name = filesystem.properties[0]; - filesystem.id = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: filesystem.properties[0], attribute: true }); - filesystem.mounted = filesystem.properties[1]; - filesystem.mountpoint = filesystem.properties[2]; - filesystem.sharesmb = filesystem.properties[3]; - - filesystem.namenew = filesystem.name.replace(new RegExp("^" + filesystems.parent.name), filesystems.parent.namenew); - filesystem.idnew = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: filesystem.namenew, attribute: true }); - - promise = promise.then(_ => new Promise(resolve => - setTimeout(function () { - if (_index <= (filesystems.id.length - 1)) { - if (filesystem.sharesmb == "on") { - FnFileSystemMountpointGet({ name: pool.name, id: pool.id }, { name: filesystem.namenew, id: filesystem.idnew }) - .done(function (data) { - filesystem.mountpoint = data.replace(/\n$/, ""); - - FnSambaZfsShareConfigurationPathSet({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: filesystem.name, namenew: filesystem.namenew, id: filesystem.id, mountpoint: filesystem.mountpoint }) - .finally(function () { - FnSambaZfsShareDisable({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id }); - }); - }); - } - } - - if (_index == (filesystems.id.length - 1)) { - setTimeout(function () { - if (!display.silent) { - FnDisplayAlert({ status: "success", title: "Samba shares successfully renamed", description: pool.name, breakword: false }, { name: "samba-rename", id: pool.id, timeout: 4 }); - } - - FnConsole.log[1]("Samba, Shares, Rename: Success, Pool: " + pool.name); - - FnSambaZfsSharesConfigurationReload() - .done(function () { - setTimeout(function () { - if (samba.restart) { - FnSambaRestart() - .finally(function () { - process.promise.resolve(); - }); - } else { - FnSambaConfigurationReload() - .finally(function () { - process.promise.resolve(); - }); - } - }, 300); - }); - }, 800); - } - - resolve(); - }, 800) - )); - }); - } else { - if (!display.silent) { - FnDisplayAlert({ status: "success", title: "Samba shares successfully renamed", description: pool.name, breakword: false }, { name: "samba-rename", id: pool.id, timeout: 4 }); - } - - FnConsole.log[1]("Samba, Shares, Rename: Success, Pool: " + pool.name); - - process.promise.resolve(); - } - - return process.promise.promise(); -} - -function FnSambaStart() { - let process = { - command: ["/bin/systemctl", "start"] - }; - - if (/Debian|Ubuntu/i.test(zfsmanager.system.operatingsystem)) { - process.command.splice(2, 0, "smbd"); - } else { - process.command.splice(2, 0, "smb"); - } - - FnConsole.log[2]("Samba, Start: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnConsole.log[1]("Samba, Start: Success"); - }) - .fail(function (message, data) { - FnConsole.warn("Samba, Start: Failed, Message: " + (data ? data : message)); - }); -} - -function FnSambaStop() { - let process = { - command: ["/bin/systemctl", "stop"] - }; - - if (/Debian|Ubuntu/i.test(zfsmanager.system.operatingsystem)) { - process.command.splice(2, 0, "smbd"); - } else { - process.command.splice(2, 0, "smb"); - } - - FnConsole.log[2]("Samba, Stop: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnConsole.log[1]("Samba, Stop: Success"); - }) - .fail(function (message, data) { - FnConsole.warn("Samba, Stop: Failed, Message: " + (data ? data : message)); - }); -} - -function FnSambaUsersharesDirectoryCreate() { - let process = { - command: ["/bin/sh", "-c", `[ ! -d /var/lib/samba/usershares ] && /bin/mkdir -p /var/lib/samba/usershares || printf "Skipped"`] - }; - - FnConsole.log[2]("Samba, Usershares Directory, Create: In Progress") - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Usershares Directory, Create:" })); - - if (data == "Skipped") { - FnConsole.log[2]("Samba, Usershares Directory, Create: Skipped"); - } else { - FnConsole.log[1]("Samba, Usershares Directory, Create: Success"); - } - }) - .fail(function (message, data) { - FnConsole.warn("Samba, Usershares Directory, Create: Failed, Message: " + (data ? data : message)); - }); -} - -function FnSambaVersionGet() { - let process = { - command: ["/usr/sbin/smbd", "-V"] - }; - let samba = { - message: "" - }; - - FnConsole.log[2]("Samba, Version, Get: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data, message) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Version, Get:" })); - - FnConsole.log[1]("Samba, Version, Get: Success, Version: " + (data ? data.replace(/^Version /i, "") : message.replace(/^Version /i, ""))); - - $("#alerts-requirements").empty().addClass("hidden"); - $("#container").removeClass("hidden"); - }) - .fail(function (message, data) { - FnConsole.error("Samba, Version, Get: Failed, Message: " + (data ? data : message)); - - samba.message = ` -
    - -
    -

    This package requires Samba

    -

    Install Samba software via your package manager

    -
    - -
    - `; - - $("#alerts-requirements").removeClass("hidden").html(samba.message); - $("#container").addClass("hidden"); - }); -} - -function FnSambaZfsShareConfigurationGenerate(filesystem = { name, id, mountpoint }, samba = { enable: false, share: { additional: [], administrative: false, browseable: true, guestok: false, name, comment, readonly: false, temporary: false } }) { - samba.share.conf = { - content: "", - path: "/" + (samba.share.temporary ? "run" : "etc") + "/cockpit/zfs/shares/" + FnGenerateShareFileName({ name: filesystem.name }) + ".conf" - } - - if (!samba.share.name) { - samba.share.name = FnGenerateShareName({ at: false, colon: false, period: false, whitespace: false }, { name: filesystem.name.replace(/^.*\/(.*)$/, "$1") }); - } - if (samba.share.administrative) { - samba.share.name = samba.share.name + "$"; - } - if (!samba.share.comment && samba.enable) { - samba.share.comment = "ZFS: " + filesystem.name; - } - - samba.share.additional = samba.share.additional.reduce((a, v) => { - let allow = true; - - if (/[\[\]]/g.test(v)) { //Do not allow section names - allow = false; - } - if (/^[#]/.test(v) == false && /[=]/.test(v)) { //Do not allow modal configurable properties - if (/(path|comment|browseable|read only|guest ok).*=/gi.test(v)) { - allow = false; - } - } - - if (allow) { - v = v.replace(/\\/g, "\\\\\\"); - - a.push((/^[#]/.test(v) == false && /[=]/.test(v) ? "\\t" + v : v)); - } - - return a; - }, []); - - samba.share.conf.content = "\"# COCKPIT ZFS MANAGER\n# WARNING: DO NOT EDIT, AUTO-GENERATED CONFIGURATION\\n\[" + samba.share.name + "\]\\n\\tpath \= " + filesystem.mountpoint + "\\n\\tcomment \= " + samba.share.comment + "\\n\\tbrowseable = " + (samba.share.browseable ? "yes" : "no") + "\\n\\tread only = " + (samba.share.readonly ? "yes" : "no") + "\\n\\tguest ok = " + (samba.share.guestok ? "yes" : "no") + "\\n\\n# ADD ADDITIONAL CONFIGURATION HERE\\n" + samba.share.additional.join("\\n") + "\\n\" > \"" + samba.share.conf.path + "\""; - - return samba.share.conf.content; -} - -function FnSambaZfsShareConfigurationGet(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id }, modal = { name, id }) { - let process = { - command: ["/bin/cat", "/" + (pool.altroot || pool.readonly ? "run" : "etc") + "/cockpit/zfs/shares/" + FnGenerateShareFileName({ name: filesystem.name }) + ".conf"] - }; - let samba = { - share: { - name: "", - path: "", - comment: "", - administrative: false, - browseable: true, - guestok: false, - readonly: false, - additional: [] - } - }; - - FnConsole.log[2]("Samba, ZFS Share Configuration, Get: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, ZFS Share Configuration, Get:" })); - - samba.share.conf = data.split(/\n/g).filter(v => v); - - samba.share.conf.forEach((_value, _index) => { - _value = _value.replace(/\t/g, ""); - - //2=name, 3=path, 4=comment, 5=browseable, 6=read only, 7=guest ok - - switch (_index) { - case 2: //2=name - if (/^\[.*\]$/g.test(_value)) { - samba.share.name = _value.replace(/\[/g, "").replace(/\]/g, ""); - - if (/[$]$/.test(samba.share.name)) { - samba.share.administrative = true; - samba.share.name = samba.share.name.replace(/[$]$/, ""); - } - } - - break; - case 3: //3=path - if (/path \=/gi.test(_value)) { - samba.share.path = _value.replace("path = ", "").replace(/["]/g, ""); - } - - break; - case 4: //4=comment - if (/comment \=/gi.test(_value)) { - samba.share.comment = _value.replace("comment = ", "").replace(/["]/g, ""); - } - - break; - case 5: //5=browseable - if (/browseable \=/gi.test(_value)) { - samba.share.browseable = (_value.replace("browseable = ", "").replace(/["]/g, "") == "yes" ? true : false); - } - - break; - case 6: //6=read only - if (/read only \=/gi.test(_value)) { - samba.share.readonly = (_value.replace("read only = ", "").replace(/["]/g, "") == "yes" ? true : false); - } - - break; - case 7: //7=guest ok - if (/guest ok \=/gi.test(_value)) { - samba.share.guestok = (_value.replace("guest ok = ", "").replace(/["]/g, "") == "yes" ? true : false); - } - - break; - } - }); - - samba.share.additional = samba.share.conf.filter((v, i) => i > 8).map(v => v.replace(/^\s+/, "")); - - FnConsole.log[1]("Samba, ZFS Share Configuration, Get: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - }) - .fail(function (message, data) { - FnConsole.warn("Samba, ZFS Share Configuration, Get: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); - }) - .finally(function () { - $("#input-" + modal.name + "-name-" + modal.id).val(samba.share.name).attr("data-field-value", samba.share.name); - $("#input-" + modal.name + "-comment-" + modal.id).val(samba.share.comment); - $("#textarea-" + modal.name + "-additional-" + modal.id).val(samba.share.additional.join("\n")); - - if (samba.share.administrative && !$("#switch-" + modal.name + "-administrative-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-administrative-" + modal.id + " input").click(); - } - if (!samba.share.browseable && $("#switch-" + modal.name + "-browseable-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-browseable-" + modal.id + " input").click(); - } - if (samba.share.guestok && !$("#switch-" + modal.name + "-guestok-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-guestok-" + modal.id + " input").click(); - } - if (samba.share.readonly && !$("#switch-" + modal.name + "-readonly-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-readonly-" + modal.id + " input").click(); - } - - if (!samba.share.name) { - $("#alert-" + modal.name + "-configurationmissing-" + modal.id).removeClass("hidden"); - - $("#input-" + modal.name + "-name-" + modal.id).val(FnGenerateShareName({ at: false, colon: false, period: false, whitespace: false }, { name: filesystem.name.replace(/^.*\/(.*)$/, "$1") })).focus(); - if (!samba.share.comment) { - $("#input-" + modal.name + "-comment-" + modal.id).val("ZFS: " + filesystem.name); - } - } - if (samba.share.additional.length > 0 && !$("#switch-" + modal.name + "-additional-" + modal.id + " input").prop("checked")) { - $("#switch-" + modal.name + "-additional-" + modal.id + " input").click(); - } - }); -} - -function FnSambaZfsShareConfigurationPathSet(pool = { name, id, altroot: false }, filesystem = { name, namenew, id, mountpoint }, display = { silent: true }) { - let process = { - command: ["/bin/cat", "/" + (pool.altroot ? "run" : "etc") + "/cockpit/zfs/shares/" + FnGenerateShareFileName({ name: filesystem.name }) + ".conf"], - promise: cockpit.defer() - }; - let samba = { - share: { - name: "", - path: "", - comment: "", - administrative: false, - browseable: true, - guestok: false, - readonly: false, - temporary: (pool.altroot ? true : false), - additional: [] - } - }; - - FnConsole.log[2]("Samba, ZFS Share Configuration, Get: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, ZFS Share Configuration, Get:" })); - - samba.share.conf = data.split(/\n/g).filter(v => v); - - samba.share.conf.forEach((_value, _index) => { - _value = _value.replace(/\t/g, ""); - - //2=name, 3=path, 4=comment, 5=browseable, 6=read only, 7=guest ok - - switch (_index) { - case 2: //2=name - if (/^\[.*\]$/g.test(_value)) { - samba.share.name = _value.replace(/\[/g, "").replace(/\]/g, ""); - - if (/[$]$/.test(samba.share.name)) { - samba.share.administrative = true; - samba.share.name = samba.share.name.replace(/[$]$/, ""); - } - } - - break; - case 3: //3=path - if (/path \=/gi.test(_value)) { - samba.share.path = _value.replace("path = ", "").replace(/["]/g, ""); - } - - break; - case 4: //4=comment - if (/comment \=/gi.test(_value)) { - samba.share.comment = _value.replace("comment = ", "").replace(/["]/g, ""); - } - - break; - case 5: //5=browseable - if (/browseable \=/gi.test(_value)) { - samba.share.browseable = (_value.replace("browseable = ", "").replace(/["]/g, "") == "yes" ? true : false); - } - - break; - case 6: //6=read only - if (/read only \=/gi.test(_value)) { - samba.share.readonly = (_value.replace("read only = ", "").replace(/["]/g, "") == "yes" ? true : false); - } - - break; - case 7: //7=guest ok - if (/guest ok \=/gi.test(_value)) { - samba.share.guestok = (_value.replace("guest ok = ", "").replace(/["]/g, "") == "yes" ? true : false); - } - - break; - } - }); - - samba.share.additional = samba.share.conf.filter((v, i) => i > 8).map(v => v.replace(/^\s+/, "")); - - FnConsole.log[1]("Samba, ZFS Share Configuration, Get: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - - if (filesystem.mountpoint != samba.share.path || filesystem.namenew) { - if (filesystem.namenew) { - if ((filesystem.name.replace(/^.*\/(.*)$/, "$1") != filesystem.namenew.replace(/^.*\/(.*)$/, "$1") && samba.share.name.toLowerCase() == FnGenerateShareName({ at: false, colon: false, period: false, whitespace: false }, { name: filesystem.name.replace(/^.*\/(.*)$/, "$1") }).toLowerCase()) || samba.share.name.toLowerCase() == FnGenerateShareName({ at: false, colon: false, period: false, whitespace: false }, { name: filesystem.name }).toLowerCase()) { - samba.share.nameunique = true; - - FnSambaShareNamesGet({ zfsonly: false }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Share, Names, Get:" })); - - if (data.replace(/\n/g, "") != "$empty") { //$empty response is received if share names list is empty - samba.shares = data.split(/\n/g).filter(v => v); - - samba.shares.forEach((_value, _index) => { - if (_value.replace(/^\[/, "").replace(/\]$/, "").toLowerCase() == filesystem.namenew.replace(/^.*\/(.*)$/, "$1").toLowerCase() + (samba.share.administrative ? "$" : "")) { - samba.share.nameunique = false; - - return; - } - }); - } - - if (/^global$|^homes$|^printers$/gi.test(samba.share.name)) { - samba.share.nameunique = false; - } - - if (!samba.share.nameunique) { - samba.share.name = FnGenerateShareName({ at: false, colon: false, period: false, whitespace: false }, { name: filesystem.namenew }); - } else { - samba.share.name = FnGenerateShareName({ at: false, colon: false, period: false, whitespace: false }, { name: filesystem.namenew.replace(/^.*\/(.*)$/, "$1") }); - } - - filesystem.name = filesystem.namenew; - samba.share.comment = "ZFS: " + filesystem.namenew; - - FnSambaZfsShareConfigurationPathSetCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, mountpoint: filesystem.mountpoint }, { share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary } }, { silent: display.silent }) - .finally(function () { - process.promise.resolve(); - }); - }) - .fail(function () { - filesystem.name = filesystem.namenew; - samba.share.comment = "ZFS: " + filesystem.namenew; - samba.share.name = FnGenerateShareName({ at: false, colon: false, period: false, whitespace: false }, { name: filesystem.namenew }); - - FnSambaZfsShareConfigurationPathSetCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, mountpoint: filesystem.mountpoint }, { share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary } }, { silent: display.silent }) - .finally(function () { - process.promise.resolve(); - }); - }); - } else { - filesystem.name = filesystem.namenew; - samba.share.comment = "ZFS: " + filesystem.namenew; - - FnSambaZfsShareConfigurationPathSetCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, mountpoint: filesystem.mountpoint }, { share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary } }, { silent: display.silent }) - .finally(function () { - process.promise.resolve(); - }); - } - } else { - FnSambaZfsShareConfigurationPathSetCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, mountpoint: filesystem.mountpoint }, { share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary } }, { silent: display.silent }) - .finally(function () { - process.promise.resolve(); - }); - } - } else { - process.promise.resolve(); - } - }) - .fail(function (message, data) { - FnConsole.warn("Samba, ZFS Share Configuration, Get: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); - - process.promise.resolve(); - }); - - return process.promise.promise(); -} - -function FnSambaZfsShareConfigurationPathSetCommand(pool = { name, id }, filesystem = { name, id, mountpoint }, samba = { share: { additional: [], administrative: false, browseable: true, guestok: false, name, comment, readonly: false, temporary: false } }, display = { silent: true }) { - let process = { - command: ["/bin/sh", "-c", "printf " + FnSambaZfsShareConfigurationGenerate({ name: filesystem.name, id: filesystem.id, mountpoint: filesystem.mountpoint }, { enable: false, share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary } })] - }; - - FnConsole.log[2]("Samba, ZFS Share Configuration, Path, Set: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - if (!display.silent) { - FnDisplayAlert({ status: "success", title: "Samba share configuration successfully updated", description: filesystem.name, breakword: false }, { name: "samba-configure-share", id: filesystem.id, timeout: 4 }); - } - - FnConsole.log[1]("Samba, ZFS Share Configuration, Path, Set: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - }) - .fail(function (message, data) { - if (!display.silent) { - FnDisplayAlert({ status: "danger", title: "Samba share configuration could not be updated", description: filesystem.name, breakword: false }, { name: "samba-configure-share", id: filesystem.id, timeout: 4 }); - } - - FnConsole.warn("Samba, ZFS Share Configuration, Path, Set: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); - }); -} - -function FnSambaZfsShareConfigurationPathsSet(pool = { name, id, altroot: false }, filesystem = { name }, samba = { restart: false }, display = { refresh: false, silent: true }) { - let process = { - command: ["/sbin/zfs", "list", "-H", "-o", "name,mounted,mountpoint,sharesmb", "-r", "-t", "filesystem", filesystem.name], - promise: cockpit.defer() - }; - - FnConsole.log[2]("Samba, ZFS Share Configuration, Paths, Set: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - cockpit.spawn(process.command, { err: "out" }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, ZFS Share Configuration, Paths, Set:" })); - - let filesystems = { - id: data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) - }; - let promise = Promise.resolve(); - - if (filesystems.id.length > 0) { - filesystems.id.forEach((_value, _index) => { - let filesystem = { - properties: _value.split(/\t/g).filter(v => v) - }; - - filesystem.name = filesystem.properties[0]; - filesystem.id = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: filesystem.properties[0], attribute: true }); - filesystem.mounted = filesystem.properties[1]; - filesystem.mountpoint = filesystem.properties[2]; - filesystem.sharesmb = filesystem.properties[3]; - - promise = promise.then(_ => new Promise(resolve => - setTimeout(function () { - if (_index <= (filesystems.id.length - 1)) { - if (filesystem.sharesmb == "on") { - FnSambaZfsShareConfigurationPathSet({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: filesystem.name, namenew: null, id: filesystem.id, mountpoint: filesystem.mountpoint }) - } - } - - if (_index == (filesystems.id.length - 1)) { - setTimeout(function () { - FnDisplayAlert({ status: "success", title: "Samba share configurations successfully updated", description: pool.name, breakword: false }, { name: "samba-configure-share", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Samba, ZFS Share Configuration, Paths, Set: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - - FnSambaZfsSharesConfigurationReload() - .done(function () { - setTimeout(function () { - if (samba.restart) { - FnSambaRestart() - .finally(function () { - if (display.refresh) { - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 500); - } - - process.promise.resolve(); - }); - } else { - FnSambaConfigurationReload() - .finally(function () { - if (display.refresh) { - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 500); - } - - process.promise.resolve(); - }); - } - }, 300); - }); - }, 500); - } - - resolve(); - }, 500) - )); - }); - } else { - FnDisplayAlert({ status: "success", title: "Samba share configurations successfully updated", description: pool.name, breakword: false }, { name: "samba-configure-share", id: pool.id, timeout: 4 }); - - FnConsole.log[1]("Samba, ZFS Share Configuration, Paths, Set: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - - process.promise.resolve(); - } - }) - .fail(function (message, data) { - FnDisplayAlert({ status: "danger", title: "Samba share configurations could not updated", description: pool.name, breakword: false }, { name: "samba-configure-share", id: pool.id, timeout: 4 }); - - FnConsole.warn("Samba, ZFS Share Configuration, Paths, Set: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); - - if (display.refresh) { - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); - }, 500); - } - - process.promise.resolve(); - }); - - return process.promise.promise(); -} - -function FnSambaZfsShareConfigure(pool = { name, id }, filesystem = { name, id, mountpoint }, samba = { share: { additional: [], administrative: false, browseable: true, guestok: false, name, comment, nameexisting, readonly: false, temporary: false }, restart: false }) { - $("#spinner-storagepool-filesystem-samba-configure-" + filesystem.id + " span").text("Configuring Samba share..."); - - FnSambaShareNamesGet({ zfsonly: false }) - .done(function (data) { - FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Share, Names, Get:" })); - - samba.share.nameunique = true; - samba.share.errormessage = "Share name is already in use."; - - if (data.replace(/\n/g, "") != "$empty") { //$empty response is received if share names list is empty - samba.shares = data.split(/\n/g).filter(v => v); - - samba.shares.forEach((_value, _index) => { - if (_value.replace(/^\[/, "").replace(/\]$/, "").toLowerCase() == samba.share.name.toLowerCase() + (samba.share.administrative ? "$" : "")) { - if (samba.share.name != samba.share.nameexisting) { //Allow the name since the share is already enabled with this name - samba.share.nameunique = false; - - return; - } - } - }); - } - - if (/^global$|^homes$|^printers$/gi.test(samba.share.name)) { - samba.share.nameunique = false; - samba.share.errormessage = "Share name can not be a restricted name."; - } - - if (!samba.share.nameunique) { - $("#validationwrapper-storagepool-filesystem-samba-configure-name-" + filesystem.id).addClass("has-error"); - $("#helpblock-storagepool-filesystem-samba-configure-name-" + filesystem.id).addClass("has-error").removeClass("hidden").text(samba.share.errormessage); - $("#input-storagepool-filesystem-samba-configure-name-" + filesystem.id).focus(); - - $("#spinner-storagepool-filesystem-samba-configure-" + filesystem.id).addClass("hidden"); - $("#spinner-storagepool-filesystem-samba-configure-" + filesystem.id + " span").text(""); - $("#btn-storagepool-filesystem-samba-configure-apply-" + filesystem.id).prop("disabled", false); - - FnConsole.warn("Samba, ZFS Share Configuration, Update: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + samba.share.errormessage); - } else { - FnSambaZfsShareConfigureCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, mountpoint: filesystem.mountpoint }, { share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary }, restart: samba.restart }); - } - }); -} - -function FnSambaZfsShareConfigureCommand(pool = { name, id }, filesystem = { name, id, mountpoint }, samba = { share: { additional: [], administrative: false, browseable: true, guestok: false, name, comment, readonly: false, temporary: false }, restart: false }) { - let process = { - command: ["/bin/sh", "-c", "printf " + FnSambaZfsShareConfigurationGenerate({ name: filesystem.name, id: filesystem.id, mountpoint: filesystem.mountpoint }, { enable: false, share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary } })] - }; - - FnConsole.log[2]("Samba, ZFS Share Configuration, Update: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnDisplayAlert({ status: "success", title: "Samba share configuration successfully updated", description: filesystem.name, breakword: false }, { name: "samba-configure-share", id: filesystem.id, timeout: 4 }); - - FnConsole.log[1]("Samba, ZFS Share Configuration, Update: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - - if (samba.restart) { - FnSambaRestart(); - } else { - FnSambaConfigurationReload(); - } - }) - .fail(function (message, data) { - FnDisplayAlert({ status: "danger", title: "Samba share configuration could not be updated", description: filesystem.name, breakword: false }, { name: "samba-configure-share", id: filesystem.id, timeout: 4 }); - - FnConsole.warn("Samba, ZFS Share Configuration, Update: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); - }) - .finally(function () { - $("#modal-storagepool-filesystem-samba-configure-" + filesystem.id).modal("hide"); - - setTimeout(function () { - FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: false, status: false }); - }, 200); - }); -} - -function FnSambaZfsShareDisable(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id }) { - let process = { - command: ["/bin/rm", "-f", "/" + (pool.altroot || pool.readonly ? "run" : "etc") + "/cockpit/zfs/shares/" + FnGenerateShareFileName({ name: filesystem.name }) + ".conf"] - }; - - FnConsole.log[2]("Samba, Share, Disable: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnConsole.log[1]("Samba, Share, Disable: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - }) - .fail(function (message, data) { - FnConsole.warn("Samba, Share, Disable: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); - }); -} - -function FnSambaZfsShareEnable(pool = { name, id }, filesystem = { name, id, mountpoint }, samba = { share: { additional: [], administrative: false, browseable: true, guestok: false, name, comment, readonly: false, temporary: false } }) { - let process = { - command: ["/bin/sh", "-c", "printf " + FnSambaZfsShareConfigurationGenerate({ name: filesystem.name, id: filesystem.id, mountpoint: filesystem.mountpoint }, { enable: true, share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary } })] - }; - - FnConsole.log[2]("Samba, Share, Enable: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnConsole.log[1]("Samba, Share, Enable: Success, Pool: " + pool.name + ", File System: " + filesystem.name); - }) - .fail(function (message, data) { - FnConsole.warn("Samba, Share, Enable: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); - }); -} - -function FnSambaZfsSharesConfigurationReload() { - let process = { - command: ["/bin/sh", "-c", "echo '# COCKPIT ZFS MANAGER\n# WARNING: DO NOT EDIT, AUTO-GENERATED CONFIGURATION' > /etc/cockpit/zfs/shares.conf && /bin/ls /etc/cockpit/zfs/shares/*.conf 2> /dev/null | /bin/sed -e 's/^/include = /' >> /etc/cockpit/zfs/shares.conf && echo '# COCKPIT ZFS MANAGER\n# WARNING: DO NOT EDIT, AUTO-GENERATED CONFIGURATION' > /run/cockpit/zfs/shares.conf && /bin/ls /run/cockpit/zfs/shares/*.conf 2> /dev/null | /bin/sed -e 's/^/include = /' >> /run/cockpit/zfs/shares.conf"] - }; - - FnConsole.log[2]("Samba, ZFS Shares Configuration, Reload: In Progress"); - FnConsole.log[3](FnConsoleCommand({ command: process.command })); - - return cockpit.spawn(process.command, { err: "out", superuser: "require" }) - .done(function () { - FnConsole.log[1]("Samba, ZFS Shares Configuration, Reload: Success"); - }) - .fail(function (message, data) { - FnConsole.warn("Samba, ZFS Shares Configuration, Reload: Failed, Message: " + (data ? data : message)); - }); -} - -//#endregion - -//#region Dynamic Content Click Actions - -function FnDynamicStatusDiskTrimCancel(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }) { - let dynamic = { - script: "" - }; - - dynamic.script = ` - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-disk-trim-cancel-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolTrimCancel({ name: "` + pool.name + `", id: "` + pool.id + `" }, { id: "` + disk.id + `" }); - }); - \x3C/script> - `; - - $("#dynamics-storagepool-status-" + pool.id).append(dynamic.script); -} - -function FnDynamicStatusDiskTrimResume(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }) { - let dynamic = { - script: "" - }; - - dynamic.script = ` - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-disk-trim-resume-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolTrimStart({ name: "` + pool.name + `", id: "` + pool.id + `" }, { id: "` + disk.id + `" }, { resume: true, secure: false }, { name: null, id: null }); - }); - \x3C/script> - `; - - $("#dynamics-storagepool-status-" + pool.id).append(dynamic.script); -} - -function FnDynamicStatusDiskTrimSuspend(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }) { - let dynamic = { - script: "" - }; - - dynamic.script = ` - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-disk-trim-suspend-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolTrimSuspend({ name: "` + pool.name + `", id: "` + pool.id + `" }, { id: "` + disk.id + `" }); - }); - \x3C/script> - `; - - $("#dynamics-storagepool-status-" + pool.id).append(dynamic.script); -} - -function FnDynamicStatusStoragePoolScrubPause(pool = { name, id, status: { config: { items: { index: 0 } } } }) { - let dynamic = { - script: "" - }; - - dynamic.script = ` - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-scrub-pause-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolScrubPause({ name: "` + pool.name + `", id: "` + pool.id + `" }, { refresh: true }); - }); - \x3C/script> - `; - - $("#dynamics-storagepool-status-" + pool.id).append(dynamic.script); -} - -function FnDynamicStatusStoragePoolScrubResume(pool = { name, id, status: { config: { items: { index: 0 } } } }) { - let dynamic = { - script: "" - }; - - dynamic.script = ` - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-scrub-resume-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolScrubStart({ name: "` + pool.name + `", id: "` + pool.id + `" }, { resume: true }), { refresh: true }; - }); - \x3C/script> - `; - - $("#dynamics-storagepool-status-" + pool.id).append(dynamic.script); -} - -function FnDynamicStatusStoragePoolScrubStart(pool = { name, id, status: { config: { items: { index: 0 } } } }) { - let dynamic = { - script: "" - }; - - dynamic.script = ` - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-scrub-start-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolScrubStart({ name: "` + pool.name + `", id: "` + pool.id + `" }, { resume: false }, { refresh: true }); - }); - \x3C/script> - `; - - $("#dynamics-storagepool-status-" + pool.id).append(dynamic.script); -} - -function FnDynamicStatusStoragePoolScrubStop(pool = { name, id, status: { config: { items: { index: 0 } } } }) { - let dynamic = { - script: "" - }; - - dynamic.script = ` - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-scrub-stop-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolScrubStop({ name: "` + pool.name + `", id: "` + pool.id + `" }, { refresh: true }); - }); - \x3C/script> - `; - - $("#dynamics-storagepool-status-" + pool.id).append(dynamic.script); -} - -function FnDynamicStatusStoragePoolTrimCancel(pool = { name, id, status: { config: { items: { index: 0 } } } }) { - let dynamic = { - script: "" - }; - - dynamic.script = ` - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-trim-cancel-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolTrimCancel({ name: "` + pool.name + `", id: "` + pool.id + `" }, { id: null }); - }); - \x3C/script> - `; - - $("#dynamics-storagepool-status-" + pool.id).append(dynamic.script); -} - -function FnDynamicStatusStoragePoolTrimResume(pool = { name, id, status: { config: { items: { index: 0 } } } }) { - let dynamic = { - script: "" - }; - - dynamic.script = ` - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-trim-resume-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolTrimStart({ name: "` + pool.name + `", id: "` + pool.id + `" }, { id: null }, { resume: true, secure: false }, { name: null, id: null }); - }); - \x3C/script> - `; - - $("#dynamics-storagepool-status-" + pool.id).append(dynamic.script); -} - -function FnDynamicStatusStoragePoolTrimSuspend(pool = { name, id, status: { config: { items: { index: 0 } } } }) { - let dynamic = { - script: "" - }; - - dynamic.script = ` - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-trim-suspend-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolTrimSuspend({ name: "` + pool.name + `", id: "` + pool.id + `" }, { id: null }); - }); - \x3C/script> - `; - - $("#dynamics-storagepool-status-" + pool.id).append(dynamic.script); -} - -//#endregion - -//#region Modals Register - -function FnModalsRegister() { - $("#modals").append(`
    `); - $("#modals").append(`
    `); - - FnModalAbout(); - FnModalConfigure(); - FnModalUpdate(); - FnModalWelcome(); - FnModalStoragePoolsCreate(); - FnModalStoragePoolsImport(); - FnModalFileSystemsUnlock(); -} - -//#endregion - -//#region Modal Cockpit ZFS Manager - -function FnModalAbout() { - let modal = { - window: "" - }; - - modal.window = ` - - `; - - $("#modals").append(modal.window); -} - -function FnModalConfigure() { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-configure").on("click", function () { - FnModalConfigureContent({ id: $("#modal-configure") }); - }); - \x3C/script> - `; - - $("#modals").append(modal.window); -} - -function FnModalConfigureContent(modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#switch-configure-samba-manage input").on("click", function () { - if (!$(this).prop("checked")) { - $("#switch-configure-samba-windowscompatibility input").prop("disabled", true); - $("#switch-configure-samba-windowscompatibility").parent().addClass("hidden"); - } else { - $("#switch-configure-samba-windowscompatibility input").removeClass("hidden").prop("disabled", false); - $("#switch-configure-samba-windowscompatibility").parent().removeClass("hidden"); - } - }); - - $("#switch-configure-zfs-storagepool-boot input").on("click", function () { - if (!$(this).prop("checked")) { - $("#switch-configure-zfs-storagepool-bootlockdown input").prop("disabled", true); - $("#switch-configure-zfs-storagepool-bootlockdown").parent().addClass("hidden"); - } else { - $("#switch-configure-zfs-storagepool-bootlockdown input").prop("disabled", false); - $("#switch-configure-zfs-storagepool-bootlockdown").parent().removeClass("hidden"); - } - }); - - $("#btn-configure-apply").on("click", function () { - $("#spinner-configure").removeClass("hidden"); - $(this).prop("disabled", true); - - let user = { - cockpit: { - manage: $("#switch-configure-cockpit-manage input").prop("checked") - }, - disks: { - base2: $("#switch-configure-disks-base2 input").prop("checked"), - }, - loglevel: $("#btnspan-configure-zfs-storagepool-loglevel").attr("data-field-value"), - samba: { - manage: $("#switch-configure-samba-manage input").prop("checked"), - windowscompatibility: $("#switch-configure-samba-windowscompatibility input").prop("checked") - }, - updates: { - check: $("#switch-configure-updates-check input").prop("checked") - }, - zfs: { - filesystem: { - cloneorigin: $("#switch-configure-zfs-filesystem-cloneorigin input").prop("checked"), - quotarestrict: $("#switch-configure-zfs-filesystem-quotarestrict input").prop("checked"), - readonlylockdown: $("#switch-configure-zfs-filesystem-readonlylockdown input").prop("checked"), - snapshotactions: $("#switch-configure-zfs-filesystem-snapshotactions input").prop("checked") - }, - snapshot: { - filesystemlist: $("#switch-configure-zfs-snapshot-filesystemlist input").prop("checked") - }, - status: { - errorcolors: $("#switch-configure-zfs-status-errorcolors input").prop("checked"), - trimunsupported: $("#switch-configure-zfs-status-trimunsupported input").prop("checked") - }, - storagepool: { - activetab: $("#btnspan-configure-zfs-storagepool-activetab").attr("data-field-value"), - boot: $("#switch-configure-zfs-storagepool-boot input").prop("checked"), - bootlockdown: $("#switch-configure-zfs-storagepool-bootlockdown input").prop("checked"), - count: $("#switch-configure-zfs-storagepool-count input").prop("checked"), - refreshall: $("#switch-configure-zfs-storagepool-refreshall input").prop("checked"), - root: $("#switch-configure-zfs-storagepool-root input").prop("checked") - } - } - }; - - FnConfigure({ cockpit: { manage: user.cockpit.manage }, disks: { base2: user.disks.base2 }, loglevel: user.loglevel, samba: { manage: user.samba.manage, windowscompatibility: user.samba.windowscompatibility }, updates: { check: user.updates.check }, zfs: { filesystem: { cloneorigin: user.zfs.filesystem.cloneorigin, quotarestrict: user.zfs.filesystem.quotarestrict, readonlylockdown: user.zfs.filesystem.readonlylockdown, snapshotactions: user.zfs.filesystem.snapshotactions }, snapshot: { filesystemlist: user.zfs.snapshot.filesystemlist }, status: { errorcolors: user.zfs.status.errorcolors, trimunsupported: user.zfs.status.trimunsupported }, storagepool: { activetab: user.zfs.storagepool.activetab, boot: user.zfs.storagepool.boot, bootlockdown: user.zfs.storagepool.bootlockdown, count: user.zfs.storagepool.count, refreshall: user.zfs.storagepool.refreshall, root: user.zfs.storagepool.root } } }, { name: "configure", welcome: false }) - }); - - $("#dropdown-configure-zfs-storagepool-activetab").on("click", "li a", function () { - $("#btnspan-configure-zfs-storagepool-activetab").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - - $("#dropdown-configure-zfs-storagepool-loglevel").on("click", "li a", function () { - $("#btnspan-configure-zfs-storagepool-loglevel").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalUpdate() { - let modal = { - window: "" - }; - - modal.window = ` - - `; - - $("#modals").append(modal.window); -} - -function FnModalUpdateContent(modal = { id }) { - modal.content = ` - - `; - - modal.id.empty().append(modal.content); - - $("#progressbar-update .progress-bar").css("width", "100%"); -} - -function FnModalWelcome() { - let modal = { - window: "" - }; - - modal.window = ` - - `; - - $("#modals").append(modal.window); -} - -function FnModalWelcomeContent(modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#switch-welcome-samba-manage input").on("click", function () { - if (!$(this).prop("checked")) { - $("#switch-welcome-samba-windowscompatibility input").prop("disabled", true); - $("#switch-welcome-samba-windowscompatibility").parent().addClass("hidden"); - } else { - $("#switch-welcome-samba-windowscompatibility input").removeClass("hidden").prop("disabled", false); - $("#switch-welcome-samba-windowscompatibility").parent().removeClass("hidden"); - } - }); - - $("#switch-welcome-zfs-storagepool-boot input").on("click", function () { - if (!$(this).prop("checked")) { - $("#switch-welcome-zfs-storagepool-bootlockdown input").prop("disabled", true); - $("#switch-welcome-zfs-storagepool-bootlockdown").parent().addClass("hidden"); - } else { - $("#switch-welcome-zfs-storagepool-bootlockdown input").prop("disabled", false); - $("#switch-welcome-zfs-storagepool-bootlockdown").parent().removeClass("hidden"); - } - }); - - $("#btn-welcome-apply").on("click", function () { - $("#spinner-welcome").removeClass("hidden"); - $(this).prop("disabled", true); - - let user = { - cockpit: { - manage: $("#switch-welcome-cockpit-manage input").prop("checked") - }, - loglevel: $("#btnspan-welcome-zfs-storagepool-loglevel").attr("data-field-value"), - samba: { - manage: $("#switch-welcome-samba-manage input").prop("checked"), - windowscompatibility: $("#switch-welcome-samba-windowscompatibility input").prop("checked") - }, - updates: { - check: $("#switch-welcome-updates-check input").prop("checked") - }, - zfs: { - storagepool: { - boot: $("#switch-welcome-zfs-storagepool-boot input").prop("checked"), - bootlockdown: $("#switch-welcome-zfs-storagepool-bootlockdown input").prop("checked"), - root: $("#switch-welcome-zfs-storagepool-root input").prop("checked") - } - } - }; - - FnConfigure({ cockpit: { manage: user.cockpit.manage }, disks: { base2: ` + zfsmanager.configuration.disks.base2 + ` }, loglevel: user.loglevel, samba: { manage: user.samba.manage, windowscompatibility: user.samba.windowscompatibility }, updates: { check: user.updates.check }, zfs: { filesystem: { cloneorigin: ` + zfsmanager.configuration.zfs.filesystem.cloneorigin + `, quotarestrict: ` + zfsmanager.configuration.zfs.filesystem.quotarestrict + `, readonlylockdown: ` + zfsmanager.configuration.zfs.filesystem.readonlylockdown + `, snapshotactions: ` + zfsmanager.configuration.zfs.filesystem.snapshotactions + ` }, snapshot: { filesystemlist: ` + zfsmanager.configuration.zfs.snapshot.filesystemlist + ` }, status: { errorcolors: ` + zfsmanager.configuration.zfs.status.errorcolors + `, trimunsupported: ` + zfsmanager.configuration.zfs.status.trimunsupported + ` }, storagepool: { activetab: ` + zfsmanager.configuration.zfs.storagepool.activetab + `, boot: user.zfs.storagepool.boot, bootlockdown: user.zfs.storagepool.bootlockdown, count: ` + zfsmanager.configuration.zfs.storagepool.count + `, refreshall: ` + zfsmanager.configuration.zfs.storagepool.refreshall + `, root: user.zfs.storagepool.root } } }, { name: "welcome", welcome: true }) - }); - - $("#dropdown-welcome-zfs-storagepool-activetab").on("click", "li a", function () { - $("#btnspan-welcome-zfs-storagepool-activetab").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - - $("#dropdown-welcome-zfs-storagepool-loglevel").on("click", "li a", function () { - $("#btnspan-welcome-zfs-storagepool-loglevel").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -//#endregion - -//#region Modal Storage Pools - -function FnModalStoragePoolsCreate() { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepools-create").on("click", function () { - FnModalStoragePoolsCreateContent({ id: $("#modal-storagepools-create") }); - FnDisksAvailableGet({ name: "storagepools-create-disks", id: null, default: true }); - - $("#input-storagepools-create-refreservation").val("10"); - $("#validationwrapper-storagepools-create-refreservation .min-slider-handle").attr("tabindex", "1003"); - setTimeout(function() { - $("#input-storagepools-create-name").focus(); - }, 600); - }); - \x3C/script> - `; - - $("#modals-storagepools").append(modal.window); -} - -function FnModalStoragePoolsCreateContent(modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#input-storagepools-create-refreservation").tooltip({ trigger: "manual" }) - .on("keyup", function (element) { - let $this = $(this); - let sd = $this.siblings("[data-provide=slider]").slider(); - - if ($this.val().trim() && !$.isNumeric(this.value)) { - this.value = sd.slider("getValue"); - } - }) - .on("keypress blur", function (element) { - if (element.which == 13 || element.type === "blur") { - element.preventDefault(); - - let $this = $(this); - let sd = $this.siblings("[data-provide=slider]").slider(); - let max = sd.slider("getAttribute", "max"); - let min = sd.slider("getAttribute", "min"); - - if (!$.isNumeric(this.value) || (this.value > max || this.value < min)) { - let warningInfo = $.isNumeric(this.value) ? "Valid value should be between " + min + " and " + max : "Valid value should be number"; - $this.attr("data-original-title", warningInfo).tooltip("show").addClass("warning"); - this.value = sd.slider("getValue"); - setTimeout(function () { - $this.tooltip("hide"); - }, 3000); - } else { - if ($this.is(".warning")) { - $this.tooltip("hide"); - } - - this.value = $this.val().trim(); - sd.slider("setValue", this.value); - } - } - }) - .siblings("[data-provide=slider]").each(function () { - $("#input-storagepools-create-refreservation").val(this.value); - $(this).slider().on("change", function (element) { - $("#input-storagepools-create-refreservation").val(element.value.newValue); - }); - }); - - $("#input-storagepools-create-refreservation").on("change textInput input", function (element) { - if ($(this).val() > 20) { //Force reset to maximum allowed value - $(this).val(20); - } else if ($(this).val() < 0) { //Force reset to minimum allowed value - $(this).val(0); - } - - if ($.isNumeric($(this).val())) { - $("#slider-storagepools-create-refreservation").slider("setValue", $(this).val()); - } - }); - - $("#switch-storagepools-create-disks-wwn input").on("click", function () { - $("#btnspan-storagepools-create-disks-identifier").text("Block Device"); - $("#dropdown-storagepools-create-disks-identifier li").siblings().removeClass("active"); - $("#dropdown-storagepools-create-disks-identifier li[value='blockdevice']").addClass("active"); - $("#helpblock-storagepools-create-disks-identifierwarning").addClass("hidden").text(""); - ` + (zfsmanager.zfs.warnings.nvmevdev ? `$("#helpblock-storagepools-create-disks-identifierwarningzfs").addClass("hidden");` : ``) + ` - - let disk = { - identifier: ($(this).prop("checked") ? "wwn" : "blockdevice"), - identifiertext: ($(this).prop("checked") ? "WWN" : "Block Device") - }; - - if ($(this).prop("checked")) { - $("#controllabel-storagepools-create-disks-identifier").addClass("hidden"); - $("#validationwrapper-storagepools-create-disks-identifier").addClass("hidden"); - } else { - $("#controllabel-storagepools-create-disks-identifier").removeClass("hidden"); - $("#validationwrapper-storagepools-create-disks-identifier").removeClass("hidden"); - } - - $("#listgroup-storagepools-create-disks input[name='checkbox-storagepools-create-disks']").map(function () { - if ($(this).attr("data-disk-id-" + disk.identifier)) { - $(this).next().find(".select-ct-disk-row-id").text((disk.identifier == "blockdevice" ? "/dev/" : "") + $(this).attr("data-disk-id-" + disk.identifier)); - $(this).attr("data-disk-name", $(this).attr("data-disk-id-" + disk.identifier)); - } else { - $(this).next().find(".select-ct-disk-row-id").text("/dev/" + $(this).attr("data-disk-id-blockdevice")); - $(this).attr("data-disk-name", $(this).attr("data-disk-id-blockdevice")); - $("#helpblock-storagepools-create-disks-identifierwarning").removeClass("hidden").text("One or more disks is missing a " + disk.identifiertext + " identifier."); - } - }); - }); - - $("#btn-storagepools-create-apply").on("click", function () { - $("#spinner-storagepools-create").removeClass("hidden"); - $(this).prop("disabled", true); - - let disks = { - id: [] - }; - let filesystem = { - compression: "", - dedup: "off", - recordsize: "131072", - refreservationpercent: 0, - selinux: false - }; - let pool = { - ashift: 0, - autoexpand: "", - autoreplace: "", - autotrim: "", - force: false, - name: "", - virtualdevice: "" - } - let validation = { - disks: false, - name: false - }; - - $("#listgroup-storagepools-create-disks input[name='checkbox-storagepools-create-disks']:checked").map(function () { - disks.id.push($(this).attr("data-disk-name")); - }); - - if ($("#input-storagepools-create-name").val().length == 0) { - $("#helpblock-storagepools-create-name").addClass("has-error").removeClass("hidden").text("Name can not be empty."); - - validation.name = false; - } else if (/^[a-zA-Z0-9-_.: ]*$/.test($("#input-storagepools-create-name").val()) == false) { - $("#helpblock-storagepools-create-name").addClass("has-error").removeClass("hidden").text("Name contains invalid characters."); - - validation.name = false; - } else if (/^[0-9]/.test($("#input-storagepools-create-name").val())) { - $("#helpblock-storagepools-create-name").addClass("has-error").removeClass("hidden").text("Name can not begin with numerical characters."); - - validation.name = false; - } else if (/^[.]/.test($("#input-storagepools-create-name").val())) { - $("#helpblock-storagepools-create-name").addClass("has-error").removeClass("hidden").text("Name can not begin with a period (.)."); - - validation.name = false; - } else if (/^[_]/.test($("#input-storagepools-create-name").val())) { - $("#helpblock-storagepools-create-name").addClass("has-error").removeClass("hidden").text("Name can not begin with an underscore (_)."); - - validation.name = false; - } else if (/^[-]/.test($("#input-storagepools-create-name").val())) { - $("#helpblock-storagepools-create-name").addClass("has-error").removeClass("hidden").text("Name can not begin with a hypen (-)."); - - validation.name = false; - } else if (/^[:]/.test($("#input-storagepools-create-name").val())) { - $("#helpblock-storagepools-create-name").addClass("has-error").removeClass("hidden").text("Name can not begin with an colon (:)."); - - validation.name = false; - } else if (/^[ ]/.test($("#input-storagepools-create-name").val())) { - $("#helpblock-storagepools-create-name").addClass("has-error").removeClass("hidden").text("Name can not begin with whitespace ( )."); - - validation.name = false; - } else if (/[ ]$/.test($("#input-storagepools-create-name").val())) { - $("#helpblock-storagepools-create-name").addClass("has-error").removeClass("hidden").text("Name can not end with whitespace ( )."); - - validation.name = false; - } else if (/^c[0-9]|^log|^mirror|^raidz|^raidz1|^raidz2|^raidz3|^spare/.test($("#input-storagepools-create-name").val())) { - $("#helpblock-storagepools-create-name").addClass("has-error").removeClass("hidden").text("Name can not begin with a reserved name."); - - validation.name = false; - } else { - $("#validationwrapper-storagepools-create-name").removeClass("has-error"); - $("#helpblock-storagepools-create-name").addClass("hidden").text(""); - - validation.name = true; - } - if (disks.id.length < 1 && $("#btnspan-storagepools-create-virtualdevice").attr("data-field-value") == "disk") { - $("#helpblock-storagepools-create-disks").removeClass("hidden").text("One or more disks is needed for Disk."); - - validation.disks = false; - } else if (disks.id.length < 2 && $("#btnspan-storagepools-create-virtualdevice").attr("data-field-value") == "mirror") { - $("#helpblock-storagepools-create-disks").removeClass("hidden").text("Two or more disks is needed for Mirror."); - - validation.disks = false; - } else if (disks.id.length < 2 && $("#btnspan-storagepools-create-virtualdevice").attr("data-field-value") == "raidz1") { - $("#helpblock-storagepools-create-disks").removeClass("hidden").text("Two or more disks is needed for RaidZ1."); - - validation.disks = false; - } else if (disks.id.length < 3 && $("#btnspan-storagepools-create-virtualdevice").attr("data-field-value") == "raidz2") { - $("#helpblock-storagepools-create-disks").removeClass("hidden").text("Three or more disks is needed for RaidZ2."); - - validation.disks = false; - } else if (disks.id.length < 4 && $("#btnspan-storagepools-create-virtualdevice").attr("data-field-value") == "raidz3") { - $("#helpblock-storagepools-create-disks").removeClass("hidden").text("Four or more disks is needed for RaidZ3."); - - validation.disks = false; - } else { - $("#validationwrapper-storagepools-create-disks").removeClass("has-error"); - $("#helpblock-storagepools-create-disks").removeClass("hidden").text(""); - - validation.disks = true; - } - - if (!validation.name || !validation.disks) { - if (!validation.name) { - $("#validationwrapper-storagepools-create-name").addClass("has-error"); - $("#input-storagepools-create-name").focus(); - } - if (!validation.disks) { - $("#validationwrapper-storagepools-create-disks").addClass("has-error"); - } - - $("#spinner-storagepools-create").addClass("hidden"); - $(this).prop("disabled", false); - } - - if (validation.name && validation.disks) { - filesystem.compression = ($("#switch-storagepools-create-compression input").prop("checked") ? "lz4" : "off"); - filesystem.dedup = $("#btnspan-storagepools-create-dedup").attr("data-field-value"); - filesystem.recordsize = $("#btnspan-storagepools-create-recordsize").attr("data-field-value"); - filesystem.refreservationpercent = ($("#input-storagepools-create-refreservation").val() != "0" ? $("#input-storagepools-create-refreservation").val() : "0"); - filesystem.selinux = $("#switch-storagepools-create-selinux input").prop("checked"); - - pool.ashift = $("#btnspan-storagepools-create-ashift").attr("data-field-value"); - pool.autoexpand = ($("#switch-storagepools-create-autoexpand input").prop("checked") ? "on" : "off"); - pool.autoreplace = ($("#switch-storagepools-create-autoreplace input").prop("checked") ? "on" : "off"); - pool.autotrim = ($("#switch-storagepools-create-autotrim input").prop("checked") ? "on" : "off"); - pool.force = $("#switch-storagepools-create-force input").prop("checked"); - pool.name = $("#input-storagepools-create-name").val(); - pool.virtualdevice = ($("#btnspan-storagepools-create-virtualdevice").attr("data-field-value") == "disk" ? "" : $("#btnspan-storagepools-create-virtualdevice").attr("data-field-value")); - - FnStoragePoolCreate({ name: pool.name, ashift: pool.ashift, autoexpand: pool.autoexpand, autoreplace: pool.autoreplace, autotrim: pool.autotrim, force: pool.force, virtualdevice: pool.virtualdevice }, { compression: filesystem.compression, dedup: filesystem.dedup, recordsize: filesystem.recordsize, refreservationpercent: filesystem.refreservationpercent, selinux: filesystem.selinux }, { id: disks.id }); - } - }); - - $("#dropdown-storagepools-create-virtualdevice").on("click", "li a", function () { - $("#btnspan-storagepools-create-virtualdevice").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - - $("#dropdown-storagepools-create-ashift").on("click", "li a", function () { - $("#btnspan-storagepools-create-ashift").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - - $("#dropdown-storagepools-create-disks-identifier").on("click", "li a", function () { - $("#btnspan-storagepools-create-disks-identifier").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - - $("#helpblock-storagepools-create-disks-identifierwarning").addClass("hidden").text(""); - ` + (zfsmanager.zfs.warnings.nvmevdev ? `$("#helpblock-storagepools-create-disks-identifierwarningzfs").addClass("hidden");` : ``) + ` - - let disk = { - identifier: $(this).parent().attr("value"), - identifiertext: $(this).parent().text() - }; - - $("#listgroup-storagepools-create-disks input[name='checkbox-storagepools-create-disks']").map(function () { - if ($(this).attr("data-disk-id-" + disk.identifier)) { - $(this).next().find(".select-ct-disk-row-id").text((disk.identifier == "blockdevice" ? "/dev/" : "") + $(this).attr("data-disk-id-" + disk.identifier)); - $(this).attr("data-disk-name", $(this).attr("data-disk-id-" + disk.identifier)); - } else { - $(this).next().find(".select-ct-disk-row-id").text("/dev/" + $(this).attr("data-disk-id-blockdevice")); - $(this).attr("data-disk-name", $(this).attr("data-disk-id-blockdevice")); - $("#helpblock-storagepools-create-disks-identifierwarning").removeClass("hidden").text("One or more disks is missing a " + disk.identifiertext + " identifier."); - - ` + (zfsmanager.zfs.warnings.nvmevdev ? ` - if (disk.identifier == "vdev" && /^nvme/gi.test($(this).attr("data-disk-id-blockdevice"))) { - $("#helpblock-storagepools-create-disks-identifierwarningzfs").removeClass("hidden"); - } - ` : ``) + ` - } - }); - }); - - $("#dropdown-storagepools-create-dedup").on("click", "li a", function () { - $("#btnspan-storagepools-create-dedup").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - - $("#dropdown-storagepools-create-recordsize").on("click", "li a", function () { - $("#btnspan-storagepools-create-recordsize").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalStoragePoolsImport() { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepools-import").on("click", function () { - FnModalStoragePoolsImportContent({ id: $("#modal-storagepools-import") }); - FnStoragePoolsImportableGet({ destroyed: false }); - }); - \x3C/script> - `; - - $("#modals-storagepools").append(modal.window); -} - -function FnModalStoragePoolsImportContent(modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#switch-storagepools-import-destroyed input").on("click", function () { - $("#helpblock-storagepools-import-storagepools").addClass("hidden").text(""); - $("#helpblock-storagepools-import-storagepools-warning").addClass("hidden").text(""); - - FnStoragePoolsImportableGet({ destroyed: ($(this).prop("checked") ? true : false) }); - }); - - $("#switch-storagepools-import-rename input").on("click", function () { - if ($(this).prop("checked")) { - $("#controllabel-storagepools-import-namenew").removeClass("hidden"); - $("#validationwrapper-storagepools-import-namenew").removeClass("hidden"); - $("#input-storagepools-import-namenew").focus(); - } else { - $("#controllabel-storagepools-import-namenew").addClass("hidden"); - $("#validationwrapper-storagepools-import-namenew").addClass("hidden"); - $("#validationwrapper-storagepools-import-namenew").removeClass("has-error"); - $("#helpblock-storagepools-import-namenew").removeClass("has-error").addClass("hidden").text(""); - $("#input-storagepools-import-namenew").val(""); - } - }); - - $("#switch-storagepools-import-selinux input").on("click", function () { - if ($(this).prop("checked") && $("#switch-storagepools-import-readonly input").prop("checked")) { - $("#switch-storagepools-import-readonly input").click(); - } - }); - - $("#switch-storagepools-import-readonly input").on("click", function () { - if ($(this).prop("checked") && $("#switch-storagepools-import-selinux input").prop("checked")) { - $("#switch-storagepools-import-selinux input").click(); - } - }); - - $("#btn-storagepools-import-apply").on("click", function () { - $("#spinner-storagepools-import").removeClass("hidden"); - $(this).prop("disabled", true); - - let disks = { - id: { - blockdevice: true, - disk: false, - path: false, - vdev: false - }, - identifier: "" - }; - - let filesystem = { - mount: true, - selinux: true - }; - - let pool = { - altroot: "", - name: [], - namenew: "", - guid: [], - destroyed: false, - force: false, - ignoremissinglog: false, - readonly: false, - recoverymode: false - }; - - let validation = { - altroot: false, - name: false, - namenew: false, - storagepools: false - }; - - $("#listgroup-storagepools-import-storagepools input[name='checkbox-storagepools-import-storagepools']:checked").map(function () { - pool.guid.push($(this).attr("data-pool-import-guid")); - pool.name.push($(this).attr("data-pool-import-name")); - - disks.id.disk = ($(this).attr("data-pool-import-id-disk") == "true" ? true : false); - disks.id.path = ($(this).attr("data-pool-import-id-path") == "true" ? true : false); - disks.id.vdev = ($(this).attr("data-pool-import-id-vdev") == "true" ? true : false); - }); - - if (pool.guid.length != 1) { - $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text("One storage pool is needed for import."); - - validation.storagepools = false; - } else { - $("#validationwrapper-storagepools-import-storagepools").removeClass("has-error"); - $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text(""); - - validation.storagepools = true; - - pool.guid = pool.guid.join(" "); - pool.name = pool.name.join(" "); - } - - if (validation.storagepools && !$("#switch-storagepools-import-rename input").prop("checked")) { - if (pool.name.length == 0) { - $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text("Storage pool name can not be empty. New name is needed."); - - validation.name = false; - } else if (/^[a-zA-Z0-9-_.: ]*$/.test(pool.name) == false) { - $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text("Storage pool name contains invalid characters. New name is needed."); - - validation.name = false; - } else if (/^[0-9]/.test(pool.name)) { - $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text("Storage pool name can not begin with numerical characters. New name is needed."); - - validation.name = false; - } else if (/^[.]/.test(pool.name)) { - $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text("Storage pool name can not begin with a period (.). New name is needed."); - - validation.name = false; - } else if (/^[_]/.test(pool.name)) { - $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text("Storage pool name can not begin with an underscore (_). New name is needed."); - - validation.name = false; - } else if (/^[-]/.test(pool.name)) { - $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text("Storage pool name can not begin with a hypen (-). New name is needed."); - - validation.name = false; - } else if (/^[:]/.test(pool.name)) { - $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text("Storage pool name can not begin with an colon (:). New name is needed."); - - validation.name = false; - } else if (/^[ ]/.test(pool.name)) { - $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text("Storage pool name can not begin with whitespace ( ). New name is needed."); - - validation.name = false; - } else if (/[ ]$/.test(pool.name)) { - $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text("Storage pool name can not end with whitespace ( ). New name is needed."); - - validation.name = false; - } else if (/^c[0-9]|^log|^mirror|^raidz|^raidz1|^raidz2|^raidz3|^spare/.test(pool.name)) { - $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text("Storage pool name can not begin with a reserved name. New name is needed."); - - validation.name = false; - } else { - validation.name = true; - } - - if (!validation.name && !$("#switch-storagepools-import-rename input").prop("checked")) { - $("#switch-storagepools-import-rename input").click(); - $("#input-storagepools-import-namenew").focus(); - } - } - - if (validation.storagepools && !validation.name && $("#switch-storagepools-import-rename input").prop("checked") && $("#input-storagepools-import-namenew").val().length >= 2) { - validation.name = true; - } - - if ($("#switch-storagepools-import-rename input").prop("checked")) { - if ($("#input-storagepools-import-namenew").val().length == 0) { - $("#helpblock-storagepools-import-namenew").addClass("has-error").removeClass("hidden").text("New name can not be empty."); - - validation.namenew = false; - } else if (/^[a-zA-Z0-9-_.: ]*$/.test($("#input-storagepools-import-namenew").val()) == false) { - $("#helpblock-storagepools-import-namenew").addClass("has-error").removeClass("hidden").text("New name contains invalid characters."); - - validation.namenew = false; - } else if (/^[0-9]/.test($("#input-storagepools-import-namenew").val())) { - $("#helpblock-storagepools-import-namenew").addClass("has-error").removeClass("hidden").text("New name can not begin with numerical characters."); - - validation.namenew = false; - } else if (/^[.]/.test($("#input-storagepools-import-namenew").val())) { - $("#helpblock-storagepools-import-namenew").addClass("has-error").removeClass("hidden").text("New name can not begin with a period (.)."); - - validation.namenew = false; - } else if (/^[_]/.test($("#input-storagepools-import-namenew").val())) { - $("#helpblock-storagepools-import-namenew").addClass("has-error").removeClass("hidden").text("New name can not begin with an underscore (_)."); - - validation.namenew = false; - } else if (/^[-]/.test($("#input-storagepools-import-namenew").val())) { - $("#helpblock-storagepools-import-namenew").addClass("has-error").removeClass("hidden").text("New name can not begin with a hypen (-)."); - - validation.namenew = false; - } else if (/^[:]/.test($("#input-storagepools-import-namenew").val())) { - $("#helpblock-storagepools-import-namenew").addClass("has-error").removeClass("hidden").text("New name can not begin with an colon (:)."); - - validation.namenew = false; - } else if (/^[ ]/.test($("#input-storagepools-import-namenew").val())) { - $("#helpblock-storagepools-import-namenew").addClass("has-error").removeClass("hidden").text("New name can not begin with whitespace ( )."); - - validation.namenew = false; - } else if (/[ ]$/.test($("#input-storagepools-import-namenew").val())) { - $("#helpblock-storagepools-import-namenew").addClass("has-error").removeClass("hidden").text("New name can not end with whitespace ( )."); - - validation.namenew = false; - } else if (/^c[0-9]|^log|^mirror|^raidz|^raidz1|^raidz2|^raidz3|^spare/.test($("#input-storagepools-import-namenew").val())) { - $("#helpblock-storagepools-import-namenew").addClass("has-error").removeClass("hidden").text("New name can not begin with a reserved name."); - - validation.namenew = false; - } else { - $("#validationwrapper-storagepools-import-namenew").removeClass("has-error"); - $("#helpblock-storagepools-import-namenew").addClass("hidden").text(""); - - validation.namenew = true; - } - } else { - $("#validationwrapper-storagepools-import-namenew").removeClass("has-error"); - $("#helpblock-storagepools-import-namenew").removeClass("has-error").addClass("hidden").text(""); - - validation.namenew = true; - } - - if (/^[a-zA-Z0-9-_.:/ ]*$/.test($("#input-storagepools-import-altroot").val()) == false) { - $("#helpblock-storagepools-import-altroot").addClass("has-error").removeClass("hidden").text("Alt Root contains invalid characters."); - - validation.altroot = false; - } else if ($("#input-storagepools-import-altroot").val() && /^[/]/.test($("#input-storagepools-import-altroot").val()) == false) { - $("#helpblock-storagepools-import-altroot").addClass("has-error").removeClass("hidden").text("Alt Root is an absolute path and must begin with a forward slash (/)."); - - validation.altroot = false; - } else if (/^[.]/.test($("#input-storagepools-import-altroot").val())) { - $("#helpblock-storagepools-import-altroot").addClass("has-error").removeClass("hidden").text("Alt Root can not begin with a period (.)."); - - validation.altroot = false; - } else if (/[.]$/.test($("#input-storagepools-import-altroot").val())) { - $("#helpblock-storagepools-import-altroot").addClass("has-error").removeClass("hidden").text("Alt Root can not end with a period (.)."); - - validation.altroot = false; - } else if (/[/][.][/]/g.test($("#input-storagepools-import-altroot").val())) { - $("#helpblock-storagepools-import-altroot").addClass("has-error").removeClass("hidden").text("Alt Root can not contain a period as a sub directory (/./)."); - - validation.altroot = false; - } else if (/[/][.][.][/]/g.test($("#input-storagepools-import-altroot").val())) { - $("#helpblock-storagepools-import-altroot").addClass("has-error").removeClass("hidden").text("Alt Root can not contain a double period as a sub directory (/../)."); - - validation.altroot = false; - } else if (/[/][/]/g.test($("#input-storagepools-import-altroot").val())) { - $("#helpblock-storagepools-import-altroot").addClass("has-error").removeClass("hidden").text("Alt Root can not contain double forward slashes (//)."); - - validation.altroot = false; - } else if (/[.][.]/g.test($("#input-storagepools-import-altroot").val())) { - $("#helpblock-storagepools-import-altroot").addClass("has-error").removeClass("hidden").text("Alt Root can not contain a double period (..)."); - - validation.altroot = false; - } else if (/^[ ]/.test($("#input-storagepools-import-altroot").val())) { - $("#helpblock-storagepools-import-altroot").addClass("has-error").removeClass("hidden").text("Alt Root can not begin with whitespace ( )."); - - validation.altroot = false; - } else if (/[ ]$/.test($("#input-storagepools-import-altroot").val())) { - $("#helpblock-storagepools-import-altroot").addClass("has-error").removeClass("hidden").text("Alt Root can not end with whitespace ( )."); - - validation.altroot = false; - } else { - $("#validationwrapper-storagepools-import-altroot").removeClass("has-error"); - $("#helpblock-storagepools-import-altroot").addClass("hidden").text(""); - - validation.altroot = true; - } - - if (!validation.altroot || !validation.name || !validation.namenew || !validation.storagepools) { - if (!validation.name || !validation.storagepools) { - $("#validationwrapper-storagepools-import-storagepools").addClass("has-error"); - } - if (!validation.namenew) { - $("#validationwrapper-storagepools-import-namenew").addClass("has-error"); - $("#input-storagepools-import-namenew").focus(); - } - if (!validation.altroot) { - $("#validationwrapper-storagepools-import-altroot").addClass("has-error"); - $("#input-storagepools-import-altroot").focus(); - } - - $("#spinner-storagepools-import").addClass("hidden"); - $(this).prop("disabled", false); - } - - if (validation.altroot && validation.name && validation.namenew && validation.storagepools) { - disks.identifier = $("#btnspan-storagepools-import-disks-identifier").attr("data-field-value"); - - filesystem.mount = $("#switch-storagepools-import-mount input").prop("checked"); - filesystem.selinux = $("#switch-storagepools-import-selinux input").prop("checked"); - - pool.altroot = $("#input-storagepools-import-altroot").val(); - pool.destroyed = $("#switch-storagepools-import-destroyed input").prop("checked"); - pool.force = $("#switch-storagepools-import-force input").prop("checked"); - pool.ignoremissinglog = $("#switch-storagepools-import-ignoremissinglog input").prop("checked"); - pool.namenew = ($("#switch-storagepools-import-rename input").prop("checked") ? $("#input-storagepools-import-namenew").val() : ""); - pool.readonly = $("#switch-storagepools-import-readonly input").prop("checked"); - pool.recoverymode = $("#switch-storagepools-import-recoverymode input").prop("checked"); - - FnStoragePoolImport({ name: pool.name, altroot: pool.altroot, destroyed: pool.destroyed, force: pool.force, guid: pool.guid, ignoremissinglog: pool.ignoremissinglog, namenew: pool.namenew, readonly: pool.readonly, recoverymode: pool.recoverymode }, { mount: filesystem.mount, selinux: filesystem.selinux }, { id: { blockdevice: disks.id.blockdevice, disk: disks.id.disk, path: disks.id.path, vdev: disks.id.vdev }, identifier: disks.identifier }); - } - }); - - $("#dropdown-storagepools-import-disks-identifier").on("click", "li a", function () { - $("#btnspan-storagepools-import-disks-identifier").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -//#endregion - -//#region Modal Storage Pool - -function FnModalStoragePoolConfigure(pool = { name, id, boot: false, guid, readonly: false, root: false }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-configure-` + pool.id + `").on("click", function () { - FnModalStoragePoolConfigureContent({ name: "` + pool.name + `", id: "` + pool.id + `", guid: "` + pool.guid + `", readonly: ` + pool.readonly + ` }, { id: $("#modal-storagepool-configure-` + pool.id + `") }); - FnStoragePoolConfigurationGet({ name: "` + pool.name + `", id: "` + pool.id + `", boot: ` + pool.boot + `, root: ` + pool.root + ` }, { name: "storagepool-configure", id: "` + pool.id + `" }); - }); - \x3C/script> - `; - - $("#modals-storagepool-" + pool.id).append(modal.window); -} - -function FnModalStoragePoolConfigureContent(pool = { name, id, guid, readonly: false }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#switch-storagepool-configure-multihost-` + pool.id + ` input").on("click", function () { - FnSystemHostIdGet({ name: "storagepool-configure", id: "` + pool.id + `" }); - - if (!$(this).prop("checked")) { - $("#controllabel-storagepool-configure-hostid-` + pool.id + `").addClass("hidden"); - $("#validationwrapper-storagepool-configure-hostid-` + pool.id + `").addClass("hidden"); - } - }); - - $("#btn-storagepool-configure-apply-` + pool.id + `").on("click", function () { - $("#spinner-storagepool-configure-` + pool.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let modal = { - id: "" - }; - let pool = { - ashift: 0, - autoexpand: "", - autoreplace: "", - autotrim: "", - comment: "", - delegation: "", - failmode: "", - listsnapshots: "", - multihost: "" - }; - let system = { - hostid: false - }; - let validation = { - comment: false - }; - - if ($("#input-storagepool-configure-comment-` + pool.id + `").val().length > 32) { - $("#helpblock-storagepool-configure-comment-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Comment can not be longer than 32 characters."); - - validation.comment = false; - } else if (/^[ -~]*$/.test($("#input-storagepool-configure-comment-` + pool.id + `").val()) == false) { - $("#helpblock-storagepool-configure-comment-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Comment contains invalid characters."); - - validation.comment = false; - } else { - $("#validationwrapper-storagepool-configure-comment-` + pool.id + `").removeClass("has-error"); - $("#helpblock-storagepool-configure-comment-` + pool.id + `").addClass("hidden").text(""); - - validation.comment = true; - } - - if (!validation.comment) { - $("#validationwrapper-storagepool-configure-comment-` + pool.id + `").addClass("has-error"); - $("#input-storagepool-configure-comment-` + pool.id + `").focus(); - - $("#spinner-storagepool-configure-` + pool.id + `").addClass("hidden"); - $(this).prop("disabled", false); - } - - if (validation.comment) { - modal.id = $("#modal-storagepool-configure-` + pool.id + `"); - - pool.ashift = ($("#btnspan-storagepool-configure-ashift-` + pool.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-configure-ashift-` + pool.id + `").attr("data-field-value-new") : null); - pool.autoexpand = ($("#switch-storagepool-configure-autoexpand-` + pool.id + ` input").prop("checked") ? "on" : "off"); - pool.autoreplace = ($("#switch-storagepool-configure-autoreplace-` + pool.id + ` input").prop("checked") ? "on" : "off"); - pool.autotrim = ($("#switch-storagepool-configure-autotrim-` + pool.id + ` input").prop("checked") ? "on" : "off"); - pool.comment = $("#input-storagepool-configure-comment-` + pool.id + `").val(); - pool.delegation = ($("#switch-storagepool-configure-delegation-` + pool.id + ` input").prop("checked") ? "on" : "off"); - pool.failmode = ($("#btnspan-storagepool-configure-failmode-` + pool.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-configure-failmode-` + pool.id + `").attr("data-field-value-new") : null); - pool.listsnapshots = ($("#switch-storagepool-configure-listsnapshots-` + pool.id + ` input").prop("checked") ? "on" : "off"); - pool.multihost = ($("#switch-storagepool-configure-multihost-` + pool.id + ` input").prop("checked") ? "on" : "off"); - - if (!$("#validationwrapper-storagepool-configure-hostid-` + pool.id + `").hasClass("hidden")) { - system.hostid = $("#btnspan-storagepool-configure-hostid-` + pool.id + `").attr("data-field-value"); - } else { - if ($("#btnspan-storagepool-configure-hostid-` + pool.id + `").attr("data-field-value") == "missing") { //Host ID is missing - Generate Host ID before disabling multihost property to avoid error - system.hostid = "libc"; - } - } - - //Set values to null if unchanged, so that they are skipped in the configure function - if (pool.ashift == $("#btnspan-storagepool-configure-ashift-` + pool.id + `").attr("data-field-value")) { - pool.ashift = null; - } - if (pool.autoexpand == $("#switch-storagepool-configure-autoexpand-` + pool.id + `").attr("data-field-value")) { - pool.autoexpand = null; - } - if (pool.autoreplace == $("#switch-storagepool-configure-autoreplace-` + pool.id + `").attr("data-field-value")) { - pool.autoreplace = null; - } - if (pool.autotrim == $("#switch-storagepool-configure-autotrim-` + pool.id + `").attr("data-field-value")) { - pool.autotrim = null; - } - if (pool.comment == $("#input-storagepool-configure-comment-` + pool.id + `").attr("data-field-value")) { - pool.comment = null; - } else if (pool.comment != $("#input-storagepool-configure-comment-` + pool.id + `").attr("data-field-value") && !pool.comment) { - pool.comment = "$empty"; - } - if (pool.failmode == $("#btnspan-storagepool-configure-failmode-` + pool.id + `").attr("data-field-value")) { - pool.failmode = null; - } - if (pool.delegation == $("#switch-storagepool-configure-delegation-` + pool.id + `").attr("data-field-value")) { - pool.delegation = null; - } - if (pool.listsnapshots == $("#switch-storagepool-configure-listsnapshots-` + pool.id + `").attr("data-field-value")) { - pool.listsnapshots = null; - } - if (pool.multihost == $("#switch-storagepool-configure-multihost-` + pool.id + `").attr("data-field-value")) { - pool.multihost = null; - } - - FnStoragePoolConfigure({ name: "` + pool.name + `", id: "` + pool.id + `", ashift: pool.ashift, autoexpand: pool.autoexpand, autoreplace: pool.autoreplace, autotrim: pool.autotrim, comment: pool.comment, delegation: pool.delegation, failmode: pool.failmode, listsnapshots: pool.listsnapshots, multihost: pool.multihost, readonly: ` + pool.readonly + ` }, { hostid: system.hostid }, { id: modal.id }); - } - }); - - $("#dropdown-storagepool-configure-ashift-` + pool.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-configure-ashift-` + pool.id + `").text($(this).text()).attr("data-field-value-new", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - - $("#dropdown-storagepool-configure-failmode-` + pool.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-configure-failmode-` + pool.id + `").text($(this).text()).attr("data-field-value-new", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - - $("#dropdown-storagepool-configure-hostid-` + pool.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-configure-hostid-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalStoragePoolConfigureFeatures(pool = { name, id, boot: false, readonly: false }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-configure-features-` + pool.id + `").on("click", function () { - FnModalStoragePoolConfigureFeaturesContent({ name: "` + pool.name + `", id: "` + pool.id + `", boot: ` + pool.boot + `, readonly: ` + pool.readonly + ` }, { id: $("#modal-storagepool-configure-features-` + pool.id + `") }); - FnStoragePoolConfigurationFeaturesGet({ name: "` + pool.name + `", id: "` + pool.id + `", boot: ` + pool.boot + ` }, { name: "storagepool-configure-features", id: "` + pool.id + `" }); - }); - \x3C/script> - `; - - $("#modals-storagepool-" + pool.id).append(modal.window); -} - -function FnModalStoragePoolConfigureFeaturesContent(pool = { name, id, boot: false, readonly: false }, modal = { id }) { - pool.version = $("#tr-storagepool-" + pool.id).attr("data-pool-version"); - - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("[id^=switch-storagepool-configure-features-][id$='-` + pool.id + `'] input").on("click", function () { - if ($(this).prop("checked") && $(this).parent().attr("data-field-value") == "disabled") { - $("#alert-storagepool-configure-features-compatibility-` + pool.id + `").removeClass("hidden"); - } - - FnModalStoragePoolConfigureFeaturesDependencies({ name: "` + pool.name + `", id: "` + pool.id + `" }, { switch: { id: $(this) } }); - }); - - $("#btn-storagepool-configure-features-apply-` + pool.id + `").on("click", function () { - $("#spinner-storagepool-configure-features-` + pool.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let modal = { - id: "" - }; - - let pool = { - feature: { - allocation_classes: ($("#switch-storagepool-configure-features-allocation_classes-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-allocation_classes-` + pool.id + ` input").prop("disabled") ? "enabled" : null), - async_destroy: ($("#switch-storagepool-configure-features-async_destroy-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-async_destroy-` + pool.id + ` input").prop("disabled") ? "enabled" : null), - bookmark_v2: ($("#switch-storagepool-configure-features-bookmark_v2-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-bookmark_v2-` + pool.id + ` input").prop("disabled") ? "enabled" : null), - bookmarks: ($("#switch-storagepool-configure-features-bookmarks-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-bookmarks-` + pool.id + ` input").prop("disabled") ? "enabled" : null), - device_removal: ($("#switch-storagepool-configure-features-device_removal-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-device_removal-` + pool.id + ` input").prop("disabled") ? "enabled" : null), - edonr: ($("#switch-storagepool-configure-features-edonr-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-edonr-` + pool.id + ` input").prop("disabled") ? "enabled" : null), - embedded_data: ($("#switch-storagepool-configure-features-embedded_data-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-embedded_data-` + pool.id + ` input").prop("disabled") ? "enabled" : null), - empty_bpobj: ($("#switch-storagepool-configure-features-empty_bpobj-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-empty_bpobj-` + pool.id + ` input").prop("disabled") ? "enabled" : null), - enabled_txg: ($("#switch-storagepool-configure-features-enabled_txg-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-enabled_txg-` + pool.id + ` input").prop("disabled") ? "enabled" : null), - encryption: ($("#switch-storagepool-configure-features-encryption-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-encryption-` + pool.id + ` input").prop("disabled") ? "enabled" : null), - extensible_dataset: ($("#switch-storagepool-configure-features-extensible_dataset-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-extensible_dataset-` + pool.id + ` input").prop("disabled") ? "enabled" : null), - filesystem_limits: ($("#switch-storagepool-configure-features-filesystem_limits-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-filesystem_limits-` + pool.id + ` input").prop("disabled") ? "enabled" : null), - hole_birth: ($("#switch-storagepool-configure-features-hole_birth-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-hole_birth-` + pool.id + ` input").prop("disabled") ? "enabled" : null), - large_blocks: ($("#switch-storagepool-configure-features-large_blocks-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-large_blocks-` + pool.id + ` input").prop("disabled") ? "enabled" : null), - large_dnode: ($("#switch-storagepool-configure-features-large_dnode-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-large_dnode-` + pool.id + ` input").prop("disabled") ? "enabled" : null), - lz4_compress: ($("#switch-storagepool-configure-features-lz4_compress-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-lz4_compress-` + pool.id + ` input").prop("disabled") ? "enabled" : null), - multi_vdev_crash_dump: ($("#switch-storagepool-configure-features-multi_vdev_crash_dump-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-multi_vdev_crash_dump-` + pool.id + ` input").prop("disabled") ? "enabled" : null), - obsolete_counts: ($("#switch-storagepool-configure-features-obsolete_counts-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-obsolete_counts-` + pool.id + ` input").prop("disabled") ? "enabled" : null), - project_quota: ($("#switch-storagepool-configure-features-project_quota-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-project_quota-` + pool.id + ` input").prop("disabled") ? "enabled" : null), - resilver_defer: ($("#switch-storagepool-configure-features-resilver_defer-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-resilver_defer-` + pool.id + ` input").prop("disabled") ? "enabled" : null), - sha512: ($("#switch-storagepool-configure-features-sha512-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-sha512-` + pool.id + ` input").prop("disabled") ? "enabled" : null), - skein: ($("#switch-storagepool-configure-features-skein-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-skein-` + pool.id + ` input").prop("disabled") ? "enabled" : null), - spacemap_histogram: ($("#switch-storagepool-configure-features-spacemap_histogram-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-spacemap_histogram-` + pool.id + ` input").prop("disabled") ? "enabled" : null), - spacemap_v2: ($("#switch-storagepool-configure-features-spacemap_v2-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-spacemap_v2-` + pool.id + ` input").prop("disabled") ? "enabled" : null), - userobj_accounting: ($("#switch-storagepool-configure-features-userobj_accounting-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-userobj_accounting-` + pool.id + ` input").prop("disabled") ? "enabled" : null), - zpool_checkpoint: ($("#switch-storagepool-configure-features-zpool_checkpoint-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-zpool_checkpoint-` + pool.id + ` input").prop("disabled") ? "enabled" : null) - } - }; - - FnStoragePoolConfigureFeatures({ name: "` + pool.name + `", id: "` + pool.id + `", feature: { allocation_classes: pool.feature.allocation_classes, async_destroy: pool.feature.async_destroy, bookmark_v2: pool.feature.bookmark_v2, bookmarks: pool.feature.bookmarks, device_removal: pool.feature.device_removal, edonr: pool.feature.edonr, embedded_data: pool.feature.embedded_data, empty_bpobj: pool.feature.empty_bpobj, enabled_txg: pool.feature.enabled_txg, encryption: pool.feature.encryption, extensible_dataset: pool.feature.extensible_dataset, filesystem_limits: pool.feature.filesystem_limits, hole_birth: pool.feature.hole_birth, large_blocks: pool.feature.large_blocks, large_dnode: pool.feature.large_dnode, lz4_compress: pool.feature.lz4_compress, multi_vdev_crash_dump: pool.feature.multi_vdev_crash_dump, obsolete_counts: pool.feature.obsolete_counts, project_quota: pool.feature.project_quota, resilver_defer: pool.feature.resilver_defer, sha512: pool.feature.sha512, skein: pool.feature.skein, spacemap_histogram: pool.feature.spacemap_histogram, spacemap_v2: pool.feature.spacemap_v2, userobj_accounting: pool.feature.userobj_accounting, zpool_checkpoint: pool.feature.zpool_checkpoint }, readonly: ` + pool.readonly + ` }, { id: $("#modal-storagepool-configure-features-` + pool.id + `") }); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalStoragePoolConfigureFeaturesDependencies(pool = { name, id }, modal = { switch: { id } }) { - if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-bookmarks-" + pool.id) { - if ($("#switch-storagepool-configure-features-bookmarks-" + pool.id + " input").prop("checked")) { - if (!$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").click(); - } - } else { - if ($("#switch-storagepool-configure-features-bookmark_v2-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-bookmark_v2-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-bookmark_v2-" + pool.id + " input").click(); - } - if ($("#switch-storagepool-configure-features-encryption-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-encryption-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-encryption-" + pool.id + " input").click(); - } - } - } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-bookmark_v2-" + pool.id) { - if ($("#switch-storagepool-configure-features-bookmark_v2-" + pool.id + " input").prop("checked")) { - if (!$("#switch-storagepool-configure-features-bookmarks-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-bookmarks-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-bookmarks-" + pool.id + " input").click(); - } - if (!$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").click(); - } - } else { - if ($("#switch-storagepool-configure-features-encryption-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-encryption-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-encryption-" + pool.id + " input").click(); - } - } - } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-device_removal-" + pool.id) { - if (!$("#switch-storagepool-configure-features-device_removal-" + pool.id + " input").prop("checked")) { - if ($("#switch-storagepool-configure-features-obsolete_counts-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-obsolete_counts-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-obsolete_counts-" + pool.id + " input").click(); - } - } - } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-edonr-" + pool.id) { - if ($("#switch-storagepool-configure-features-edonr-" + pool.id + " input").prop("checked")) { - if (!$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").click(); - } - } - } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-enabled_txg-" + pool.id) { - if (!$("#switch-storagepool-configure-features-enabled_txg-" + pool.id + " input").prop("checked")) { - if ($("#switch-storagepool-configure-features-hole_birth-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-hole_birth-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-hole_birth-" + pool.id + " input").click(); - } - } - } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-encryption-" + pool.id) { - if ($("#switch-storagepool-configure-features-encryption-" + pool.id + " input").prop("checked")) { - if (!$("#switch-storagepool-configure-features-bookmarks-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-bookmarks-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-bookmarks-" + pool.id + " input").click(); - } - if (!$("#switch-storagepool-configure-features-bookmark_v2-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-bookmark_v2-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-bookmark_v2-" + pool.id + " input").click(); - } - if (!$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").click(); - } - } - } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-extensible_dataset-" + pool.id) { - if (!$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("checked")) { - if ($("#switch-storagepool-configure-features-bookmarks-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-bookmarks-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-bookmarks-" + pool.id + " input").click(); - } - if ($("#switch-storagepool-configure-features-bookmark_v2-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-bookmark_v2-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-bookmark_v2-" + pool.id + " input").click(); - } - if ($("#switch-storagepool-configure-features-edonr-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-edonr-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-edonr-" + pool.id + " input").click(); - } - if ($("#switch-storagepool-configure-features-encryption-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-encryption-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-encryption-" + pool.id + " input").click(); - } - if ($("#switch-storagepool-configure-features-filesystem_limits-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-filesystem_limits-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-filesystem_limits-" + pool.id + " input").click(); - } - if ($("#switch-storagepool-configure-features-large_blocks-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-large_blocks-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-large_blocks-" + pool.id + " input").click(); - } - if ($("#switch-storagepool-configure-features-large_dnode-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-large_dnode-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-large_dnode-" + pool.id + " input").click(); - } - if ($("#switch-storagepool-configure-features-project_quota-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-project_quota-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-project_quota-" + pool.id + " input").click(); - } - if ($("#switch-storagepool-configure-features-sha512-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-sha512-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-sha512-" + pool.id + " input").click(); - } - if ($("#switch-storagepool-configure-features-skein-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-skein-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-skein-" + pool.id + " input").click(); - } - if ($("#switch-storagepool-configure-features-userobj_accounting-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-userobj_accounting-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-userobj_accounting-" + pool.id + " input").click(); - } - } - } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-filesystem_limits-" + pool.id) { - if ($("#switch-storagepool-configure-features-filesystem_limits-" + pool.id + " input").prop("checked")) { - if (!$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").click(); - } - } - } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-hole_birth-" + pool.id) { - if ($("#switch-storagepool-configure-features-hole_birth-" + pool.id + " input").prop("checked")) { - if (!$("#switch-storagepool-configure-features-enabled_txg-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-enabled_txg-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-enabled_txg-" + pool.id + " input").click(); - } - } - } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-large_blocks-" + pool.id) { - if ($("#switch-storagepool-configure-features-large_blocks-" + pool.id + " input").prop("checked")) { - if (!$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").click(); - } - } - } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-large_dnode-" + pool.id) { - if ($("#switch-storagepool-configure-features-large_dnode-" + pool.id + " input").prop("checked")) { - if (!$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").click(); - } - } - } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-obsolete_counts-" + pool.id) { - if ($("#switch-storagepool-configure-features-obsolete_counts-" + pool.id + " input").prop("checked")) { - if (!$("#switch-storagepool-configure-features-device_removal-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-device_removal-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-device_removal-" + pool.id + " input").click(); - } - } - } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-project_quota-" + pool.id) { - if ($("#switch-storagepool-configure-features-project_quota-" + pool.id + " input").prop("checked")) { - if (!$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").click(); - } - } - } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-sha512-" + pool.id) { - if ($("#switch-storagepool-configure-features-sha512-" + pool.id + " input").prop("checked")) { - if (!$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").click(); - } - } - } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-skein-" + pool.id) { - if ($("#switch-storagepool-configure-features-skein-" + pool.id + " input").prop("checked")) { - if (!$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").click(); - } - } - } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-userobj_accounting-" + pool.id) { - if ($("#switch-storagepool-configure-features-userobj_accounting-" + pool.id + " input").prop("checked")) { - if (!$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("disabled")) { - $("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").click(); - } - } - } -} - -function FnModalStoragePoolDestroy(pool = { name, id, altroot: false }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-destroy-` + pool.id + `").on("click", function () { - FnModalStoragePoolDestroyContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + ` }, { id: $("#modal-storagepool-destroy-` + pool.id + `") }); - }); - \x3C/script> - `; - - $("#modals-storagepool-" + pool.id).append(modal.window); -} - -function FnModalStoragePoolDestroyContent(pool = { name, id, altroot: false }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-destroy-apply-` + pool.id + `").on("click", function () { - $("#spinner-storagepool-destroy-` + pool.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let pool = { - force: $("#switch-storagepool-destroy-force-` + pool.id + ` input").prop("checked"), - labelclear: $("#switch-storagepool-destroy-labelclear-` + pool.id + ` input").prop("checked") - }; - let samba = { - restart: $("#switch-storagepool-destroy-samba-restart-` + pool.id + ` input").prop("checked") - }; - - FnStoragePoolDestroy({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, force: pool.force, labelclear: pool.labelclear }, { restart: samba.restart }); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalStoragePoolExport(pool = { name, id, altroot: false, readonly: false }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-export-` + pool.id + `").on("click", function () { - FnModalStoragePoolExportContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { id: $("#modal-storagepool-export-` + pool.id + `") }); - }); - \x3C/script> - `; - - $("#modals-storagepool-" + pool.id).append(modal.window); -} - -function FnModalStoragePoolExportContent(pool = { name, id, altroot: false, readonly: false }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-export-apply-` + pool.id + `").on("click", function () { - $("#spinner-storagepool-export-` + pool.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let pool = { - force: $("#switch-storagepool-export-force-` + pool.id + ` input").prop("checked") - }; - let samba = { - restart: $("#switch-storagepool-export-samba-restart-` + pool.id + ` input").prop("checked") - }; - - FnStoragePoolExport({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, force: pool.force, readonly: ` + pool.readonly + ` }, { restart: samba.restart }); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -//#endregion - -//#region Modal File Systems - -function FnModalFileSystemsCreate(pool = { name, id, altroot: false, feature: { allocation_classes: true, edonr: true, encryption: true, large_blocks: true, large_dnode: true, lz4_compress: true, sha512: true, skein: true } }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-filesystems-create-` + pool.id + `").on("click", function () { - FnModalFileSystemsCreateContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, feature: { allocation_classes: ` + pool.feature.allocation_classes + `, edonr: ` + pool.feature.edonr + `, encryption: ` + pool.feature.encryption + `, large_blocks: ` + pool.feature.large_blocks + `, large_dnode: ` + pool.feature.large_dnode + `, lz4_compress: ` + pool.feature.lz4_compress + `, sha512: ` + pool.feature.sha512 + `, skein: ` + pool.feature.skein + ` } }, { id: $("#modal-storagepool-filesystems-create-` + pool.id + `") }); - FnFileSystemsNamesGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { existing: { name: null, clone: false, encryption: false, encryptionroot: null, origin: null}, override: true }, { dropdown: { id: $("#dropdown-storagepool-filesystems-create-parentfilesystem-` + pool.id + `"), selected: "` + pool.name + `" } }); - FnFileSystemConfigurationInheritedGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + pool.name + `" }, { name: "storagepool-filesystems-create", id: "` + pool.id + `" }); - - $("#input-storagepool-filesystems-create-quota-` + pool.id + `").val("0"); - $("#validationwrapper-storagepool-filesystems-create-quota-` + pool.id + ` .min-slider-handle").attr("tabindex", "15"); - setTimeout(function() { - $("#input-storagepool-filesystems-create-name-` + pool.id + `").focus(); - }, 600); - }); - \x3C/script> - `; - - $("#modals-storagepool-filesystems-" + pool.id).append(modal.window); -} - -function FnModalFileSystemsCreateContent(pool = { name, id, altroot: false, feature: { allocation_classes: true, edonr: true, encryption: true, large_blocks: true, large_dnode: true, lz4_compress: true, sha512: true, skein: true } }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#input-storagepool-filesystems-create-quota-` + pool.id + `").tooltip({ trigger: "manual" }) - .on("keyup", function (element) { - let $this = $(this); - let sd = $this.siblings("[data-provide=slider]").slider(); - - if ($this.val().trim() && !$.isNumeric(this.value)) { - this.value = sd.slider("getValue"); - } - }) - .on("keypress blur", function (element) { - if (element.which == 13 || element.type === "blur") { - element.preventDefault(); - - let $this = $(this); - let sd = $this.siblings("[data-provide=slider]").slider(); - let max = sd.slider("getAttribute", "max"); - let min = sd.slider("getAttribute", "min"); - - if (!$.isNumeric(this.value) || (this.value > max || this.value < min)) { - let warningInfo = $.isNumeric(this.value) ? "Valid value should be between " + min + " and " + max : "Valid value should be number"; - $this.attr("data-original-title", warningInfo).tooltip("show").addClass("warning"); - this.value = sd.slider("getValue"); - setTimeout(function () { - $this.tooltip("hide"); - }, 3000); - } else { - if ($this.is(".warning")) { - $this.tooltip("hide"); - } - - this.value = $this.val().trim(); - sd.slider("setValue", this.value); - } - } - }) - .siblings("[data-provide=slider]").each(function () { - $("#input-storagepool-filesystems-create-quota-` + pool.id + `").val(this.value); - $(this).slider().on("change", function (element) { - $("#input-storagepool-filesystems-create-quota-` + pool.id + `").val(element.value.newValue); - }); - }); - - $("#input-storagepool-filesystems-create-quota-` + pool.id + `").on("change textInput input", function (element) { - if ($(this).val() > 1000) { //Force reset to maximum allowed value - $(this).val(1000); - } else if ($(this).val() < 0) { //Force reset to minimum allowed value - $(this).val(0); - } - - if ($.isNumeric($(this).val())) { - $("#slider-storagepool-filesystems-create-quota-` + pool.id + `").slider("setValue", $(this).val()); - } - }); - - $("#switch-storagepool-filesystems-create-encryption-` + pool.id + ` input").on("click", function () { - $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").removeClass("has-error").addClass("hidden").text(""); - $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").removeClass("has-error").addClass("hidden").text(""); - - if ($(this).prop("checked")) { - $("#controllabel-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").removeClass("hidden"); - $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").removeClass("hidden"); - $("#controllabel-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").removeClass("hidden"); - $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").removeClass("hidden"); - $("#controllabel-storagepool-filesystems-create-encryption-cipher-` + pool.id + `").removeClass("hidden"); - $("#validationwrapper-storagepool-filesystems-create-encryption-cipher-` + pool.id + `").removeClass("hidden"); - } else { - $("#controllabel-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").addClass("hidden"); - $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").addClass("hidden"); - $("#input-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").val(""); - $("#controllabel-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").addClass("hidden"); - $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").addClass("hidden"); - $("#input-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").val(""); - $("#controllabel-storagepool-filesystems-create-encryption-cipher-` + pool.id + `").addClass("hidden"); - $("#validationwrapper-storagepool-filesystems-create-encryption-cipher-` + pool.id + `").addClass("hidden"); - } - }); - - $("#switch-storagepool-filesystems-create-sharenfs-` + pool.id + ` input").on("click", function () { - $("#validationwrapper-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").removeClass("has-error").addClass("hidden").text(""); - - if ($(this).prop("checked")) { - $("#controllabel-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").removeClass("hidden"); - $("#validationwrapper-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").removeClass("hidden"); - - FnSystemNfsVersionGet({ alert: { id: $("#alert-storagepool-filesystems-create-sharenfs-options-` + pool.id + `") } }); - } else { - $("#validationwrapper-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").addClass("hidden"); - $("#controllabel-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").addClass("hidden"); - } - }); - - $("#btn-storagepool-filesystems-create-apply-` + pool.id + `").on("click", function () { - $("#spinner-storagepool-filesystems-create-` + pool.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let filesystem = { - name: "", - id: "", - atime: "", - casesensitivity: "", - cipher: "", - compression: "", - dedup: "", - dnodesize: "", - encryption: "", - passphrase: "", - quota: "none", - readonly: "", - recordsize: "", - selinux: "", - sharesmb: "", - special_small_blocks: "", - xattr: "" - }; - let validation = { - encryption: false, - name: false, - sharenfs: false - }; - - if ($("#input-storagepool-filesystems-create-name-` + pool.id + `").val().length == 0) { - $("#helpblock-storagepool-filesystems-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not be empty."); - - validation.name = false; - } else if (/^[a-zA-Z0-9-_.: ]*$/.test($("#input-storagepool-filesystems-create-name-` + pool.id + `").val()) == false) { - $("#helpblock-storagepool-filesystems-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name contains invalid characters."); - - validation.name = false; - } else if (/^[.]/.test($("#input-storagepool-filesystems-create-name-` + pool.id + `").val())) { - $("#helpblock-storagepool-filesystems-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a period (.)."); - - validation.name = false; - } else if (/^[_]/.test($("#input-storagepool-filesystems-create-name-` + pool.id + `").val())) { - $("#helpblock-storagepool-filesystems-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with an underscore (_)."); - - validation.name = false; - } else if (/^[-]/.test($("#input-storagepool-filesystems-create-name-` + pool.id + `").val())) { - $("#helpblock-storagepool-filesystems-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a hypen (-)."); - - validation.name = false; - } else if (/^[:]/.test($("#input-storagepool-filesystems-create-name-` + pool.id + `").val())) { - $("#helpblock-storagepool-filesystems-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with an colon (:)."); - - validation.name = false; - } else if (/^[ ]/.test($("#input-storagepool-filesystems-create-name-` + pool.id + `").val())) { - $("#helpblock-storagepool-filesystems-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with whitespace ( )."); - - validation.name = false; - } else if (/[ ]$/.test($("#input-storagepool-filesystems-create-name-` + pool.id + `").val())) { - $("#helpblock-storagepool-filesystems-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not end with whitespace ( )."); - - validation.name = false; - } else { - $("#validationwrapper-storagepool-filesystems-create-name-` + pool.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystems-create-name-` + pool.id + `").addClass("hidden").text(""); - - validation.name = true; - } - if ($("#switch-storagepool-filesystems-create-encryption-` + pool.id + ` input").prop("checked")) { - if ($("#input-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").val().length == 0 && $("#switch-storagepool-filesystems-create-encryption-` + pool.id + ` input").prop("disabled")) { - $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").removeClass("has-error").addClass("hidden").text(""); - $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").removeClass("has-error").addClass("hidden").text(""); - - validation.encryption = true; - } else if ($("#input-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").val().length == 0) { - $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").addClass("has-error"); - $("#helpblock-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Passphrase can not be empty."); - $("#input-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").focus(); - - validation.encryption = false; - } else if ($("#input-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").val().length < 8) { - $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").addClass("has-error"); - $("#helpblock-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Passphrase requires a minimum of 8 characters."); - $("#input-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").focus(); - - validation.encryption = false; - } else if (/^[a-zA-Z0-9-_. \`~!@#$%^\(\)+\\[\\]{}:',/?]*$/.test($("#input-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").val()) == false) { - $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").addClass("has-error"); - $("#helpblock-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Passphrase contains invalid characters."); - $("#input-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").focus(); - - validation.encryption = false; - } else if ($("#input-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").val().length < 8 || $("#input-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").val() != $("#input-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").val()) { - $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").removeClass("has-error").removeClass("hidden").text(""); - $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").addClass("has-error"); - $("#helpblock-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Passphrase does not match"); - $("#input-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").focus(); - - validation.encryption = false; - } else { - $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").removeClass("has-error").addClass("hidden").text(""); - $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").removeClass("has-error").addClass("hidden").text(""); - - validation.encryption = true; - } - } else { - validation.encryption = true; - } - - if ($("#switch-storagepool-filesystems-create-sharenfs-` + pool.id + ` input").prop("checked")) { - if (/^[a-zA-Z0-9-_.:/@#+=!&*(), ]*$/.test($("#input-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").val()) == false) { - $("#validationwrapper-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").addClass("has-error"); - $("#helpblock-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").addClass("has-error").removeClass("hidden").text("NFS Share options contain invalid characters."); - $("#input-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").focus(); - - validation.sharenfs = false; - } else { - validation.sharenfs = true; - } - } else { - validation.sharenfs = true; - } - - if (!validation.name || !validation.encryption || !validation.sharenfs) { - if (!validation.name) { - $("#validationwrapper-storagepool-filesystems-create-name-` + pool.id + `").addClass("has-error"); - $("#input-storagepool-filesystems-create-name-` + pool.id + `").focus(); - } - - $("#spinner-storagepool-filesystems-create-` + pool.id + `").addClass("hidden"); - $(this).prop("disabled", false); - } - - if (validation.name && validation.encryption && validation.sharenfs) { - filesystem.atime = $("#btnspan-storagepool-filesystems-create-atime-` + pool.id + `").attr("data-field-value"); - filesystem.casesensitivity = $("#btnspan-storagepool-filesystems-create-casesensitivity-` + pool.id + `").attr("data-field-value"); - filesystem.cipher = $("#btnspan-storagepool-filesystems-create-encryption-cipher-` + pool.id + `").attr("data-field-value"); - filesystem.compression = $("#btnspan-storagepool-filesystems-create-compression-` + pool.id + `").attr("data-field-value"); - filesystem.dedup = $("#btnspan-storagepool-filesystems-create-dedup-` + pool.id + `").attr("data-field-value"); - filesystem.dnodesize = $("#btnspan-storagepool-filesystems-create-dnodesize-` + pool.id + `").attr("data-field-value"); - filesystem.encryption = $("#switch-storagepool-filesystems-create-encryption-` + pool.id + ` input").prop("checked"); - filesystem.name = $("#btnspan-storagepool-filesystems-create-parentfilesystem-` + pool.id + `").attr("data-field-value") + "/" + $("#input-storagepool-filesystems-create-name-` + pool.id + `").val(); - filesystem.id = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: filesystem.name, attribute: true }); - filesystem.passphrase = $("#input-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").val(); - filesystem.readonly = ($("#switch-storagepool-filesystems-create-readonly-` + pool.id + ` input").prop("checked") ? "on" : "off"); - filesystem.recordsize = $("#btnspan-storagepool-filesystems-create-recordsize-` + pool.id + `").attr("data-field-value"); - filesystem.selinux = ($("#switch-storagepool-filesystems-create-selinux-` + pool.id + ` input").prop("checked") ? "on" : "off"); - filesystem.sharesmb = ($("#switch-storagepool-filesystems-create-samba-share-` + pool.id + ` input").prop("checked") ? "on" : "off"); - filesystem.special_small_blocks = $("#btnspan-storagepool-filesystems-create-special_small_blocks-` + pool.id + `").attr("data-field-value"); - filesystem.xattr = $("#btnspan-storagepool-filesystems-create-xattr-` + pool.id + `").attr("data-field-value"); - - if ($("#switch-storagepool-filesystems-create-sharenfs-` + pool.id + ` input").prop("checked")) { - if ($("#input-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").val().toLowerCase() == "on" || $("#input-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").val() == "sec=sys,rw,crossmnt,no_subtree_check,no_root_squash" || !$("#input-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").val()) { - filesystem.sharenfs = "on"; - } else { - filesystem.sharenfs = $("#input-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").val(); - } - } else { - filesystem.sharenfs = "off"; - } - - if ($("#input-storagepool-filesystems-create-quota-` + pool.id + `").val() > 0) { //Remove friendly text so final value is sent - filesystem.quota = $("#input-storagepool-filesystems-create-quota-` + pool.id + `").val() + $("#btnspan-storagepool-filesystems-create-quota-` + pool.id + `").attr("data-field-value").replace(/iB$/g, ""); - } else { - filesystem.quota = "none"; - } - - FnFileSystemCreate({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + ` }, { name: filesystem.name, id: filesystem.id, atime: filesystem.atime, casesensitivity: filesystem.casesensitivity, cipher: filesystem.cipher, compression: filesystem.compression, dedup: filesystem.dedup, dnodesize: filesystem.dnodesize, encryption: filesystem.encryption, passphrase: filesystem.passphrase, quota: filesystem.quota, readonly: filesystem.readonly, recordsize: filesystem.recordsize, selinux: filesystem.selinux, sharenfs: filesystem.sharenfs, sharesmb: filesystem.sharesmb, special_small_blocks: filesystem.special_small_blocks, xattr: filesystem.xattr }); - } - }); - - $("#dropdown-storagepool-filesystems-create-parentfilesystem-` + pool.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-filesystems-create-parentfilesystem-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - - FnFileSystemConfigurationInheritedGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: $(this).text() }, { name: "storagepool-filesystems-create", id: "` + pool.id + `" }); - }); - - $("#dropdown-storagepool-filesystems-create-atime-` + pool.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-filesystems-create-atime-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - - $("#dropdown-storagepool-filesystems-create-casesensitivity-` + pool.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-filesystems-create-casesensitivity-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - - $("#dropdown-storagepool-filesystems-create-compression-` + pool.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-filesystems-create-compression-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - - $("#dropdown-storagepool-filesystems-create-dedup-` + pool.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-filesystems-create-dedup-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - - $("#dropdown-storagepool-filesystems-create-dnodesize-` + pool.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-filesystems-create-dnodesize-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - - $("#dropdown-storagepool-filesystems-create-encryption-cipher-` + pool.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-filesystems-create-encryption-cipher-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - - $("#dropdown-storagepool-filesystems-create-quota-` + pool.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-filesystems-create-quota-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).text()); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - - let size = { - slider: { - value: $("#input-storagepool-filesystems-create-quota-` + pool.id + `").val(), - valuemax: $("#input-storagepool-filesystems-create-quota-` + pool.id + `").attr("data-filesystem-quota-max-" + $(this).text().toLowerCase()) - } - }; - - $("#slider-storagepool-filesystems-create-quota-` + pool.id + `").data("slider").options.max = size.slider.valuemax; - $("#slider-storagepool-filesystems-create-quota-` + pool.id + `").data("slider").options.step = (size.slider.valuemax < 10 ? "0.1" : "1"); - $("#slider-storagepool-filesystems-create-quota-` + pool.id + `").slider("setValue", 0); //Force display update - $("#slider-storagepool-filesystems-create-quota-` + pool.id + `").slider("setValue", size.slider.value); - $("#input-storagepool-filesystems-create-quota-` + pool.id + `").val($("#slider-storagepool-filesystems-create-quota-` + pool.id + `").data("slider").getValue()); - }); - - $("#dropdown-storagepool-filesystems-create-recordsize-` + pool.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-filesystems-create-recordsize-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - - $("#dropdown-storagepool-filesystems-create-special_small_blocks-` + pool.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-filesystems-create-special_small_blocks-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - - $("#dropdown-storagepool-filesystems-create-xattr-` + pool.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-filesystems-create-xattr-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalFileSystemsUnlock() { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepools-filesystems-unlock").on("click", function () { - FnModalFileSystemsUnlockContent({ id: $("#modal-storagepools-filesystems-unlock") }); - FnFileSystemsLockedGet(); - - setTimeout(function() { - $("#input-storagepools-filesystems-unlock-passphrase").focus(); - }, 600); - }); - \x3C/script> - `; - - $("#modals-storagepools-filesystems").append(modal.window); -} - -function FnModalFileSystemsUnlockContent(modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#switch-storagepools-filesystems-unlock-mount input").on("click", function () { - if ($(this).prop("checked")) { - $("#switch-storagepools-filesystems-unlock-overlay").parent().removeClass("hidden"); - } else { - $("#switch-storagepools-filesystems-unlock-overlay").parent().addClass("hidden"); - } - }); - - $("#btn-storagepools-filesystems-unlock-apply").on("click", function () { - $("#spinner-storagepools-filesystems-unlock").removeClass("hidden"); - $(this).prop("disabled", true); - - let filesystem = { - mount: true, - passphrase: "" - }; - let filesystems = { - id: [] - }; - let modal = { - name: "storagepools-filesystems-unlock", - id: "" - }; - let samba = { - enable: false - }; - let validation = { - filesystems: false, - passphrase: false - }; - - $("#listgroup-storagepools-filesystems-unlock-filesystems input[name='checkbox-storagepools-filesystems-unlock-filesystems']:checked").map(function () { - filesystems.id.push($(this).attr("data-filesystem-name")); - }); - - if (filesystems.id.length == 0) { - $("#validationwrapper-storagepools-filesystems-unlock-filesystems").addClass("has-error"); - $("#helpblock-storagepools-filesystems-unlock-filesystems").removeClass("hidden").text("One or more file systems is needed for unlock."); - - validation.filesystems = false; - } else { - $("#validationwrapper-storagepools-filesystems-unlock-filesystems").removeClass("has-error"); - $("#helpblock-storagepools-filesystems-unlock-filesystems").removeClass("hidden").text(""); - - validation.filesystems = true; - } - - if ($("#input-storagepools-filesystems-unlock-passphrase").val().length == 0) { - $("#helpblock-storagepools-filesystems-unlock-passphrase").addClass("has-error").removeClass("hidden").text("Passphrase can not be empty."); - - validation.passphrase = false; - } else if ($("#input-storagepools-filesystems-unlock-passphrase").val().length < 8) { - $("#helpblock-storagepools-filesystems-unlock-passphrase").addClass("has-error").removeClass("hidden").text("Passphrase requires a minimum of 8 characters."); - - validation.passphrase = false; - } else if (/^[a-zA-Z0-9-_. \`~!@#$%^\(\)+\\[\\]{}:',/?]*$/.test($("#input-storagepools-filesystems-unlock-passphrase").val()) == false) { - $("#helpblock-storagepools-filesystems-unlock-passphrase").addClass("has-error").removeClass("hidden").text("Passphrase contains invalid characters."); - - validation.passphrase = false; - } else { - $("#validationwrapper-storagepools-filesystems-unlock-passphrase").removeClass("has-error"); - $("#helpblock-storagepools-filesystems-unlock-passphrase").removeClass("has-error").addClass("hidden").text(""); - - validation.passphrase = true; - } - - if (!validation.filesystems || !validation.passphrase) { - if (!validation.passphrase) { - $("#validationwrapper-storagepools-filesystems-unlock-passphrase").addClass("has-error"); - $("#input-storagepools-filesystems-unlock-passphrase").focus(); - } - - $("#spinner-storagepools-filesystems-unlock").addClass("hidden"); - $(this).prop("disabled", false); - } - - if (validation.filesystems && validation.passphrase) { - filesystem.mount = $("#switch-storagepools-filesystems-unlock-mount input").prop("checked"); - filesystem.overlay = $("#switch-storagepools-filesystems-unlock-overlay input").prop("checked"); - filesystem.passphrase = $("#input-storagepools-filesystems-unlock-passphrase").val(); - - FnFileSystemsUnlock({ id: filesystems.id }, { mount: filesystem.mount, overlay: filesystem.overlay, passphrase: filesystem.passphrase }, { name: modal.name, id: modal.id }); - } - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -//#endregion - -//#region Modal File System - -function FnModalFileSystemChangePassphrase(pool = { name, id }, filesystem = { name, id }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-filesystem-changepassphrase-` + filesystem.id + `").on("click", function () { - FnModalFileSystemChangePassphraseContent({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `" }, { id: $("#modal-storagepool-filesystem-changepassphrase-` + filesystem.id + `") }); - - setTimeout(function() { - $("#input-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").focus(); - }, 600); - }); - \x3C/script> - `; - - $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); -} - -function FnModalFileSystemChangePassphraseContent(pool = { name, id }, filesystem = { name, id }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-filesystem-changepassphrase-apply-` + filesystem.id + `").on("click", function () { - $("#spinner-storagepool-filesystem-changepassphrase-` + filesystem.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let filesystem = { - passphrase: "" - }; - let validation = { - passphrase: false - }; - - if ($("#input-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").val().length == 0) { - $("#validationwrapper-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").addClass("has-error"); - $("#helpblock-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Passphrase can not be empty."); - $("#input-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").focus(); - - validation.passphrase = false; - } else if ($("#input-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").val().length < 8) { - $("#validationwrapper-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").addClass("has-error"); - $("#helpblock-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Passphrase requires a minimum of 8 characters."); - $("#input-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").focus(); - - validation.passphrase = false; - } else if (/^[a-zA-Z0-9-_. \`~!@#$%^\(\)+\\[\\]{}:',/?]*$/.test($("#input-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").val()) == false) { - $("#validationwrapper-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").addClass("has-error"); - $("#helpblock-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Passphrase contains invalid characters."); - $("#input-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").focus(); - - validation.passphrase = false; - } else if ($("#input-storagepool-filesystem-changepassphrase-passphrase-confirm-` + filesystem.id + `").val().length < 8 || $("#input-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").val() != $("#input-storagepool-filesystem-changepassphrase-passphrase-confirm-` + filesystem.id + `").val()) { - $("#validationwrapper-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").removeClass("has-error").removeClass("hidden").text(""); - $("#validationwrapper-storagepool-filesystem-changepassphrase-passphrase-confirm-` + filesystem.id + `").addClass("has-error"); - $("#helpblock-storagepool-filesystem-changepassphrase-passphrase-confirm-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Passphrase does not match."); - $("#input-storagepool-filesystem-changepassphrase-passphrase-confirm-` + filesystem.id + `").focus(); - - validation.passphrase = false; - } else { - $("#validationwrapper-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").removeClass("has-error").removeClass("hidden").text(""); - $("#validationwrapper-storagepool-filesystem-changepassphrase-passphrase-confirm-` + filesystem.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystem-changepassphrase-passphrase-confirm-` + filesystem.id + `").removeClass("has-error").removeClass("hidden").text(""); - - validation.passphrase = true; - } - - if (!validation.passphrase) { - $("#spinner-storagepool-filesystem-changepassphrase-` + filesystem.id + `").addClass("hidden"); - $(this).prop("disabled", false); - } - - if (validation.passphrase) { - $("#validationwrapper-storagepool-filesystem-changepassphrase-filesystem-` + filesystem.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystem-changepassphrase-filesystem-` + filesystem.id + `").removeClass("has-error").addClass("hidden").text(""); - - filesystem.passphrase = $("#input-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").val(); - - FnFileSystemChangePassphrase({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", passphrase: filesystem.passphrase }); - } - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalFileSystemConfigure(pool = { name, id, altroot: false, feature: { allocation_classes: true, edonr: true, large_blocks: true, large_dnode: true, lz4_compress: true, sha512: true, skein: true }, readonly: false }, filesystem = { name, id, origin, type }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-filesystem-configure-` + filesystem.id + `").on("click", function () { - FnModalFileSystemConfigureContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, feature: { allocation_classes: ` + pool.feature.allocation_classes + `, edonr: ` + pool.feature.edonr + `, large_blocks: ` + pool.feature.large_blocks + `, large_dnode: ` + pool.feature.large_dnode + `, lz4_compress: ` + pool.feature.lz4_compress + `, sha512: ` + pool.feature.sha512 + `, skein: ` + pool.feature.skein + ` }, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", origin: "` + filesystem.origin + `", type: "` + filesystem.type + `" }, { id: $("#modal-storagepool-filesystem-configure-` + filesystem.id + `") }); - FnFileSystemConfigurationGet({ name: "` + pool.name + `", id: "` + pool.id + `", readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `" }, { name: "storagepool-filesystem-configure", id: "` + filesystem.id + `" }); - ` + (pool.altroot ? `FnStoragePoolAlternativeRootGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "storagepool-filesystem-configure", id: "` + filesystem.id + `" });` : ``) + ` - - $("#input-storagepool-filesystem-configure-quota-` + filesystem.id + `").val("0"); - $("#validationwrapper-storagepool-filesystem-configure-quota-` + filesystem.id + ` .min-slider-handle").attr("tabindex", "14"); - $("#input-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").val("0"); - $("#validationwrapper-storagepool-filesystem-configure-refreservation-` + filesystem.id + ` .min-slider-handle").attr("tabindex", "18"); - }); - \x3C/script> - `; - - $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); -} - -function FnModalFileSystemConfigureContent(pool = { name, id, altroot: false, feature: { allocation_classes: true, edonr: true, large_blocks: true, large_dnode: true, lz4_compress: true, sha512: true, skein: true }, readonly: false }, filesystem = { name, id, origin, type }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#input-storagepool-filesystem-configure-quota-` + filesystem.id + `").tooltip({ trigger: "manual" }) - .on("keyup", function (element) { - let $this = $(this); - let sd = $this.siblings("[data-provide=slider]").slider(); - - if ($this.val().trim() && !$.isNumeric(this.value)) { - this.value = sd.slider("getValue"); - } - }) - .on("keypress blur", function (element) { - if (element.which == 13 || element.type === "blur") { - element.preventDefault(); - - let $this = $(this); - let sd = $this.siblings("[data-provide=slider]").slider(); - let max = sd.slider("getAttribute", "max"); - let min = sd.slider("getAttribute", "min"); - - if (!$.isNumeric(this.value) || (this.value > max || this.value < min)) { - let warningInfo = $.isNumeric(this.value) ? "Valid value should be between " + min + " and " + max : "Valid value should be number"; - $this.attr("data-original-title", warningInfo).tooltip("show").addClass("warning"); - this.value = sd.slider("getValue"); - setTimeout(function () { - $this.tooltip("hide"); - }, 3000); - } else { - if ($this.is(".warning")) { - $this.tooltip("hide"); - } - - this.value = $this.val().trim(); - sd.slider("setValue", this.value); - } - } - }) - .siblings("[data-provide=slider]").each(function () { - $("#input-storagepool-filesystem-configure-quota-` + filesystem.id + `").val(this.value); - $(this).slider().on("change", function (element) { - $("#input-storagepool-filesystem-configure-quota-` + filesystem.id + `").val(element.value.newValue); - }); - }); - - $("#input-storagepool-filesystem-configure-quota-` + filesystem.id + `").on("change textInput input", function (element) { - if ($(this).val() > 1000) { //Force reset to maximum allowed value - $(this).val(1000); - } else if ($(this).val() < 0) { //Force reset to minimum allowed value - $(this).val(0); - } - - if ($.isNumeric($(this).val())) { - $("#slider-storagepool-filesystem-configure-quota-` + filesystem.id + `").slider("setValue", $(this).val()); - } - }); - - $("#input-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").tooltip({ trigger: "manual" }) - .on("keyup", function (element) { - let $this = $(this); - let sd = $this.siblings("[data-provide=slider]").slider(); - - if ($this.val().trim() && !$.isNumeric(this.value)) { - this.value = sd.slider("getValue"); - } - }) - .on("keypress blur", function (element) { - if (element.which == 13 || element.type === "blur") { - element.preventDefault(); - - let $this = $(this); - let sd = $this.siblings("[data-provide=slider]").slider(); - let max = sd.slider("getAttribute", "max"); - let min = sd.slider("getAttribute", "min"); - - if (!$.isNumeric(this.value) || (this.value > max || this.value < min)) { - let warningInfo = $.isNumeric(this.value) ? "Valid value should be between " + min + " and " + max : "Valid value should be number"; - $this.attr("data-original-title", warningInfo).tooltip("show").addClass("warning"); - this.value = sd.slider("getValue"); - setTimeout(function () { - $this.tooltip("hide"); - }, 3000); - } else { - if ($this.is(".warning")) { - $this.tooltip("hide"); - } - - this.value = $this.val().trim(); - sd.slider("setValue", this.value); - } - } - }) - .siblings("[data-provide=slider]").each(function () { - $("#input-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").val(this.value); - $(this).slider().on("change", function (element) { - $("#input-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").val(element.value.newValue); - }); - }); - - $("#input-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").on("change textInput input", function (element) { - if ($(this).val() > 1000) { //Force reset to maximum allowed value - $(this).val(1000); - } else if ($(this).val() < 0) { //Force reset to minimum allowed value - $(this).val(0); - } - - if ($.isNumeric($(this).val())) { - $("#slider-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").slider("setValue", $(this).val()); - } - }); - - $("#switch-storagepool-filesystem-configure-sharenfs-` + filesystem.id + ` input").on("click", function () { - $("#validationwrapper-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").removeClass("has-error").addClass("hidden").text(""); - - if ($(this).prop("checked")) { - $("#controllabel-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").removeClass("hidden"); - $("#validationwrapper-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").removeClass("hidden"); - - FnSystemNfsVersionGet({ alert: { id: $("#alert-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `") } }); - } else { - $("#validationwrapper-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").addClass("hidden"); - $("#controllabel-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").addClass("hidden"); - } - }); - - $("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").on("input", function (element) { - if ($("#switch-storagepool-filesystem-configure-sharesmb-` + filesystem.id + `").attr("data-field-value") == "on") { - if ($(this).val() != $(this).attr("data-field-value")) { - $("#switch-storagepool-filesystem-configure-samba-restart-` + filesystem.id + `").parent().removeClass("hidden"); - } else { - $("#switch-storagepool-filesystem-configure-samba-restart-` + filesystem.id + `").parent().addClass("hidden"); - } - } - }); - - $("#btn-storagepool-filesystem-configure-apply-` + filesystem.id + `").on("click",function () { - $("#spinner-storagepool-filesystem-configure-` + filesystem.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let filesystem = { - aclinherit: "", - acltype: "", - atime: "", - canmount: "", - checksum: "", - compression: "", - context: "", - dedup: "", - dnodesize: "", - defcontext: "", - fscontext: "", - mountpoint: "", - quota: "none", - readonly: "", - recordsize: "", - refreservation: "0B", - rootcontext: "", - selinux: "", - sharenfs: "", - sharesmb: "", - special_small_blocks: "0B", - xattr: "" - }; - let modal = { - id: $("#modal-storagepool-filesystem-configure-` + filesystem.id + `") - }; - let samba = { - restart: false - }; - let validation = { - mountpoint: false, - sharenfs: false - }; - - if ($("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val().length == 0) { - $("#helpblock-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Mountpoint can not be empty."); - - validation.mountpoint = false; - } else if (/^[a-zA-Z0-9-_.:/ ]*$/.test($("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val()) == false) { - $("#helpblock-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Mountpoint contains invalid characters."); - - validation.mountpoint = false; - } else if ($("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val() && /^[/]/.test($("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val()) == false) { - $("#helpblock-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Mountpoint is an absolute path and must begin with a forward slash (/)."); - - validation.mountpoint = false; - } else if (/^[.]/.test($("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Mountpoint can not begin with a period (.)."); - - validation.mountpoint = false; - } else if (/[.]$/.test($("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Mountpoint can not end with a period (.)."); - - validation.mountpoint = false; - } else if (/[/][.][/]/g.test($("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Mountpoint can not contain a period as a sub directory (/./)."); - - validation.mountpoint = false; - } else if (/[/][.][.][/]/g.test($("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Mountpoint can not contain a double period as a sub directory (/../)."); - - validation.mountpoint = false; - } else if (/[/][/]/g.test($("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Mountpoint can not contain double forward slashes (//)."); - - validation.mountpoint = false; - } else if (/[.][.]/g.test($("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Mountpoint can not contain a double period (..)."); - - validation.mountpoint = false; - } else if (/^[ ]/.test($("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Mountpoint can not begin with whitespace ( )."); - - validation.mountpoint = false; - } else if (/[ ]$/.test($("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Mountpoint can not end with whitespace ( )."); - - validation.mountpoint = false; - } else { - $("#validationwrapper-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("hidden").text(""); - - validation.mountpoint = true; - } - - if ($("#switch-storagepool-filesystem-configure-sharenfs-` + filesystem.id + ` input").prop("checked")) { - if (/^[a-zA-Z0-9-_.:/@#+=!&*(), ]*$/.test($("#input-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").val()) == false) { - $("#validationwrapper-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").addClass("has-error"); - $("#helpblock-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("NFS Share options contain invalid characters."); - $("#input-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").focus(); - - validation.sharenfs = false; - } else { - validation.sharenfs = true; - } - } else { - validation.sharenfs = true; - } - - if (!validation.mountpoint || !validation.sharenfs) { - if (!validation.mountpoint) { - $("#validationwrapper-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("has-error"); - $("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").focus(); - } - - $("#spinner-storagepool-filesystem-configure-` + filesystem.id + `").addClass("hidden"); - $(this).prop("disabled", false); - } - - if (validation.mountpoint && validation.sharenfs) { - filesystem.aclinherit = ($("#btnspan-storagepool-filesystem-configure-aclinherit-` + filesystem.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-filesystem-configure-aclinherit-` + filesystem.id + `").attr("data-field-value-new") : null); - filesystem.acltype = ($("#btnspan-storagepool-filesystem-configure-acltype-` + filesystem.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-filesystem-configure-acltype-` + filesystem.id + `").attr("data-field-value-new") : null); - filesystem.atime = ($("#btnspan-storagepool-filesystem-configure-atime-` + filesystem.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-filesystem-configure-atime-` + filesystem.id + `").attr("data-field-value-new") : null); - filesystem.canmount = ($("#btnspan-storagepool-filesystem-configure-canmount-` + filesystem.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-filesystem-configure-canmount-` + filesystem.id + `").attr("data-field-value-new") : null); - filesystem.checksum = ($("#btnspan-storagepool-filesystem-configure-checksum-` + filesystem.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-filesystem-configure-checksum-` + filesystem.id + `").attr("data-field-value-new") : null); - filesystem.compression = ($("#btnspan-storagepool-filesystem-configure-compression-` + filesystem.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-filesystem-configure-compression-` + filesystem.id + `").attr("data-field-value-new") : null); - filesystem.context = ($("#switch-storagepool-filesystem-configure-selinux-` + filesystem.id + ` input").prop("checked") ? "system_u:object_r:samba_share_t:s0" : "none"); - filesystem.dedup = ($("#btnspan-storagepool-filesystem-configure-dedup-` + filesystem.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-filesystem-configure-dedup-` + filesystem.id + `").attr("data-field-value-new") : null); - filesystem.dnodesize = ($("#btnspan-storagepool-filesystem-configure-dnodesize-` + filesystem.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-filesystem-configure-dnodesize-` + filesystem.id + `").attr("data-field-value-new") : null); - filesystem.defcontext = ($("#switch-storagepool-filesystem-configure-selinux-` + filesystem.id + ` input").prop("checked") ? "system_u:object_r:samba_share_t:s0" : "none"); - filesystem.fscontext = ($("#switch-storagepool-filesystem-configure-selinux-` + filesystem.id + ` input").prop("checked") ? "system_u:object_r:samba_share_t:s0" : "none"); - filesystem.mountpoint = $("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val(); - filesystem.readonly = ($("#switch-storagepool-filesystem-configure-readonly-` + filesystem.id + ` input").prop("checked") ? "on" : "off"); - filesystem.recordsize = ($("#btnspan-storagepool-filesystem-configure-recordsize-` + filesystem.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-filesystem-configure-recordsize-` + filesystem.id + `").attr("data-field-value-new") : null); - filesystem.rootcontext = ($("#switch-storagepool-filesystem-configure-selinux-` + filesystem.id + ` input").prop("checked") ? "system_u:object_r:samba_share_t:s0" : "none"); - filesystem.selinux = $("#switch-storagepool-filesystem-configure-selinux-` + filesystem.id + ` input").prop("checked"); - filesystem.sharesmb = ` + (zfsmanager.configuration.samba.manage ? `$("#switch-storagepool-filesystem-configure-sharesmb-` + filesystem.id + `").attr("data-field-value");` : `($("#switch-storagepool-filesystem-configure-sharesmb-` + filesystem.id + ` input").prop("checked") ? "on" : "off");`) + ` - filesystem.special_small_blocks = ($("#btnspan-storagepool-filesystem-configure-special_small_blocks-` + filesystem.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-filesystem-configure-special_small_blocks-` + filesystem.id + `").attr("data-field-value-new") : null); - filesystem.xattr = ($("#btnspan-storagepool-filesystem-configure-xattr-` + filesystem.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-filesystem-configure-xattr-` + filesystem.id + `").attr("data-field-value-new") : null); - - if ($("#input-storagepool-filesystem-configure-quota-` + filesystem.id + `").val() > 0) { //Remove friendly text so final value is sent - filesystem.quota = $("#input-storagepool-filesystem-configure-quota-` + filesystem.id + `").val() + $("#btnspan-storagepool-filesystem-configure-quota-` + filesystem.id + `").attr("data-field-value").replace(/iB$/g, ""); - } else { - filesystem.quota = "none"; - } - - if ($("#input-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").val() > 0) { //Remove friendly text so final value is sent - filesystem.refreservation = $("#input-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").val() + $("#btnspan-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").attr("data-field-value").replace(/iB$/g, ""); - } else { - filesystem.refreservation = "0B"; - } - - if ($("#switch-storagepool-filesystem-configure-sharenfs-` + filesystem.id + ` input").prop("checked")) { - if ($("#input-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").val().toLowerCase() == "on" || $("#input-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").val() == "sec=sys,rw,crossmnt,no_subtree_check,no_root_squash" || !$("#input-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").val()) { - filesystem.sharenfs = "on"; - } else { - filesystem.sharenfs = $("#input-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").val(); - } - } else { - filesystem.sharenfs = "off"; - } - - //Set values to null if unchanged, so that they are skipped in the configure function - if (/^Inherited/.test(filesystem.aclinherit) && $("#btnspan-storagepool-filesystem-configure-aclinherit-` + filesystem.id + `").attr("data-field-source") == "inherited") { - filesystem.aclinherit = null; - } else if (/^Default/.test(filesystem.aclinherit) && $("#btnspan-storagepool-filesystem-configure-aclinherit-` + filesystem.id + `").attr("data-field-source") == "default") { - filesystem.aclinherit = null; - } else if (filesystem.aclinherit == $("#btnspan-storagepool-filesystem-configure-aclinherit-` + filesystem.id + `").attr("data-field-value") && $("#btnspan-storagepool-filesystem-configure-aclinherit-` + filesystem.id + `").attr("data-field-source") == "local") { - filesystem.aclinherit = null; - } - - if (/^Inherited/.test(filesystem.acltype) && $("#btnspan-storagepool-filesystem-configure-acltype-` + filesystem.id + `").attr("data-field-source") == "inherited") { - filesystem.acltype = null; - } else if (/^Default/.test(filesystem.acltype) && $("#btnspan-storagepool-filesystem-configure-acltype-` + filesystem.id + `").attr("data-field-source") == "default") { - filesystem.acltype = null; - } else if (filesystem.acltype == $("#btnspan-storagepool-filesystem-configure-acltype-` + filesystem.id + `").attr("data-field-value") && $("#btnspan-storagepool-filesystem-configure-acltype-` + filesystem.id + `").attr("data-field-source") == "local") { - filesystem.acltype = null; - } - - if (/^Inherited/.test(filesystem.atime) && $("#btnspan-storagepool-filesystem-configure-atime-` + filesystem.id + `").attr("data-field-source") == "inherited") { - filesystem.atime = null; - } else if (/^Default/.test(filesystem.atime) && $("#btnspan-storagepool-filesystem-configure-atime-` + filesystem.id + `").attr("data-field-source") == "default") { - filesystem.atime = null; - } else if (filesystem.atime == $("#btnspan-storagepool-filesystem-configure-atime-` + filesystem.id + `").attr("data-field-value") && $("#btnspan-storagepool-filesystem-configure-atime-` + filesystem.id + `").attr("data-field-source") == "local") { - filesystem.atime = null; - } - - if (filesystem.canmount == $("#btnspan-storagepool-filesystem-configure-canmount-` + filesystem.id + `").attr("data-field-value")) { - filesystem.canmount = null; - } - - if (/^Inherited/.test(filesystem.checksum) && $("#btnspan-storagepool-filesystem-configure-checksum-` + filesystem.id + `").attr("data-field-source") == "inherited") { - filesystem.checksum = null; - } else if (/^Default/.test(filesystem.checksum) && $("#btnspan-storagepool-filesystem-configure-checksum-` + filesystem.id + `").attr("data-field-source") == "default") { - filesystem.checksum = null; - } else if (filesystem.checksum == $("#btnspan-storagepool-filesystem-configure-checksum-` + filesystem.id + `").attr("data-field-value") && $("#btnspan-storagepool-filesystem-configure-checksum-` + filesystem.id + `").attr("data-field-source") == "local") { - filesystem.checksum = null; - } - - if (/^Inherited/.test(filesystem.compression) && $("#btnspan-storagepool-filesystem-configure-compression-` + filesystem.id + `").attr("data-field-source") == "inherited") { - filesystem.compression = null; - } else if (/^Default/.test(filesystem.compression) && $("#btnspan-storagepool-filesystem-configure-compression-` + filesystem.id + `").attr("data-field-source") == "default") { - filesystem.compression = null; - } else if (filesystem.compression == $("#btnspan-storagepool-filesystem-configure-compression-` + filesystem.id + `").attr("data-field-value") && $("#btnspan-storagepool-filesystem-configure-compression-` + filesystem.id + `").attr("data-field-source") == "local") { - filesystem.compression = null; - } - - - if (/^Inherited/.test(filesystem.dedup) && $("#btnspan-storagepool-filesystem-configure-dedup-` + filesystem.id + `").attr("data-field-source") == "inherited") { - filesystem.dedup = null; - } else if (/^Default/.test(filesystem.dedup) && $("#btnspan-storagepool-filesystem-configure-dedup-` + filesystem.id + `").attr("data-field-source") == "default") { - filesystem.dedup = null; - } else if (filesystem.dedup == $("#btnspan-storagepool-filesystem-configure-dedup-` + filesystem.id + `").attr("data-field-value") && $("#btnspan-storagepool-filesystem-configure-dedup-` + filesystem.id + `").attr("data-field-source") == "local") { - filesystem.dedup = null; - } - - if (/^Inherited/.test(filesystem.dnodesize) && $("#btnspan-storagepool-filesystem-configure-dnodesize-` + filesystem.id + `").attr("data-field-source") == "inherited") { - filesystem.dnodesize = null; - } else if (/^Default/.test(filesystem.dnodesize) && $("#btnspan-storagepool-filesystem-configure-dnodesize-` + filesystem.id + `").attr("data-field-source") == "default") { - filesystem.dnodesize = null; - } else if (filesystem.dnodesize == $("#btnspan-storagepool-filesystem-configure-dnodesize-` + filesystem.id + `").attr("data-field-value") && $("#btnspan-storagepool-filesystem-configure-dnodesize-` + filesystem.id + `").attr("data-field-source") == "local") { - filesystem.dnodesize = null; - } - - if (filesystem.mountpoint == $("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").attr("data-field-value")) { - filesystem.mountpoint = null; - } else { - ` + (pool.altroot ? `filesystem.mountpoint = filesystem.mountpoint.replace(new RegExp("^" + $("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").attr("data-field-altroot")), "");` : ``) + ` - - samba.restart = $("#switch-storagepool-filesystem-configure-samba-restart-` + filesystem.id + ` input").prop("checked"); - } - - if (filesystem.quota == $("#input-storagepool-filesystem-configure-quota-` + filesystem.id + `").attr("data-field-value")) { - filesystem.quota = null; - } - - if (filesystem.readonly == $("#switch-storagepool-filesystem-configure-readonly-` + filesystem.id + `").attr("data-field-value")) { - filesystem.readonly = null; - } - - if (/^Inherited/.test(filesystem.recordsize) && $("#btnspan-storagepool-filesystem-configure-recordsize-` + filesystem.id + `").attr("data-field-source") == "inherited") { - filesystem.recordsize = null; - } else if (/^Default/.test(filesystem.recordsize) && $("#btnspan-storagepool-filesystem-configure-recordsize-` + filesystem.id + `").attr("data-field-source") == "default") { - filesystem.recordsize = null; - } else if (filesystem.recordsize == $("#btnspan-storagepool-filesystem-configure-recordsize-` + filesystem.id + `").attr("data-field-value") && $("#btnspan-storagepool-filesystem-configure-recordsize-` + filesystem.id + `").attr("data-field-source") == "local") { - filesystem.recordsize = null; - } - - if (filesystem.refreservation == $("#input-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").attr("data-field-value")) { - filesystem.refreservation = null; - } - - if (filesystem.selinux == $("#switch-storagepool-filesystem-configure-selinux-` + filesystem.id + `").attr("data-field-value")) { - filesystem.context = null; - filesystem.defcontext = null; - filesystem.fscontext = null; - filesystem.rootcontext = null; - filesystem.selinux = null; - } - - if (filesystem.sharenfs == $("#input-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").attr("data-field-value")) { - filesystem.sharenfs = null; - } - - if (/^Inherited/.test(filesystem.special_small_blocks) && $("#btnspan-storagepool-filesystem-configure-special_small_blocks-` + filesystem.id + `").attr("data-field-source") == "inherited") { - filesystem.special_small_blocks = null; - } else if (/^Default/.test(filesystem.special_small_blocks) && $("#btnspan-storagepool-filesystem-configure-special_small_blocks-` + filesystem.id + `").attr("data-field-source") == "default") { - filesystem.special_small_blocks = null; - } else if (filesystem.special_small_blocks == $("#btnspan-storagepool-filesystem-configure-special_small_blocks-` + filesystem.id + `").attr("data-field-value") && $("#btnspan-storagepool-filesystem-configure-special_small_blocks-` + filesystem.id + `").attr("data-field-source") == "local") { - filesystem.special_small_blocks = null; - } - - if (/^Inherited/.test(filesystem.xattr) && $("#btnspan-storagepool-filesystem-configure-xattr-` + filesystem.id + `").attr("data-field-source") == "inherited") { - filesystem.xattr = null; - } else if (/^Default/.test(filesystem.xattr) && $("#btnspan-storagepool-filesystem-configure-xattr-` + filesystem.id + `").attr("data-field-source") == "default") { - filesystem.xattr = null; - } else if (filesystem.xattr == $("#btnspan-storagepool-filesystem-configure-xattr-` + filesystem.id + `").attr("data-field-value") && $("#btnspan-storagepool-filesystem-configure-xattr-` + filesystem.id + `").attr("data-field-source") == "local") { - filesystem.xattr = null; - } - - FnFileSystemConfigure({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", aclinherit: filesystem.aclinherit, acltype: filesystem.acltype, atime: filesystem.atime, canmount: filesystem.canmount, checksum: filesystem.checksum, compression: filesystem.compression, context: filesystem.context, dedup: filesystem.dedup, dnodesize: filesystem.dnodesize, defcontext: filesystem.defcontext, fscontext: filesystem.fscontext, mountpoint: filesystem.mountpoint, quota: filesystem.quota, readonly: filesystem.readonly, recordsize: filesystem.recordsize, refreservation: filesystem.refreservation, rootcontext: filesystem.rootcontext, sharenfs: filesystem.sharenfs, sharesmb: filesystem.sharesmb, special_small_blocks: filesystem.special_small_blocks, type: "` + filesystem.type + `", xattr: filesystem.xattr }, { restart: samba.restart }, { id: modal.id }); - } - }); - - $("#dropdown-storagepool-filesystem-configure-aclinherit-` + filesystem.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-filesystem-configure-aclinherit-` + filesystem.id + `").text($(this).text()).attr("data-field-value-new", (/^Default/.test($(this).text()) ? "Default" : $(this).parent().attr("value"))); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - - $("#dropdown-storagepool-filesystem-configure-acltype-` + filesystem.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-filesystem-configure-acltype-` + filesystem.id + `").text($(this).text()).attr("data-field-value-new", (/^Default/.test($(this).text()) ? "Default" : $(this).parent().attr("value"))); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - - $("#dropdown-storagepool-filesystem-configure-atime-` + filesystem.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-filesystem-configure-atime-` + filesystem.id + `").text($(this).text()).attr("data-field-value-new", (/^Default/.test($(this).text()) ? "Default" : $(this).parent().attr("value"))); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - - $("#dropdown-storagepool-filesystem-configure-canmount-` + filesystem.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-filesystem-configure-canmount-` + filesystem.id + `").text($(this).text()).attr("data-field-value-new", (/^Default/.test($(this).text()) ? "Default" : $(this).parent().attr("value"))); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - - $("#dropdown-storagepool-filesystem-configure-checksum-` + filesystem.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-filesystem-configure-checksum-` + filesystem.id + `").text($(this).text()).attr("data-field-value-new", (/^Default/.test($(this).text()) ? "Default" : $(this).parent().attr("value"))); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - - $("#dropdown-storagepool-filesystem-configure-compression-` + filesystem.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-filesystem-configure-compression-` + filesystem.id + `").text($(this).text()).attr("data-field-value-new", (/^Default/.test($(this).text()) ? "Default" : $(this).parent().attr("value"))); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - - $("#dropdown-storagepool-filesystem-configure-dedup-` + filesystem.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-filesystem-configure-dedup-` + filesystem.id + `").text($(this).text()).attr("data-field-value-new", (/^Default/.test($(this).text()) ? "Default" : $(this).parent().attr("value"))); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - - $("#dropdown-storagepool-filesystem-configure-dnodesize-` + filesystem.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-filesystem-configure-dnodesize-` + filesystem.id + `").text($(this).text()).attr("data-field-value-new", (/^Default/.test($(this).text()) ? "Default" : $(this).parent().attr("value"))); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - - $("#dropdown-storagepool-filesystem-configure-quota-` + filesystem.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-filesystem-configure-quota-` + filesystem.id + `").text($(this).text()).attr("data-field-value", $(this).text()); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - - let size = { - slider: { - value: $("#input-storagepool-filesystem-configure-quota-` + filesystem.id + `").val(), - valuemax: $("#input-storagepool-filesystem-configure-quota-` + filesystem.id + `").attr("data-filesystem-quota-max-" + $(this).text().toLowerCase()) - } - }; - - $("#slider-storagepool-filesystem-configure-quota-` + filesystem.id + `").data("slider").options.max = size.slider.valuemax; - $("#slider-storagepool-filesystem-configure-quota-` + filesystem.id + `").data("slider").options.step = (size.slider.valuemax < 10 ? "0.1" : "1"); - $("#slider-storagepool-filesystem-configure-quota-` + filesystem.id + `").slider("setValue", 0); //Force display update - $("#slider-storagepool-filesystem-configure-quota-` + filesystem.id + `").slider("setValue", size.slider.value); - $("#input-storagepool-filesystem-configure-quota-` + filesystem.id + `").val($("#slider-storagepool-filesystem-configure-quota-` + filesystem.id + `").data("slider").getValue()); - }); - - $("#dropdown-storagepool-filesystem-configure-recordsize-` + filesystem.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-filesystem-configure-recordsize-` + filesystem.id + `").text($(this).text()).attr("data-field-value-new", (/^Default/.test($(this).text()) ? "Default" : $(this).parent().attr("value"))); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - - $("#dropdown-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").text($(this).text()).attr("data-field-value", $(this).text()); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - - let size = { - slider: { - value: $("#input-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").val(), - valuemax: $("#input-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").attr("data-filesystem-refreservation-max-" + $(this).text().toLowerCase()) - } - }; - - $("#slider-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").data("slider").options.max = size.slider.valuemax; - $("#slider-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").data("slider").options.step = (size.slider.valuemax < 10 ? "0.1" : "1"); - $("#slider-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").slider("setValue", 0); //Force display update - $("#slider-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").slider("setValue", size.slider.value); - $("#input-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").val($("#slider-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").data("slider").getValue()); - }); - - $("#dropdown-storagepool-filesystem-configure-special_small_blocks-` + filesystem.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-filesystem-configure-special_small_blocks-` + filesystem.id + `").text($(this).text()).attr("data-field-value-new", (/^Default/.test($(this).text()) ? "Default" : $(this).parent().attr("value"))); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - - $("#dropdown-storagepool-filesystem-configure-xattr-` + filesystem.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-filesystem-configure-xattr-` + filesystem.id + `").text($(this).text()).attr("data-field-value-new", (/^Default/.test($(this).text()) ? "Default" : $(this).parent().attr("value"))); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalFileSystemDestroy(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, sharesmb: false, type }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-filesystem-destroy-` + filesystem.id + `").on("click", function () { - FnModalFileSystemDestroyContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", sharesmb: ` + filesystem.sharesmb + `, type: "` + filesystem.type + `" }, { id: $("#modal-storagepool-filesystem-destroy-` + filesystem.id + `") }); - FnFileSystemChildDatasetsGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", clones: true }, { name: "storagepool-filesystem-destroy", id: "` + filesystem.id + `" }); - }); - \x3C/script> - `; - - $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); -} - -function FnModalFileSystemDestroyContent(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, sharesmb: false, type }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#switch-storagepool-filesystem-destroy-recursive-` + filesystem.id + ` input").on("click", function () { - if ($(this).prop("checked") && $("#switch-storagepool-filesystem-destroy-recursiveall-` + filesystem.id + ` input").prop("checked")) { - $("#switch-storagepool-filesystem-destroy-recursiveall-` + filesystem.id + ` input").click(); - } - - $("#panel-storagepool-filesystem-destroy-child-filesystemswithclones-` + filesystem.id + `").addClass("hidden"); - $("#panel-storagepool-filesystem-destroy-child-filesystemswithclones-` + filesystem.id + ` .collapse").collapse("hide"); - $("#panel-storagepool-filesystem-destroy-child-snapshotswithclones-` + filesystem.id + `").addClass("hidden"); - $("#panel-storagepool-filesystem-destroy-child-snapshotswithclones-` + filesystem.id + ` .collapse").collapse("hide"); - - if ($(this).prop("checked") && $("#panelgroup-storagepool-filesystem-destroy-` + filesystem.id + `").attr("data-filesystem-child-filesystems") > 0) { - $("#panel-storagepool-filesystem-destroy-child-filesystems-` + filesystem.id + `").removeClass("hidden"); - } else { - $("#panel-storagepool-filesystem-destroy-child-filesystems-` + filesystem.id + `").addClass("hidden"); - $("#panel-storagepool-filesystem-destroy-child-filesystems-` + filesystem.id + ` .collapse").collapse("hide"); - } - if ($(this).prop("checked") && $("#panelgroup-storagepool-filesystem-destroy-` + filesystem.id + `").attr("data-filesystem-child-snapshots") > 0) { - $("#panel-storagepool-filesystem-destroy-child-snapshots-` + filesystem.id + `").removeClass("hidden"); - } else { - $("#panel-storagepool-filesystem-destroy-child-snapshots-` + filesystem.id + `").addClass("hidden"); - $("#panel-storagepool-filesystem-destroy-child-snapshots-` + filesystem.id + ` .collapse").collapse("hide"); - } - if ($(this).prop("checked") && ($("#panelgroup-storagepool-filesystem-destroy-` + filesystem.id + `").attr("data-filesystem-child-filesystems") > 0 || $("#panelgroup-storagepool-filesystem-destroy-` + filesystem.id + `").attr("data-filesystem-child-snapshots") > 0)) { - $("#panelgroup-storagepool-filesystem-destroy-` + filesystem.id + `").addClass("modal-ct-bodytext-1"); - } else { - $("#panelgroup-storagepool-filesystem-destroy-` + filesystem.id + `").removeClass("modal-ct-bodytext-1"); - } - }); - - $("#switch-storagepool-filesystem-destroy-recursiveall-` + filesystem.id + ` input").on("click", function () { - if ($(this).prop("checked") && $("#switch-storagepool-filesystem-destroy-recursive-` + filesystem.id + ` input").prop("checked")) { - $("#switch-storagepool-filesystem-destroy-recursive-` + filesystem.id + ` input").click(); - } - - $("#panel-storagepool-filesystem-destroy-child-filesystems-` + filesystem.id + `").addClass("hidden"); - $("#panel-storagepool-filesystem-destroy-child-filesystems-` + filesystem.id + ` .collapse").collapse("hide"); - $("#panel-storagepool-filesystem-destroy-child-snapshots-` + filesystem.id + `").addClass("hidden"); - $("#panel-storagepool-filesystem-destroy-child-snapshots-` + filesystem.id + ` .collapse").collapse("hide"); - - if ($(this).prop("checked") && $("#panelgroup-storagepool-filesystem-destroy-` + filesystem.id + `").attr("data-filesystem-child-filesystemswithclones") > 0) { - $("#panel-storagepool-filesystem-destroy-child-filesystemswithclones-` + filesystem.id + `").removeClass("hidden"); - } else { - $("#panel-storagepool-filesystem-destroy-child-filesystemswithclones-` + filesystem.id + `").addClass("hidden"); - $("#panel-storagepool-filesystem-destroy-child-filesystemswithclones-` + filesystem.id + ` .collapse").collapse("hide"); - } - if ($(this).prop("checked") && $("#panelgroup-storagepool-filesystem-destroy-` + filesystem.id + `").attr("data-filesystem-child-snapshotswithclones") > 0) { - $("#panel-storagepool-filesystem-destroy-child-snapshotswithclones-` + filesystem.id + `").removeClass("hidden"); - } else { - $("#panel-storagepool-filesystem-destroy-child-snapshotswithclones-` + filesystem.id + `").addClass("hidden"); - $("#panel-storagepool-filesystem-destroy-child-snapshotswithclones-` + filesystem.id + ` .collapse").collapse("hide"); - } - if ($(this).prop("checked") && ($("#panelgroup-storagepool-filesystem-destroy-` + filesystem.id + `").attr("data-filesystem-child-filesystemswithclones") > 0 || $("#panelgroup-storagepool-filesystem-destroy-` + filesystem.id + `").attr("data-filesystem-child-snapshotswithclones") > 0)) { - $("#panelgroup-storagepool-filesystem-destroy-` + filesystem.id + `").addClass("modal-ct-bodytext-1"); - } else { - $("#panelgroup-storagepool-filesystem-destroy-` + filesystem.id + `").removeClass("modal-ct-bodytext-1"); - } - }); - - $("#btn-storagepool-filesystem-destroy-apply-` + filesystem.id + `").on("click", function () { - $("#spinner-storagepool-filesystem-destroy-` + filesystem.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let filesystem = { - force: $("#switch-storagepool-filesystem-destroy-force-` + filesystem.id + ` input").prop("checked"), - recursive: $("#switch-storagepool-filesystem-destroy-recursive-` + filesystem.id + ` input").prop("checked"), - recursiveall: $("#switch-storagepool-filesystem-destroy-recursiveall-` + filesystem.id + ` input").prop("checked") - }; - let samba = { - restart: $("#switch-storagepool-filesystem-destroy-samba-restart-` + filesystem.id + ` input").prop("checked") - }; - - FnFileSystemDestroy({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", force: filesystem.force, recursive: filesystem.recursive, recursiveall: filesystem.recursiveall, sharesmb: ` + filesystem.sharesmb + `, type: "` + filesystem.type + `" }, { restart: samba.restart }); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalFileSystemLock(pool = { name, id }, filesystem = { name, id, type }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-filesystem-lock-` + filesystem.id + `").on("click", function () { - FnModalFileSystemLockContent({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", type: "` + filesystem.type + `" }, { id: $("#modal-storagepool-filesystem-lock-` + filesystem.id + `") }); - }); - \x3C/script> - `; - - $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); -} - -function FnModalFileSystemLockContent(pool = { name, id }, filesystem = { name, id, type }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-filesystem-lock-apply-` + filesystem.id + `").on("click", function () { - $("#spinner-storagepool-filesystem-lock-` + filesystem.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - FnFileSystemLock({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", type: "` + filesystem.type + `" }, { refresh: true }); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalFileSystemMount(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, sharesmb: false, type }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-filesystem-mount-` + filesystem.id + `").on("click", function () { - FnModalFileSystemMountContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", sharesmb: ` + filesystem.sharesmb + `, type: "` + filesystem.type + `" }, { id: $("#modal-storagepool-filesystem-mount-` + filesystem.id + `") }); - FnFileSystemsMountedGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `" }, { alert: { id: $("#div-storagepool-filesystem-mount-warning-` + filesystem.id + `"), mount: true } }); - }); - \x3C/script> - `; - - $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); -} - -function FnModalFileSystemMountContent(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, sharesmb: false, type }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#switch-storagepool-filesystem-mount-samba-enable-` + filesystem.id + ` input").on("click", function () { - if ($(this).prop("checked")) { - ` + (filesystem.name == pool.name ? `$("#alert-storagepool-filesystem-samba-warning-` + filesystem.id + `").removeClass("hidden");` : ``) + ` - } else { - ` + (filesystem.name == pool.name ? `$("#alert-storagepool-filesystem-samba-warning-` + filesystem.id + `").addClass("hidden");` : ``) + ` - } - }); - - $("#btn-storagepool-filesystem-mount-apply-` + filesystem.id + `").on("click", function () { - $("#spinner-storagepool-filesystem-mount-` + filesystem.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let filesystem = { - overlay: $("#switch-storagepool-filesystem-mount-overlay-` + filesystem.id + ` input").prop("checked") - }; - let samba = { - enable: ` + ((pool.readonly || filesystem.sharesmb) ? false : `$("#switch-storagepool-filesystem-mount-samba-enable-` + filesystem.id + ` input").prop("checked")`) + ` - }; - - FnFileSystemMount({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", overlay: filesystem.overlay, type: "` + filesystem.type + `" }, { enable: samba.enable }, { refresh: true }); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalFileSystemPromote(pool = { name, id }, filesystem = { name, id, origin, type }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-filesystem-promote-` + filesystem.id + `").on("click", function () { - FnModalFileSystemPromoteContent({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", origin: "` + filesystem.origin + `", type: "` + filesystem.type + `" }, { id: $("#modal-storagepool-filesystem-promote-` + filesystem.id + `") }); - }); - \x3C/script> - `; - - $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); -} - -function FnModalFileSystemPromoteContent(pool = { name, id }, filesystem = { name, id, origin, type }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-filesystem-promote-apply-` + filesystem.id + `").on("click", function () { - $("#spinner-storagepool-filesystem-promote-` + filesystem.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - FnFileSystemPromote({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", type: "` + filesystem.type + `" }); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalFileSystemRename(pool = { name, id, altroot: false }, filesystem = { name, id, clone: false, encryption: false, encryptionroot, origin, sharesmb: false, type }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-filesystem-rename-` + filesystem.id + `").on("click", function () { - FnModalFileSystemRenameContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", clone: ` + filesystem.clone + `, encryption: ` + filesystem.encryption + `, origin: "` + filesystem.origin + `", sharesmb: ` + filesystem.sharesmb + `, type: "` + filesystem.type + `" }, { id: $("#modal-storagepool-filesystem-rename-` + filesystem.id + `") }); - FnFileSystemsNamesGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { existing: { name: "` + filesystem.name + `", clone: ` + filesystem.clone + `, encryption: ` + filesystem.encryption + `, encryptionroot: "` + filesystem.encryptionroot + `", origin: "` + filesystem.origin + `" }, override: false }, { dropdown: { id: $("#dropdown-storagepool-filesystem-rename-parentfilesystem-` + filesystem.id + `"), selected: "` + filesystem.name.replace(/\/[^\/]+$/, "") + `" } }); - - setTimeout(function() { - $("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").focus(); - }, 600); - }); - \x3C/script> - `; - - $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); -} - -function FnModalFileSystemRenameContent(pool = { name, id, altroot: false }, filesystem = { name, id, clone: false, encryption: false, origin, sharesmb: false, type }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-filesystem-rename-apply-` + filesystem.id + `").on("click", function () { - $("#spinner-storagepool-filesystem-rename-` + filesystem.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let filesystem = { - createnonexistparents: false, - force: false, - namenew: "", - parent: "" - }; - let samba = { - restart: false - }; - let validation = { - name: false - }; - - if ($("#btnspan-storagepool-filesystem-rename-parentfilesystem-` + filesystem.id + `").attr("data-field-value") + "/" + $("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val() == "` + filesystem.name + `") { - $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name or parent file system must be different."); - - validation.name = false; - } else if (new RegExp("^" + "` + filesystem.name + `/").test($("#btnspan-storagepool-filesystem-rename-parentfilesystem-` + filesystem.id + `").attr("data-field-value") + "/" + $("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not be a descendant of current file system."); - - validation.name = false; - } else if ($("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val().length == 0) { - $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not be empty."); - - validation.name = false; - } else if (/^[a-zA-Z0-9-_.:/ ]*$/.test($("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val()) == false) { - $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name contains invalid characters."); - - validation.name = false; - } else if (/^[.]/.test($("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a period (.)."); - - validation.name = false; - } else if (/^[_]/.test($("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with an underscore (_)."); - - validation.name = false; - } else if (/^[-]/.test($("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a hypen (-)."); - - validation.name = false; - } else if (/^[:]/.test($("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with an colon (:)."); - - validation.name = false; - } else if (/^[/]/.test($("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a forward slash (/)."); - - validation.name = false; - } else if (/[/]$/.test($("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not end with a forward slash (/)."); - - validation.name = false; - } else if (/^ |\\/ /.test($("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with whitespace ( )."); - - validation.name = false; - } else if (/ $| \\//.test($("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not end with whitespace ( )."); - - validation.name = false; - } else { - $("#validationwrapper-storagepool-filesystem-rename-name-` + filesystem.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("hidden").text(""); - - validation.name = true; - } - - if (!validation.name) { - $("#validationwrapper-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error"); - $("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").focus(); - - $("#spinner-storagepool-filesystem-rename-` + filesystem.id + `").addClass("hidden"); - $(this).prop("disabled", false); - } - - if (validation.name) { - filesystem.createnonexistparents = $("#switch-storagepool-filesystem-rename-createnonexistparents-` + filesystem.id + ` input").prop("checked"); - filesystem.force = $("#switch-storagepool-filesystem-rename-force-` + filesystem.id + ` input").prop("checked"); - filesystem.namenew = $("#btnspan-storagepool-filesystem-rename-parentfilesystem-` + filesystem.id + `").attr("data-field-value") + "/" + $("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val(); - filesystem.parent = $("#btnspan-storagepool-filesystem-rename-parentfilesystem-` + filesystem.id + `").attr("data-field-value"); - - samba.restart = $("#switch-storagepool-filesystem-rename-samba-restart-` + filesystem.id + ` input").prop("checked") - - FnFileSystemRename({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", createnonexistparents: filesystem.createnonexistparents, force: filesystem.force, namenew: filesystem.namenew, parent: filesystem.parent, sharesmb: ` + filesystem.sharesmb + `, type: "` + filesystem.type + `" }, { restart: samba.restart }); - } - }); - - $("#dropdown-storagepool-filesystem-rename-parentfilesystem-` + filesystem.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-filesystem-rename-parentfilesystem-` + filesystem.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalFileSystemSambaConfigure(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, mountpoint }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-filesystem-samba-configure-` + filesystem.id + `").on("click", function () { - FnModalFileSystemSambaConfigureContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", mountpoint: "` + filesystem.mountpoint + `" }, { id: $("#modal-storagepool-filesystem-samba-configure-` + filesystem.id + `") }); - FnSambaZfsShareConfigurationGet({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `" }, { name: "storagepool-filesystem-samba-configure", id: "` + filesystem.id + `" }); - - setTimeout(function() { - $("#input-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").focus(); - }, 600); - }); - \x3C/script> - `; - - $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); -} - -function FnModalFileSystemSambaConfigureContent(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, mountpoint }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#switch-storagepool-filesystem-samba-configure-additional-` + filesystem.id + ` input").on("click", function () { - $("#validationwrapper-storagepool-filesystem-samba-configure-additional-` + filesystem.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystem-samba-configure-additional-` + filesystem.id + `").removeClass("has-error").addClass("hidden").text(""); - - if ($("#switch-storagepool-filesystem-samba-configure-additional-` + filesystem.id + ` input").prop("checked")) { - $("#validationwrapper-storagepool-filesystem-samba-configure-additional-` + filesystem.id + `").removeClass("hidden"); - } else { - $("#validationwrapper-storagepool-filesystem-samba-configure-additional-` + filesystem.id + `").addClass("hidden"); - } - }); - - $("#btn-storagepool-filesystem-samba-configure-apply-` + filesystem.id + `").on("click", function () { - $("#spinner-storagepool-filesystem-samba-configure-` + filesystem.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let samba = { - share: { - additional: ($("#switch-storagepool-filesystem-samba-configure-additional-` + filesystem.id + ` input").prop("checked") ? $("#textarea-storagepool-filesystem-samba-configure-additional-` + filesystem.id + `").val().split("\\n").filter(v => v) : []), - administrative: false, - browseable: true, - comment: "", - guestok: false, - name: "", - nameexisting: "", - readonly: false - } - }; - let validation = { - comment: false, - name: false, - additional: false - }; - - if ($("#input-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").val().length == 0) { - $("#helpblock-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Share name can not be empty."); - - validation.name = false; - } else if (/^[a-zA-Z0-9-_.@%+!#$^,(){}~ ]*$/.test($("#input-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").val()) == false) { - $("#helpblock-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Share name contains invalid characters."); - - validation.name = false; - } else if (/^[ ]/.test($("#input-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Share name can not begin with whitespace ( )."); - - validation.name = false; - } else if (/[ ]$/.test($("#input-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Share name can not end with whitespace ( )."); - - validation.name = false; - } else { - $("#validationwrapper-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").addClass("hidden").text(""); - - validation.name = true; - } - - if (/^[ -~]*$/.test($("#input-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").val()) == false) { - $("#helpblock-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Comment contains invalid characters."); - - validation.comment = false; - } else if (/^[.]/.test($("#input-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Comment can not begin with a period (.)."); - - validation.comment = false; - } else if (/^[ ]/.test($("#input-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Comment can not begin with whitespace ( )."); - - validation.comment = false; - } else if (/[ ]$/.test($("#input-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Comment can not end with whitespace ( )."); - - validation.comment = false; - } else { - $("#validationwrapper-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").addClass("hidden").text(""); - - validation.comment = true; - } - - if (samba.share.additional.length > 0) { - samba.share.additional.forEach((_value, _index) => { - if (/[\\[\\]]/g.test(_value)) { //Do not allow section names - $("#helpblock-storagepool-filesystem-samba-configure-additional-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Additional must not contain brackets. Line: " + (_index + 1)); - - validation.additional = false; - return; - } else if (/^[#]/.test(_value) == false && /[=]/.test(_value) && /(path|comment|browseable|read only|guest ok).*=/gi.test(_value)) { - $("#helpblock-storagepool-filesystem-samba-configure-additional-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Additional must not contain duplicate properties. Line: " + (_index + 1)); - - validation.additional = false; - return; - } else if (/[#=]/.test(_value) == false) { - $("#helpblock-storagepool-filesystem-samba-configure-additional-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Additional must contain comments or properties only. Line: " + (_index + 1)); - - validation.additional = false; - return; - } else if (_index == (samba.share.additional.length -1)) { - $("#validationwrapper-storagepool-filesystem-samba-configure-additional-` + filesystem.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystem-samba-configure-additional-` + filesystem.id + `").removeClass("has-error").addClass("hidden").text(""); - - validation.additional = true; - } - }); - } else { - validation.additional = true; - } - - if (!validation.name || !validation.comment || !validation.additional) { - if (!validation.name) { - $("#validationwrapper-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").addClass("has-error"); - $("#input-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").focus(); - } - if (!validation.comment) { - $("#validationwrapper-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").addClass("has-error"); - $("#input-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").focus(); - } - if (!validation.additional) { - $("#validationwrapper-storagepool-filesystem-samba-configure-additional-` + filesystem.id + `").addClass("has-error"); - $("#textarea-storagepool-filesystem-samba-configure-additional-` + filesystem.id + `").focus(); - } - - $("#spinner-storagepool-filesystem-samba-configure-` + filesystem.id + `").addClass("hidden"); - $(this).prop("disabled", false); - } - - if (validation.name && validation.comment && validation.additional) { - samba.restart = $("#switch-storagepool-filesystem-samba-configure-restart-` + filesystem.id + ` input").prop("checked"); - samba.share.administrative = $("#switch-storagepool-filesystem-samba-configure-administrative-` + filesystem.id + ` input").prop("checked"); - samba.share.browseable = $("#switch-storagepool-filesystem-samba-configure-browseable-` + filesystem.id + ` input").prop("checked"); - samba.share.comment = $("#input-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").val(); - samba.share.guestok = $("#switch-storagepool-filesystem-samba-configure-guestok-` + filesystem.id + ` input").prop("checked"); - samba.share.name = $("#input-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").val(); - samba.share.nameexisting = $("#input-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").attr("data-field-value"); - samba.share.readonly = $("#switch-storagepool-filesystem-samba-configure-readonly-` + filesystem.id + ` input").prop("checked"); - - FnSambaZfsShareConfigure({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", mountpoint: "` + filesystem.mountpoint + `" }, { share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, nameexisting: samba.share.nameexisting, readonly: samba.share.readonly, temporary: ` + (pool.altroot || pool.readonly ? true : false) + ` }, restart: samba.restart }); - } - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalFileSystemSambaDisable(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, type }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-filesystem-samba-disable-` + filesystem.id + `").on("click", function () { - FnModalFileSystemSambaDisableContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", type: "` + filesystem.type + `" }, { id: $("#modal-storagepool-filesystem-samba-disable-` + filesystem.id + `") }); - }); - \x3C/script> - `; - - $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); -} - -function FnModalFileSystemSambaDisableContent(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, type }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-filesystem-samba-disable-apply-` + filesystem.id + `").on("click", function () { - $("#spinner-storagepool-filesystem-samba-disable-` + filesystem.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let samba = { - restart: $("#switch-storagepool-filesystem-samba-disable-restart-` + filesystem.id + ` input").prop("checked") - }; - - FnSambaShareDisable({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `" }, { restart: samba.restart }, { modal: true, silent: false }); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalFileSystemSambaEnable(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, mounted: false, mountpoint }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-filesystem-samba-enable-` + filesystem.id + `").on("click", function () { - FnModalFileSystemSambaEnableContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", mounted: ` + filesystem.mounted + `, mountpoint: "` + filesystem.mountpoint + `" }, { id: $("#modal-storagepool-filesystem-samba-enable-` + filesystem.id + `") }); - - setTimeout(function() { - $("#input-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").focus(); - }, 600); - }); - \x3C/script> - `; - - $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); -} - -function FnModalFileSystemSambaEnableContent(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, mounted: false, mountpoint }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#switch-storagepool-filesystem-samba-enable-additional-` + filesystem.id + ` input").on("click", function () { - $("#validationwrapper-storagepool-filesystem-samba-enable-additional-` + filesystem.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystem-samba-enable-additional-` + filesystem.id + `").removeClass("has-error").addClass("hidden").text(""); - - if ($(this).prop("checked")) { - $("#validationwrapper-storagepool-filesystem-samba-enable-additional-` + filesystem.id + `").removeClass("hidden"); - } else { - $("#validationwrapper-storagepool-filesystem-samba-enable-additional-` + filesystem.id + `").addClass("hidden"); - } - }); - - $("#btn-storagepool-filesystem-samba-enable-apply-` + filesystem.id + `").on("click", function () { - $("#spinner-storagepool-filesystem-samba-enable-` + filesystem.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let samba = { - share: { - additional: ($("#switch-storagepool-filesystem-samba-enable-additional-` + filesystem.id + ` input").prop("checked") ? $("#textarea-storagepool-filesystem-samba-enable-additional-` + filesystem.id + `").val().split("\\n").filter(v => v) : []), - administrative: false, - browseable: true, - comment: "", - guestok: false, - name: "", - readonly: false - } - }; - let validation = { - comment: false, - name: false, - additional: false - }; - - if ($("#input-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").val().length == 0) { - $("#helpblock-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Share name can not be empty."); - - validation.name = false; - } else if (/^[a-zA-Z0-9-_.@%+!#$^,(){}~ ]*$/.test($("#input-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").val()) == false) { - $("#helpblock-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Share name contains invalid characters."); - - validation.name = false; - } else if (/^[ ]/.test($("#input-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Share name can not begin with whitespace ( )."); - - validation.name = false; - } else if (/[ ]$/.test($("#input-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Share name can not end with whitespace ( )."); - - validation.name = false; - } else { - $("#validationwrapper-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").addClass("hidden").text(""); - - validation.name = true; - } - - if (/^[ -~]*$/.test($("#input-storagepool-filesystem-samba-enable-comment-` + filesystem.id + `").val()) == false) { - $("#helpblock-storagepool-filesystem-samba-enable-comment-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Comment contains invalid characters."); - - validation.comment = false; - } else if (/^[ ]/.test($("#input-storagepool-filesystem-samba-enable-comment-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-samba-enable-comment-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Comment can not begin with whitespace ( )."); - - validation.comment = false; - } else if (/[ ]$/.test($("#input-storagepool-filesystem-samba-enable-comment-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-samba-enable-comment-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Comment can not end with whitespace ( )."); - - validation.comment = false; - } else { - $("#validationwrapper-storagepool-filesystem-samba-enable-comment-` + filesystem.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystem-samba-enable-comment-` + filesystem.id + `").addClass("hidden").text(""); - - validation.comment = true; - } - - if (samba.share.additional.length > 0) { - samba.share.additional.forEach((_value, _index) => { - if (/[\\[\\]]/g.test(_value)) { //Do not allow section names - $("#helpblock-storagepool-filesystem-samba-enable-additional-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Additional must not contain brackets. Line: " + (_index + 1)); - - validation.additional = false; - return; - } else if (/^[#]/.test(_value) == false && /[=]/.test(_value) && /(path|comment|browseable|read only|guest ok).*=/gi.test(_value)) { - $("#helpblock-storagepool-filesystem-samba-enable-additional-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Additional must not contain duplicate properties. Line: " + (_index + 1)); - - validation.additional = false; - return; - } else if (/[#=]/.test(_value) == false) { - $("#helpblock-storagepool-filesystem-samba-enable-additional-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Additional must contain comments or properties only. Line: " + (_index + 1)); - - validation.additional = false; - return; - } else if (_index == (samba.share.additional.length -1)) { - $("#validationwrapper-storagepool-filesystem-samba-enable-additional-` + filesystem.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystem-samba-enable-additional-` + filesystem.id + `").removeClass("has-error").addClass("hidden").text(""); - - validation.additional = true; - } - }); - } else { - validation.additional = true; - } - - if (!validation.name || !validation.comment || !validation.additional) { - if (!validation.name) { - $("#validationwrapper-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").addClass("has-error"); - $("#input-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").focus(); - } - if (!validation.comment) { - $("#validationwrapper-storagepool-filesystem-samba-enable-comment-` + filesystem.id + `").addClass("has-error"); - $("#input-storagepool-filesystem-samba-enable-comment-` + filesystem.id + `").focus(); - } - if (!validation.additional) { - $("#validationwrapper-storagepool-filesystem-samba-enable-additional-` + filesystem.id + `").addClass("has-error"); - $("#textarea-storagepool-filesystem-samba-enable-additional-` + filesystem.id + `").focus(); - } - - $("#spinner-storagepool-filesystem-samba-enable-` + filesystem.id + `").addClass("hidden"); - $(this).prop("disabled", false); - } - - if (validation.name && validation.comment && validation.additional) { - samba.share.administrative = $("#switch-storagepool-filesystem-samba-enable-administrative-` + filesystem.id + ` input").prop("checked"); - samba.share.browseable = $("#switch-storagepool-filesystem-samba-enable-browseable-` + filesystem.id + ` input").prop("checked"); - samba.share.comment = $("#input-storagepool-filesystem-samba-enable-comment-` + filesystem.id + `").val(); - samba.share.guestok = $("#switch-storagepool-filesystem-samba-enable-guestok-` + filesystem.id + ` input").prop("checked"); - samba.share.name = $("#input-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").val(); - samba.share.readonly = $("#switch-storagepool-filesystem-samba-enable-readonly-` + filesystem.id + ` input").prop("checked"); - - FnSambaShareEnable({ name: "` + pool.name + `", id: "` + pool.id + `", readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", mounted: ` + filesystem.mounted + `, mountpoint: "` + filesystem.mountpoint + `" }, { share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: ` + (pool.altroot || pool.readonly ? true : false) + ` } }, { silent: false }); - } - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalFileSystemSnapshotCreate(pool = { name, id }, filesystem = { name, id }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-filesystem-snapshot-create-` + filesystem.id + `").on("click", function () { - FnModalFileSystemSnapshotCreateContent({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `" }, { id: $("#modal-storagepool-filesystem-snapshot-create-` + filesystem.id + `") }); - }); - \x3C/script> - `; - - $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); -} - -function FnModalFileSystemSnapshotCreateContent(pool = { name, id }, filesystem = { name, id }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#switch-storagepool-filesystem-snapshot-create-customname-` + filesystem.id + ` input").on("click", function () { - $("#validationwrapper-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").removeClass("has-error").addClass("hidden").text(""); - - if ($(this).prop("checked")) { - $("#input-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").val("").prop("readonly", false).focus(); - } else { - $("#input-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").val("YYYY.MM.DD-HH.MM.SS").prop("readonly", true);; - } - }); - - $("#btn-storagepool-filesystem-snapshot-create-apply-` + filesystem.id + `").on("click", function () { - $("#spinner-storagepool-filesystem-snapshot-create-` + filesystem.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let snapshot = { - name: "", - id: "", - recursive: false - }; - let validation = { - name: false - }; - - if ($("#input-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").val().length == 0) { - $("#helpblock-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not be empty."); - - validation.name = false; - } else if (/^[a-zA-Z0-9-_.: ]*$/.test($("#input-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").val()) == false) { - $("#helpblock-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name contains invalid characters."); - - validation.name = false; - } else if (/^[.]/.test($("#input-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a period (.)."); - - validation.name = false; - } else if (/^[_]/.test($("#input-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with an underscore (_)."); - - validation.name = false; - } else if (/^[-]/.test($("#input-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a hypen (-)."); - - validation.name = false; - } else if (/^[:]/.test($("#input-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with an colon (:)."); - - validation.name = false; - } else if (/^[ ]/.test($("#input-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with whitespace ( )."); - - validation.name = false; - } else if (/[ ]$/.test($("#input-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").val())) { - $("#helpblock-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not end with whitespace ( )."); - - validation.name = false; - } else { - $("#validationwrapper-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").addClass("hidden").text(""); - - validation.name = true; - } - - if (!validation.name) { - $("#validationwrapper-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").addClass("has-error"); - $("#input-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").focus(); - - $("#spinner-storagepool-filesystem-snapshot-create-` + filesystem.id + `").addClass("hidden"); - $(this).prop("disabled", false); - } - - if (validation.name) { - snapshot.name = "` + filesystem.name + `" + "@" + $("#input-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").val(); - snapshot.id = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: snapshot.name, attribute: true }); - snapshot.recursive = $("#switch-storagepool-filesystem-snapshot-create-recursive-` + filesystem.id + ` input").prop("checked"); - - if ($("#switch-storagepool-filesystem-snapshot-create-customname-` + filesystem.id + ` input").prop("checked")) { - FnSnapshotCreate({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: snapshot.name, id: snapshot.id, recursive: snapshot.recursive }, { name: "storagepool-filesystem-snapshot-create", id: "` + filesystem.id + `"}); - } else { - FnSnapshotCreateDateGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: snapshot.name, id: snapshot.id, recursive: snapshot.recursive }, { name: "storagepool-filesystem-snapshot-create", id: "` + filesystem.id + `"}); - } - } - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalFileSystemUnlock(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, sharesmb: false, type }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-filesystem-unlock-` + filesystem.id + `").on("click", function () { - FnModalFileSystemUnlockContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", sharesmb: ` + filesystem.sharesmb + `, type: "` + filesystem.type + `" }, { id: $("#modal-storagepool-filesystem-unlock-` + filesystem.id + `") }); - - setTimeout(function() { - $("#input-storagepool-filesystem-unlock-passphrase-` + filesystem.id + `").focus(); - }, 600); - }); - \x3C/script> - `; - - $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); -} - -function FnModalFileSystemUnlockContent(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, sharesmb: false, type }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#switch-storagepool-filesystem-unlock-mount-` + filesystem.id + ` input").on("click", function () { - if ($(this).prop("checked")) { - $("#switch-storagepool-filesystem-unlock-overlay-` + filesystem.id + `").parent().removeClass("hidden"); - } else { - $("#switch-storagepool-filesystem-unlock-overlay-` + filesystem.id + `").parent().addClass("hidden"); - } - }); - - $("#btn-storagepool-filesystem-unlock-apply-` + filesystem.id + `").on("click", function () { - $("#spinner-storagepool-filesystem-unlock-` + filesystem.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let filesystem = { - mount: true, - passphrase: "" - }; - let samba = { - enable: false - }; - let validation = { - passphrase: false - }; - - if ($("#input-storagepool-filesystem-unlock-passphrase-` + filesystem.id + `").val().length == 0) { - $("#helpblock-storagepool-filesystem-unlock-passphrase-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Passphrase can not be empty."); - - validation.passphrase = false; - } else if ($("#input-storagepool-filesystem-unlock-passphrase-` + filesystem.id + `").val().length < 8) { - $("#helpblock-storagepool-filesystem-unlock-passphrase-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Passphrase requires a minimum of 8 characters."); - - validation.passphrase = false; - } else if (/^[a-zA-Z0-9-_. \`~!@#$%^\(\)+\\[\\]{}:',/?]*$/.test($("#input-storagepool-filesystem-unlock-passphrase-` + filesystem.id + `").val()) == false) { - $("#helpblock-storagepool-filesystem-unlock-passphrase-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Passphrase contains invalid characters."); - - validation.passphrase = false; - } else { - $("#validationwrapper-storagepool-filesystem-unlock-passphrase-` + filesystem.id + `").removeClass("has-error"); - $("#helpblock-storagepool-filesystem-unlock-passphrase-` + filesystem.id + `").removeClass("has-error").addClass("hidden").text(""); - - validation.passphrase = true; - } - - if (!validation.passphrase) { - $("#validationwrapper-storagepool-filesystem-unlock-passphrase-` + filesystem.id + `").addClass("has-error"); - $("#input-storagepool-filesystem-unlock-passphrase-` + filesystem.id + `").focus(); - - $("#spinner-storagepool-filesystem-unlock-` + filesystem.id + `").addClass("hidden"); - $(this).prop("disabled", false); - } - - if (validation.passphrase) { - filesystem.mount = $("#switch-storagepool-filesystem-unlock-mount-` + filesystem.id + ` input").prop("checked"); - filesystem.overlay = $("#switch-storagepool-filesystem-unlock-overlay-` + filesystem.id + ` input").prop("checked"); - filesystem.passphrase = $("#input-storagepool-filesystem-unlock-passphrase-` + filesystem.id + `").val(); - - samba.enable = ` + ((pool.readonly || filesystem.sharesmb) ? false : `$("#switch-storagepool-filesystem-unlock-samba-enable-` + filesystem.id + ` input").prop("checked")`) + `; - - FnFileSystemUnlock({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", mount: filesystem.mount, overlay: filesystem.overlay, passphrase: filesystem.passphrase, type: "` + filesystem.type + `" }, { enable: samba.enable }, { name: "storagepool-filesystem-unlock", id: "` + filesystem.id + `" }, { refresh: true }); - } - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalFileSystemUnmount(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, encryptionroot, keystatus, sharesmb: false, type }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-filesystem-unmount-` + filesystem.id + `").on("click", function () { - FnModalFileSystemUnmountContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", encryptionroot: "` + filesystem.encryptionroot + `", keystatus: "` + filesystem.keystatus + `", sharesmb: ` + filesystem.sharesmb + `, type: "` + filesystem.type + `" }, { id: $("#modal-storagepool-filesystem-unmount-` + filesystem.id + `") }); - FnFileSystemsMountedGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `" }, { alert: { id: $("#div-storagepool-filesystem-unmount-warning-` + filesystem.id + `"), mount: false } }); - }); - \x3C/script> - `; - - $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); -} - -function FnModalFileSystemUnmountContent(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, encryptionroot, keystatus, sharesmb: false, type }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-filesystem-unmount-apply-` + filesystem.id + `").on("click", function () { - $("#spinner-storagepool-filesystem-unmount-` + filesystem.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let filesystem = { - force: $("#switch-storagepool-filesystem-unmount-force-` + filesystem.id + ` input").prop("checked"), - lock: ` + (filesystem.keystatus == "available" && filesystem.encryptionroot == filesystem.name ? `$("#switch-storagepool-filesystem-unmount-lock-` + filesystem.id + ` input").prop("checked")` : false) + ` - }; - let samba = { - disable: ` + ((!pool.readonly && filesystem.sharesmb) ? `$("#switch-storagepool-filesystem-unmount-samba-disable-` + filesystem.id + ` input").prop("checked")` : false) + `, - restart: $("#switch-storagepool-filesystem-unmount-samba-restart-` + filesystem.id + ` input").prop("checked") - }; - - FnFileSystemUnmount({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", force: filesystem.force, lock: filesystem.lock, type: "` + filesystem.type + `" }, { disable: samba.disable, restart: samba.restart }); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -//#endregion - -//#region Modal Snapshots - -function FnModalSnaphshotsCreate(pool = { name, id }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-snapshots-create-` + pool.id + `").on("click", function () { - FnModalSnaphshotsCreateContent({ name: "` + pool.name + `", id: "` + pool.id + `" }, { id: $("#modal-storagepool-snapshots-create-` + pool.id + `") }); - FnFileSystemsNamesGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { existing: { name: null, clone: false, encryption: false, encryptionroot: null, origin: null }, override: true }, { dropdown: { id: $("#dropdown-storagepool-snapshots-create-filesystem-` + pool.id + `"), selected: "` + pool.name + `" } }); - }); - \x3C/script> - `; - - $("#modals-storagepool-snapshots-" + pool.id).append(modal.window); -} - -function FnModalSnaphshotsCreateContent(pool = { name, id }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#switch-storagepool-snapshots-create-customname-` + pool.id + ` input").on("click", function () { - $("#validationwrapper-storagepool-snapshots-create-name-` + pool.id + `").removeClass("has-error"); - $("#helpblock-storagepool-snapshots-create-name-` + pool.id + `").removeClass("has-error").addClass("hidden").text(""); - - if ($(this).prop("checked")) { - $("#input-storagepool-snapshots-create-name-` + pool.id + `").val("").prop("readonly", false).focus(); - } else { - $("#input-storagepool-snapshots-create-name-` + pool.id + `").val("YYYY.MM.DD-HH.MM.SS").prop("readonly", true);; - } - }); - - $("#btn-storagepool-snapshots-create-apply-` + pool.id + `").on("click", function () { - $("#spinner-storagepool-snapshots-create-` + pool.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let snapshot = { - name: "", - id: "", - recursive: false - }; - let validation = { - name: false - }; - - if ($("#input-storagepool-snapshots-create-name-` + pool.id + `").val().length == 0) { - $("#helpblock-storagepool-snapshots-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not be empty."); - - validation.name = false; - } else if (/^[a-zA-Z0-9-_.: ]*$/.test($("#input-storagepool-snapshots-create-name-` + pool.id + `").val()) == false) { - $("#helpblock-storagepool-snapshots-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name contains invalid characters."); - - validation.name = false; - } else if (/^[.]/.test($("#input-storagepool-snapshots-create-name-` + pool.id + `").val())) { - $("#helpblock-storagepool-snapshots-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a period (.)."); - - validation.name = false; - } else if (/^[_]/.test($("#input-storagepool-snapshots-create-name-` + pool.id + `").val())) { - $("#helpblock-storagepool-snapshots-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with an underscore (_)."); - - validation.name = false; - } else if (/^[-]/.test($("#input-storagepool-snapshots-create-name-` + pool.id + `").val())) { - $("#helpblock-storagepool-snapshots-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a hypen (-)."); - - validation.name = false; - } else if (/^[:]/.test($("#input-storagepool-snapshots-create-name-` + pool.id + `").val())) { - $("#helpblock-storagepool-snapshots-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with an colon (:)."); - - validation.name = false; - } else if (/^[ ]/.test($("#input-storagepool-snapshots-create-name-` + pool.id + `").val())) { - $("#helpblock-storagepool-snapshots-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with whitespace ( )."); - - validation.name = false; - } else if (/[ ]$/.test($("#input-storagepool-snapshots-create-name-` + pool.id + `").val())) { - $("#helpblock-storagepool-snapshots-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not end with whitespace ( )."); - - validation.name = false; - } else { - $("#validationwrapper-storagepool-snapshots-create-name-` + pool.id + `").removeClass("has-error"); - $("#helpblock-storagepool-snapshots-create-name-` + pool.id + `").addClass("hidden").text(""); - - validation.name = true; - } - - if (!validation.name) { - $("#validationwrapper-storagepool-snapshots-create-name-` + pool.id + `").addClass("has-error"); - $("#input-storagepool-snapshots-create-name-` + pool.id + `").focus(); - - $("#spinner-storagepool-snapshots-create-` + pool.id + `").addClass("hidden"); - $(this).prop("disabled", false); - } - - if (validation.name) { - snapshot.name = $("#btnspan-storagepool-snapshots-create-filesystem-` + pool.id + `").attr("data-field-value") + "@" + $("#input-storagepool-snapshots-create-name-` + pool.id + `").val(); - snapshot.id = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: snapshot.name, attribute: true }); - snapshot.recursive = $("#switch-storagepool-snapshots-create-recursive-` + pool.id + ` input").prop("checked"); - - if ($("#switch-storagepool-snapshots-create-customname-` + pool.id + ` input").prop("checked")) { - FnSnapshotCreate({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: snapshot.name, id: snapshot.id, recursive: snapshot.recursive }, { name: "storagepool-snapshots-create", id: "` + pool.id + `"}); - } else { - FnSnapshotCreateDateGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: snapshot.name, id: snapshot.id, recursive: snapshot.recursive }, { name: "storagepool-snapshots-create", id: "` + pool.id + `"}); - } - } - }); - - $("#dropdown-storagepool-snapshots-create-filesystem-` + pool.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-snapshots-create-filesystem-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -//#endregion - -//#region Modal Snapshot - -function FnModalSnapshotClone(pool = { name, id, altroot: false }, snapshot = { name, id, encryption: false, encryptionroot }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-snapshot-clone-` + snapshot.id + `").on("click", function () { - FnModalSnapshotCloneContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + ` }, { name: "` + snapshot.name + `", id: "` + snapshot.id + `", encryption: ` + snapshot.encryption + ` }, { id: $("#modal-storagepool-snapshot-clone-` + snapshot.id + `") }); - FnFileSystemsNamesGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { existing: { name: null, clone: false, encryption: ` + snapshot.encryption + `, encryptionroot: "` + snapshot.encryptionroot + `", origin: null }, override: false }, { dropdown: { id: $("#dropdown-storagepool-snapshot-clone-parentfilesystem-` + snapshot.id + `"), selected: "` + snapshot.name.replace(/^(.*)\@.*$/, "$1") + `" } }); - - setTimeout(function() { - $("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").focus(); - }, 600); - }); - \x3C/script> - `; - - $("#modals-storagepool-snapshot-" + pool.id).append(modal.window); -} - -function FnModalSnapshotCloneContent(pool = { name, id, altroot: false }, snapshot = { name, id, encryption: false }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-snapshot-clone-apply-` + snapshot.id + `").on("click", function () { - $("#spinner-storagepool-snapshot-clone-` + snapshot.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let snapshot = { - clone: { - createnonexistparents: false, - name: "", - parent: "" - } - }; - let validation = { - name: false - }; - - if ($("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").val().length == 0) { - $("#helpblock-storagepool-snapshot-clone-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not be empty."); - - validation.name = false; - } else if (/^[a-zA-Z0-9-_.:/ ]*$/.test($("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").val()) == false) { - $("#helpblock-storagepool-snapshot-clone-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name contains invalid characters."); - - validation.name = false; - } else if (/^[.]/.test($("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").val())) { - $("#helpblock-storagepool-snapshot-clone-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a period (.)."); - - validation.name = false; - } else if (/^[_]/.test($("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").val())) { - $("#helpblock-storagepool-snapshot-clone-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with an underscore (_)."); - - validation.name = false; - } else if (/^[-]/.test($("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").val())) { - $("#helpblock-storagepool-snapshot-clone-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a hypen (-)."); - - validation.name = false; - } else if (/^[:]/.test($("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").val())) { - $("#helpblock-storagepool-snapshot-clone-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with an colon (:)."); - - validation.name = false; - } else if (/^[/]/.test($("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").val())) { - $("#helpblock-storagepool-snapshot-clone-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a forward slash (/)."); - - validation.name = false; - } else if (/[/]$/.test($("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").val())) { - $("#helpblock-storagepool-snapshot-clone-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not end with a forward slash (/)."); - - validation.name = false; - } else if (/^ |\\/ /.test($("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").val())) { - $("#helpblock-storagepool-snapshot-clone-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with whitespace ( )."); - - validation.name = false; - } else if (/ $| \\//.test($("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").val())) { - $("#helpblock-storagepool-snapshot-clone-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not end with whitespace ( )."); - - validation.name = false; - } else { - $("#validationwrapper-storagepool-snapshot-clone-name-` + snapshot.id + `").removeClass("has-error"); - $("#helpblock-storagepool-snapshot-clone-name-` + snapshot.id + `").removeClass("has-error").addClass("hidden").text(""); - - validation.name = true; - } - - if (!validation.name) { - $("#validationwrapper-storagepool-snapshot-clone-name-` + snapshot.id + `").addClass("has-error"); - $("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").focus(); - - $("#spinner-storagepool-snapshot-clone-` + snapshot.id + `").addClass("hidden"); - $(this).prop("disabled", false); - } - - if (validation.name) { - snapshot.clone.createnonexistparents = $("#switch-storagepool-snapshot-clone-createnonexistparents-` + snapshot.id + ` input").prop("checked"); - snapshot.clone.name = $("#btnspan-storagepool-snapshot-clone-parentfilesystem-` + snapshot.id + `").attr("data-field-value") + "/" + $("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").val(); - snapshot.clone.parent = $("#btnspan-storagepool-snapshot-clone-parentfilesystem-` + snapshot.id + `").attr("data-field-value"); - - FnSnapshotClone({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + ` }, { name: "` + snapshot.name + `", id: "` + snapshot.id + `", clone: { name: snapshot.clone.name, createnonexistparents: snapshot.clone.createnonexistparents, parent: snapshot.clone.parent } }); - } - }); - - $("#dropdown-storagepool-snapshot-clone-parentfilesystem-` + snapshot.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-snapshot-clone-parentfilesystem-` + snapshot.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalSnapshotDestroy(pool = { name, id, altroot: false, readonly: false }, snapshot = { name, id, clones: [] }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-snapshot-destroy-` + snapshot.id + `").on("click", function () { - FnModalSnapshotDestroyContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + snapshot.name + `", id: "` + snapshot.id + `", clones: [` + (snapshot.clones.length > 0 ? `"` + snapshot.clones.join(`","`) + `"` : ``) + `] }, { id: $("#modal-storagepool-snapshot-destroy-` + snapshot.id + `") }); - ` + (snapshot.clones.length > 0 ? `FnSnapshotChildFileSystemsGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + snapshot.name + `", id: "` + snapshot.id + `" }, { id: ` + (snapshot.clones.length > 0 ? `["` + snapshot.clones.join(`", "`) + `"]` : `[]`) + ` }, { name: "storagepool-snapshot-destroy", id: "` + snapshot.id + `" });` : ``) + ` - FnSnapshotChildSnapshotsGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + snapshot.name + `", id: "` + snapshot.id + `", exclude: false }, { id: ` + (snapshot.clones.length > 0 ? `["` + snapshot.clones.join(`", "`) + `"]` : `[]`) + ` }, { name: "storagepool-snapshot-destroy", id: "` + snapshot.id + `" }); - }); - \x3C/script> - `; - - $("#modals-storagepool-snapshot-" + pool.id).append(modal.window); -} - -function FnModalSnapshotDestroyContent(pool = { name, id, altroot: false, readonly: false }, snapshot = { name, id, clones: [] }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#switch-storagepool-snapshot-destroy-recursive-` + snapshot.id + ` input").on("click", function () { - if ($(this).prop("checked") && $("#switch-storagepool-snapshot-destroy-recursiveall-` + snapshot.id + ` input").prop("checked")) { - $("#switch-storagepool-snapshot-destroy-recursiveall-` + snapshot.id + ` input").click(); - } - - $("#panel-storagepool-snapshot-destroy-child-filesystems-` + snapshot.id + `").addClass("hidden"); - $("#panel-storagepool-snapshot-destroy-child-filesystems-` + snapshot.id + ` .collapse").collapse("hide"); - $("#panel-storagepool-snapshot-destroy-child-snapshotswithclones-` + snapshot.id + `").addClass("hidden"); - $("#panel-storagepool-snapshot-destroy-child-snapshotswithclones-` + snapshot.id + ` .collapse").collapse("hide"); - - if ($(this).prop("checked") && $("#panelgroup-storagepool-snapshot-destroy-` + snapshot.id + `").attr("data-snapshot-child-snapshots") > 0) { - $("#panel-storagepool-snapshot-destroy-child-snapshots-` + snapshot.id + `").removeClass("hidden"); - } else { - $("#panel-storagepool-snapshot-destroy-child-snapshots-` + snapshot.id + `").addClass("hidden"); - $("#panel-storagepool-snapshot-destroy-child-snapshots-` + snapshot.id + ` .collapse").collapse("hide"); - } - if ($(this).prop("checked") && $("#panelgroup-storagepool-snapshot-destroy-` + snapshot.id + `").attr("data-snapshot-child-snapshots") > 0) { - $("#panelgroup-storagepool-snapshot-destroy-` + snapshot.id + `").addClass("modal-ct-bodytext-1"); - } else { - $("#panelgroup-storagepool-snapshot-destroy-` + snapshot.id + `").removeClass("modal-ct-bodytext-1"); - } - }); - - $("#switch-storagepool-snapshot-destroy-recursiveall-` + snapshot.id + ` input").on("click", function () { - if ($(this).prop("checked") && $("#switch-storagepool-snapshot-destroy-recursive-` + snapshot.id + ` input").prop("checked")) { - $("#switch-storagepool-snapshot-destroy-recursive-` + snapshot.id + ` input").click(); - } - - $("#panel-storagepool-snapshot-destroy-child-filesystems-` + snapshot.id + `").addClass("hidden"); - $("#panel-storagepool-snapshot-destroy-child-filesystems-` + snapshot.id + ` .collapse").collapse("hide"); - $("#panel-storagepool-snapshot-destroy-child-snapshots-` + snapshot.id + `").addClass("hidden"); - $("#panel-storagepool-snapshot-destroy-child-snapshots-` + snapshot.id + ` .collapse").collapse("hide"); - - if ($(this).prop("checked") && $("#panelgroup-storagepool-snapshot-destroy-` + snapshot.id + `").attr("data-snapshot-child-filesystems") > 0) { - $("#panel-storagepool-snapshot-destroy-child-filesystems-` + snapshot.id + `").removeClass("hidden"); - } else { - $("#panel-storagepool-snapshot-destroy-child-filesystems-` + snapshot.id + `").addClass("hidden"); - $("#panel-storagepool-snapshot-destroy-child-filesystems-` + snapshot.id + ` .collapse").collapse("hide"); - } - if ($(this).prop("checked") && $("#panelgroup-storagepool-snapshot-destroy-` + snapshot.id + `").attr("data-snapshot-child-snapshotswithclones") > 0) { - $("#panel-storagepool-snapshot-destroy-child-snapshotswithclones-` + snapshot.id + `").removeClass("hidden"); - } else { - $("#panel-storagepool-snapshot-destroy-child-snapshotswithclones-` + snapshot.id + `").addClass("hidden"); - $("#panel-storagepool-snapshot-destroy-child-snapshotswithclones-` + snapshot.id + ` .collapse").collapse("hide"); - } - if ($(this).prop("checked") && ($("#panelgroup-storagepool-snapshot-destroy-` + snapshot.id + `").attr("data-snapshot-child-snapshotswithclones") > 0 || $("#panelgroup-storagepool-snapshot-destroy-` + snapshot.id + `").attr("data-snapshot-child-snapshotswithclones") > 0)) { - $("#panelgroup-storagepool-snapshot-destroy-` + snapshot.id + `").addClass("modal-ct-bodytext-1"); - } else { - $("#panelgroup-storagepool-snapshot-destroy-` + snapshot.id + `").removeClass("modal-ct-bodytext-1"); - } - }); - - $("#btn-storagepool-snapshot-destroy-apply-` + snapshot.id + `").on("click", function () { - $("#spinner-storagepool-snapshot-destroy-` + snapshot.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let snapshot = { - recursive: $("#switch-storagepool-snapshot-destroy-recursive-` + snapshot.id + ` input").prop("checked"), - recursiveall: $("#switch-storagepool-snapshot-destroy-recursiveall-` + snapshot.id + ` input").prop("checked") - }; - let samba = { - restart: $("#switch-storagepool-snapshot-destroy-samba-restart-` + snapshot.id + ` input").prop("checked") - }; - - FnSnapshotDestroy({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + snapshot.name + `", id: "` + snapshot.id + `", clones: ` + (snapshot.clones.length > 0 ? `["` + snapshot.clones.join(`", "`) + `"]` : `[]`) + `, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { restart: samba.restart }); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalSnapshotRename(pool = { name, id }, snapshot = { name, id, creation }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-snapshot-rename-` + snapshot.id + `").on("click", function () { - FnModalSnapshotRenameContent({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + snapshot.name + `", id: "` + snapshot.id + `", creation: "` + snapshot.creation + `" }, { id: $("#modal-storagepool-snapshot-rename-` + snapshot.id + `") }); - - setTimeout(function() { - $("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").focus(); - }, 600); - }); - \x3C/script> - `; - - $("#modals-storagepool-snapshot-" + pool.id).append(modal.window); -} - -function FnModalSnapshotRenameContent(pool = { name, id }, snapshot = { name, id, creation }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#switch-storagepool-snapshot-rename-creationdate-` + snapshot.id + ` input").on("click", function () { - if ($(this).prop("checked")) { - $("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").val("` + FnDateTimeSnapshot({ date: new Date(snapshot.creation * 1000) }) + `").prop("readonly", true); - } else { - $("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").val("` + snapshot.name.replace(/^.*\@(.*)$/, "$1") + `").prop("readonly", false).focus(); - } - }); - - $("#btn-storagepool-snapshot-rename-apply-` + snapshot.id + `").on("click", function () { - $("#spinner-storagepool-snapshot-rename-` + snapshot.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let snapshot = { - namenew: "", - recursive: false - }; - let validation = { - name: false - }; - - if ("` + snapshot.name.replace(/^(.*)\@.*$/, "$1") + `" + "@" + $("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").val() == "` + snapshot.name + `") { - $("#helpblock-storagepool-snapshot-rename-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name must be different."); - - validation.name = false; - } else if ($("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").val().length == 0) { - $("#helpblock-storagepool-snapshot-rename-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not be empty."); - - validation.name = false; - } else if (/^[a-zA-Z0-9-_.: ]*$/.test($("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").val()) == false) { - $("#helpblock-storagepool-snapshot-rename-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name contains invalid characters."); - - validation.name = false; - } else if (/^[.]/.test($("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").val())) { - $("#helpblock-storagepool-snapshot-rename-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a period (.)."); - - validation.name = false; - } else if (/^[_]/.test($("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").val())) { - $("#helpblock-storagepool-snapshot-rename-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with an underscore (_)."); - - validation.name = false; - } else if (/^[-]/.test($("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").val())) { - $("#helpblock-storagepool-snapshot-rename-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a hypen (-)."); - - validation.name = false; - } else if (/^[:]/.test($("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").val())) { - $("#helpblock-storagepool-snapshot-rename-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with an colon (:)."); - - validation.name = false; - } else if (/^[ ]/.test($("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").val())) { - $("#helpblock-storagepool-snapshot-rename-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with whitespace ( )."); - - validation.name = false; - } else if (/[ ]$/.test($("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").val())) { - $("#helpblock-storagepool-snapshot-rename-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not end with whitespace ( )."); - - validation.name = false; - } else { - $("#validationwrapper-storagepool-snapshot-rename-name-` + snapshot.id + `").removeClass("has-error"); - $("#helpblock-storagepool-snapshot-rename-name-` + snapshot.id + `").removeClass("has-error").addClass("hidden").text(""); - - validation.name = true; - } - - if (!validation.name) { - $("#validationwrapper-storagepool-snapshot-rename-name-` + snapshot.id + `").addClass("has-error"); - $("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").focus(); - - $("#spinner-storagepool-snapshot-rename-` + snapshot.id + `").addClass("hidden"); - $(this).prop("disabled", false); - } - - if (validation.name) { - snapshot.namenew = "` + snapshot.name.replace(/^(.*)\@.*$/, "$1") + `" + "@" + $("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").val(); - snapshot.recursive = $("#switch-storagepool-snapshot-rename-recursive-` + snapshot.id + ` input").prop("checked"); - - FnSnapshotRename({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + snapshot.name + `", id: "` + snapshot.id + `", namenew: snapshot.namenew, recursive: snapshot.recursive }); - } - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalSnapshotRollBack(pool = { name, id, altroot: false, readonly: false }, snapshot = { name, id, creation }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-snapshot-rollback-` + snapshot.id + `").on("click", function () { - FnModalSnapshotRollBackContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + snapshot.name + `", id: "` + snapshot.id + `", creation: "` + snapshot.creation + `" }, { id: $("#modal-storagepool-snapshot-rollback-` + snapshot.id + `") }); - FnSnapshotRollBackSnapshotsGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + snapshot.name + `", id: "` + snapshot.id + `", creation: "` + snapshot.creation + `" }, { name: "storagepool-snapshot-rollback", id: "` + snapshot.id + `" }); - }); - \x3C/script> - `; - - $("#modals-storagepool-snapshot-" + pool.id).append(modal.window); -} - -function FnModalSnapshotRollBackContent(pool = { name, id, altroot: false, readonly: false }, snapshot = { name, id, creation }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#switch-storagepool-snapshot-rollback-recursive-` + snapshot.id + ` input").on("click", function () { - if ($(this).prop("checked") && $("#switch-storagepool-snapshot-rollback-recursiveall-` + snapshot.id + ` input").prop("checked")) { - $("#switch-storagepool-snapshot-rollback-recursiveall-` + snapshot.id + ` input").click(); - } - - $("#panel-storagepool-snapshot-rollback-child-filesystems-` + snapshot.id + `").addClass("hidden"); - $("#panel-storagepool-snapshot-rollback-child-filesystems-` + snapshot.id + ` .collapse").collapse("hide"); - $("#panel-storagepool-snapshot-rollback-child-snapshotswithclones-` + snapshot.id + `").addClass("hidden"); - $("#panel-storagepool-snapshot-rollback-child-snapshotswithclones-` + snapshot.id + ` .collapse").collapse("hide"); - - if ($(this).prop("checked") && $("#panelgroup-storagepool-snapshot-rollback-` + snapshot.id + `").attr("data-snapshot-snapshots") > 0) { - $("#panel-storagepool-snapshot-rollback-snapshots-` + snapshot.id + `").removeClass("hidden"); - } else { - $("#panel-storagepool-snapshot-rollback-snapshots-` + snapshot.id + `").addClass("hidden"); - $("#panel-storagepool-snapshot-rollback-snapshots-` + snapshot.id + ` .collapse").collapse("hide"); - } - }); - - $("#switch-storagepool-snapshot-rollback-recursiveall-` + snapshot.id + ` input").on("click", function () { - if ($(this).prop("checked") && $("#switch-storagepool-snapshot-rollback-recursive-` + snapshot.id + ` input").prop("checked")) { - $("#switch-storagepool-snapshot-rollback-recursive-` + snapshot.id + ` input").click(); - } - - if ($(this).prop("checked")) { - $("#switch-storagepool-snapshot-rollback-force-` + snapshot.id + `").parent().removeClass("hidden"); - } else { - $("#switch-storagepool-snapshot-rollback-force-` + snapshot.id + `").parent().addClass("hidden"); - - if ($("#switch-storagepool-snapshot-rollback-force-` + snapshot.id + ` input").prop("checked")) { - $("#switch-storagepool-snapshot-rollback-force-` + snapshot.id + ` input").click(); - } - } - - $("#panel-storagepool-snapshot-rollback-child-filesystems-` + snapshot.id + `").addClass("hidden"); - $("#panel-storagepool-snapshot-rollback-child-filesystems-` + snapshot.id + ` .collapse").collapse("hide"); - $("#panel-storagepool-snapshot-rollback-snapshots-` + snapshot.id + `").addClass("hidden"); - $("#panel-storagepool-snapshot-rollback-snapshots-` + snapshot.id + ` .collapse").collapse("hide"); - - if ($(this).prop("checked") && $("#panelgroup-storagepool-snapshot-rollback-` + snapshot.id + `").attr("data-snapshot-child-filesystems") > 0) { - $("#panel-storagepool-snapshot-rollback-child-filesystems-` + snapshot.id + `").removeClass("hidden"); - } else { - $("#panel-storagepool-snapshot-rollback-child-filesystems-` + snapshot.id + `").addClass("hidden"); - $("#panel-storagepool-snapshot-rollback-child-filesystems-` + snapshot.id + ` .collapse").collapse("hide"); - } - if ($(this).prop("checked") && $("#panelgroup-storagepool-snapshot-rollback-` + snapshot.id + `").attr("data-snapshot-child-snapshotswithclones") > 0) { - $("#panel-storagepool-snapshot-rollback-child-snapshotswithclones-` + snapshot.id + `").removeClass("hidden"); - } else { - $("#panel-storagepool-snapshot-rollback-child-snapshotswithclones-` + snapshot.id + `").addClass("hidden"); - $("#panel-storagepool-snapshot-rollback-child-snapshotswithclones-` + snapshot.id + ` .collapse").collapse("hide"); - } - }); - - $("#btn-storagepool-snapshot-rollback-apply-` + snapshot.id + `").on("click", function () { - $("#spinner-storagepool-snapshot-rollback-` + snapshot.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let snapshot = { - force: ($("#switch-storagepool-snapshot-rollback-recursiveall-` + snapshot.id + ` input").prop("checked") ? $("#switch-storagepool-snapshot-rollback-force-` + snapshot.id + ` input").prop("checked") : false), - recursive: $("#switch-storagepool-snapshot-rollback-recursive-` + snapshot.id + ` input").prop("checked"), - recursiveall: $("#switch-storagepool-snapshot-rollback-recursiveall-` + snapshot.id + ` input").prop("checked") - }; - let samba = { - restart: $("#switch-storagepool-snapshot-rollback-samba-restart-` + snapshot.id + ` input").prop("checked") - }; - - FnSnapshotRollBack({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + snapshot.name + `", id: "` + snapshot.id + `", creation: "` + snapshot.creation + `", force: snapshot.force, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { restart: samba.restart }); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -//#endregion - -//#region Modal Status - -function FnModalStatusDiskAttach(pool = { name, id, status: { config: { items: { index: 0 }, tier: { name, dedup: false, logs: false, special: false } } } }, virtualdevice = { id, disk: true }) { - let modal = { - tiername: (pool.status.config.tier.dedup ? "Dedup" : (pool.status.config.tier.logs ? "Log" : (pool.status.config.tier.special ? "Special" : pool.status.config.tier.name))), - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-disk-attach-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); - FnModalStatusDiskAttachContent({ name: "` + pool.name + `", id: "` + pool.id + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: "` + virtualdevice.id + `" , disk: ` + virtualdevice.disk + ` }, { id: $("#modal-storagepool-status-disk-attach-` + pool.status.config.items.index + `-` + pool.id + `"), tiername: "` + modal.tiername + `" }); - FnDisksAvailableGet({ name: "storagepool-status-disk-attach-disks", id: "` + pool.status.config.items.index + `-` + pool.id + `", default: true }); - }); - \x3C/script> - `; - - $("#modals-storagepool-status-" + pool.id).append(modal.window); -} - -function FnModalStatusDiskAttachContent(pool = { name, id, status: { config: { items: { index: 0 } } } }, virtualdevice = { id, disk: true }, modal = { id, tiername }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#switch-storagepool-status-disk-attach-disks-wwn-` + pool.status.config.items.index + `-` + pool.id + ` input").on("click", function () { - $("#btnspan-storagepool-status-disk-attach-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").text("Block Device"); - $("#dropdown-storagepool-status-disk-attach-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + ` li").siblings().removeClass("active"); - $("#dropdown-storagepool-status-disk-attach-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + ` li[value='blockdevice']").addClass("active"); - $("#helpblock-storagepool-status-disk-attach-disks-identifierwarning-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden").text(""); - ` + (zfsmanager.zfs.warnings.nvmevdev ? `$("#helpblock-storagepool-status-disk-attach-disks-identifierwarningzfs-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden");` : ``) + ` - - let disk = { - identifier: ($(this).prop("checked") ? "wwn" : "blockdevice"), - identifiertext: ($(this).prop("checked") ? "WWN" : "Block Device") - }; - - if ($(this).prop("checked")) { - $("#controllabel-storagepool-status-disk-attach-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden"); - $("#validationwrapper-storagepool-status-disk-attach-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden"); - } else { - $("#controllabel-storagepool-status-disk-attach-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - $("#validationwrapper-storagepool-status-disk-attach-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - } - - $("#listgroup-storagepool-status-disk-attach-disks-` + pool.status.config.items.index + `-` + pool.id + ` input[name='checkbox-storagepool-status-disk-attach-disks-` + pool.status.config.items.index + `-` + pool.id + `']").map(function () { - if ($(this).attr("data-disk-id-" + disk.identifier)) { - $(this).next().find(".select-ct-disk-row-id").text((disk.identifier == "blockdevice" ? "/dev/" : "") + $(this).attr("data-disk-id-" + disk.identifier)); - $(this).attr("data-disk-name", $(this).attr("data-disk-id-" + disk.identifier)); - } else { - $(this).next().find(".select-ct-disk-row-id").text("/dev/" + $(this).attr("data-disk-id-blockdevice")); - $(this).attr("data-disk-name", $(this).attr("data-disk-id-blockdevice")); - $("#helpblock-storagepool-status-disk-attach-disks-identifierwarning-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One or more disks is missing a " + disk.identifiertext + " identifier."); - } - }); - }); - - $("#btn-storagepool-status-disk-attach-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - $("#spinner-storagepool-status-disk-attach-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let disk = { - idnew: [] - }; - let modal = { - name: "", - id: "" - }; - let pool = { - force: false - }; - let validation = { - disks: false - }; - - $("#listgroup-storagepool-status-disk-attach-disks-` + pool.status.config.items.index + `-` + pool.id + ` input[name='checkbox-storagepool-status-disk-attach-disks-` + pool.status.config.items.index + `-` + pool.id + `']:checked").map(function () { - disk.idnew.push($(this).attr("data-disk-name")); - }); - - if (disk.idnew.length != 1) { - $("#helpblock-storagepool-status-disk-attach-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One disk is needed."); - - validation.disks = false; - } else { - $("#validationwrapper-storagepool-status-disk-attach-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("has-error"); - $("#helpblock-storagepool-status-disk-attach-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text(""); - - validation.disks = true; - } - - if (!validation.disks) { - $("#validationwrapper-storagepool-status-disk-attach-disks-` + pool.status.config.items.index + `-` + pool.id + `").addClass("has-error"); - - $("#spinner-storagepool-status-disk-attach-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden"); - $(this).prop("disabled", false); - } - - if (validation.disks) { - modal.name = "storagepool-status-disk-attach"; - modal.id = "` + pool.status.config.items.index + `-` + pool.id + `"; - - pool.force = $("#switch-storagepool-status-disk-attach-force-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked"); - - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolDiskAttach({ name: "` + pool.name + `", id: "` + pool.id + `", force: pool.force }, { id: "` + virtualdevice.id + `", disk: ` + virtualdevice.disk + ` }, { idnew: disk.idnew }, { name: modal.name, id: modal.id }); - } - }); - - $("#dropdown-storagepool-status-disk-attach-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-status-disk-attach-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - - $("#helpblock-storagepool-status-disk-attach-disks-identifierwarning-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden").text(""); - ` + (zfsmanager.zfs.warnings.nvmevdev ? `$("#helpblock-storagepool-status-disk-attach-disks-identifierwarningzfs-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden");` : ``) + ` - - let disk = { - identifier: $(this).parent().attr("value"), - identifiertext: $(this).parent().text() - }; - - $("#listgroup-storagepool-status-disk-attach-disks-` + pool.status.config.items.index + `-` + pool.id + ` input[name='checkbox-storagepool-status-disk-attach-disks-` + pool.status.config.items.index + `-` + pool.id + `']").map(function () { - if ($(this).attr("data-disk-id-" + disk.identifier)) { - $(this).next().find(".select-ct-disk-row-id").text((disk.identifier == "blockdevice" ? "/dev/" : "") + $(this).attr("data-disk-id-" + disk.identifier)); - $(this).attr("data-disk-name", $(this).attr("data-disk-id-" + disk.identifier)); - } else { - $(this).next().find(".select-ct-disk-row-id").text("/dev/" + $(this).attr("data-disk-id-blockdevice")); - $(this).attr("data-disk-name", $(this).attr("data-disk-id-blockdevice")); - $("#helpblock-storagepool-status-disk-attach-disks-identifierwarning-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One or more disks is missing a " + disk.identifiertext + " identifier."); - +} + +function FnStoragePoolsGetCommand(process = { data, message }) { + let pools = { + id: [] + }; + + pools.id = process.data.split(/\n/g).filter(v => { + if (!zfsmanager.configuration.zfs.storagepool.boot && zfsmanager.zfs.storagepool.boot && new RegExp("^" + zfsmanager.zfs.storagepool.boot + "\t").test(v)) { + //Do not display boot + } else if (!zfsmanager.configuration.zfs.storagepool.root && zfsmanager.zfs.storagepool.root && new RegExp("^" + zfsmanager.zfs.storagepool.root + "\t").test(v)) { + //Do not display root + } else { + return v; + } + }); + + pools.id.forEach((_value, _index) => { + let pool = { + properties: _value.split(/\t/g).filter(v => v), + actionsmenu: { + register: {} + } + }; + + //0=name, 1=guid, 2=health, 3=size, 4=alloc, 5=free, 6=fragmentation, 7=readonly, 8=altroot, 9=autotrim, 10=version, 11=feature@allocation_classes, 12=feature@async_destroy, 13=feature@bookmark_v2, 14=feature@bookmarks, 15=feature@device_removal, 16=feature@edonr, 17=feature@embedded_data, 18=feature@empty_bpobj, 19=feature@enabled_txg, 20=feature@encryption, 21=feature@extensible_dataset, 22=feature@filesystem_limits, 23=feature@hole_birth, 24=feature@large_blocks, 25=feature@large_dnode, 26=feature@lz4_compress, 27=feature@multi_vdev_crash_dump, 28=feature@obsolete_counts, 29=feature@project_quota, 30=feature@resilver_defer, 31=feature@sha512, 32=feature@skein, 33=feature@spacemap_histogram, 34=feature@spacemap_v2, 35=feature@userobj_accounting, 36=feature@zpool_checkpoint + + pool.activetab = "filesystems"; + pool.allocated = FnFormatBytes({ base2: true, decimals: 2, value: pool.properties[4] }); + pool.allocatedpercent = FnRound({ decimals: 2, value: (pool.properties[4] / pool.properties[3]) * 100 }); + pool.altroot = (pool.properties[8] && pool.properties[8] != "-" ? true : false); + pool.autotrim = (pool.properties[9].toLowerCase() == "on" ? true : false); + pool.boot = (zfsmanager.zfs.storagepool.boot && pool.properties[0] == zfsmanager.zfs.storagepool.boot ? true : false); + pool.feature = { + allocation_classes: (/active|enabled/gi.test(pool.properties[11]) ? true : false), + async_destroy: (/active|enabled/gi.test(pool.properties[12]) ? true : false), + bookmark_v2: (/active|enabled/gi.test(pool.properties[13]) ? true : false), + bookmarks: (/active|enabled/gi.test(pool.properties[14]) ? true : false), + device_removal: (/active|enabled/gi.test(pool.properties[15]) ? true : false), + edonr: (/active|enabled/gi.test(pool.properties[16]) ? true : false), + embedded_data: (/active|enabled/gi.test(pool.properties[17]) ? true : false), + empty_bpobj: (/active|enabled/gi.test(pool.properties[18]) ? true : false), + enabled_txg: (/active|enabled/gi.test(pool.properties[19]) ? true : false), + encryption: (/active|enabled/gi.test(pool.properties[20]) ? true : false), + extensible_dataset: (/active|enabled/gi.test(pool.properties[21]) ? true : false), + filesystem_limits: (/active|enabled/gi.test(pool.properties[22]) ? true : false), + hole_birth: (/active|enabled/gi.test(pool.properties[23]) ? true : false), + large_blocks: (/active|enabled/gi.test(pool.properties[24]) ? true : false), + large_dnode: (/active|enabled/gi.test(pool.properties[25]) ? true : false), + lz4_compress: (/active|enabled/gi.test(pool.properties[26]) ? true : false), + multi_vdev_crash_dump: (/active|enabled/gi.test(pool.properties[27]) ? true : false), + obsolete_counts: (/active|enabled/gi.test(pool.properties[28]) ? true : false), + project_quota: (/active|enabled/gi.test(pool.properties[29]) ? true : false), + resilver_defer: (/active|enabled/gi.test(pool.properties[30]) ? true : false), + sha512: (/active|enabled/gi.test(pool.properties[31]) ? true : false), + skein: (/active|enabled/gi.test(pool.properties[32]) ? true : false), + spacemap_histogram: (/active|enabled/gi.test(pool.properties[33]) ? true : false), + spacemap_v2: (/active|enabled/gi.test(pool.properties[34]) ? true : false), + userobj_accounting: (/active|enabled/gi.test(pool.properties[35]) ? true : false), + zpool_checkpoint: (/active|enabled/gi.test(pool.properties[36]) ? true : false) + }; + pool.fragmentation = (pool.properties[6] == "-" ? 0 : pool.properties[6]); + pool.free = FnFormatBytes({ base2: true, decimals: 2, value: pool.properties[5] }); + pool.freepercent = FnRound({ decimals: 2, value: (pool.properties[5] / pool.properties[3]) * 100 }); + pool.guid = pool.properties[1]; + pool.health = pool.properties[2]; + pool.healthicon = FnStoragePoolHealthIcon({ health: pool.properties[2] }); + pool.id = FnGenerateId({ at: false, colon: true, forwardslash: false, period: true, underscore: true, whitespace: true }, { name: pool.properties[0], attribute: true }); + pool.name = pool.properties[0]; + pool.readonly = ((pool.properties[7].toLowerCase() == "on" || pool.boot && zfsmanager.configuration.zfs.storagepool.bootlockdown) ? true : false); + pool.size = FnFormatBytes({ base2: true, decimals: 2, value: pool.properties[3] }); + pool.root = (zfsmanager.zfs.storagepool.root && pool.properties[0] == zfsmanager.zfs.storagepool.root ? true : false); + pool.upgrade = ($.isNumeric(pool.properties[8] && !pool.boot) ? true : false); + pool.version = pool.properties[10]; + + //Upgrade available if a requested feature flag returns false + if (!pool.boot) { + for (var x in pool.feature) { + if (!pool.feature[x] && !pool.upgrade) { + pool.upgrade = true; + } + } + } + + $("#modals-storagepool-" + pool.id).remove(); + $("#modals").append(`
    `); + + pool.output = ` + + + + Name:` + pool.name + (pool.readonly ? ` ` : (pool.altroot ? ` ` : ``)) + ` + + Health:
    ` + pool.health + `
    + + + Size:
    ` + pool.size + `
    + + + Allocated:
    ` + pool.allocated + `
    + + + Free:
    ` + pool.free + `
    + + + Fragmentation:
    ` + pool.fragmentation + ` %
    + + + Usage: +
    +
    + ` + pool.allocatedpercent + `% Allocated +
    +
    + ` + pool.freepercent + `% Free +
    +
    + + + Upgrade Available: + ` + (pool.upgrade ? `Yes` : `No`) + ` + + + `; + + //Actions menu + pool.actionsmenu.items = { + itemconfigure: [], + itemconfiguredivider: function () { + if (this.itemconfigure.length > 0 && (this.itemconfigurefeatures.length > 0 || this.item.length > 0)) { + this.itemconfigure.push(this.divider); + } + }, + itemconfigurefeatures: [], + itemconfigurefeaturesdivider: function () { + if (this.itemconfigurefeatures.length > 0 && this.item.length > 0) { + this.itemconfigurefeatures.push(this.divider); + } + }, + item: [], + divider: `` + }; + pool.actionsmenu.display = function () { + if ((this.items.itemconfigure.length + this.items.itemconfigurefeatures.length + this.items.item.length) > 0) { + this.items.itemconfiguredivider(); + this.items.itemconfigurefeaturesdivider(); + + return this.header + this.items.itemconfigure.join("\n") + this.items.itemconfigurefeatures.join("\n") + this.items.item.join("\n") + this.footer; + } else { + return ""; + } + }; + pool.actionsmenu.header = ` + + `; + + //Configure Storage Pool + pool.actionsmenu.items.itemconfigure.push(`
  • Configure Storage Pool
  • `); + + //Configure Storage Pool Features + pool.actionsmenu.items.itemconfigurefeatures.push(`
  • Configure Storage Pool Features
  • `); + + //Export Storage Pool + if (!pool.boot && !pool.root) { + pool.actionsmenu.items.item.push(`
  • Export Storage Pool
  • `); + + pool.actionsmenu.register.export = true; + } + + //Destroy Storage Pool + if (!pool.readonly && !pool.boot && !pool.root) { + pool.actionsmenu.items.item.push(`
  • Destroy Storage Pool
  • `); + + pool.actionsmenu.register.destroy = true; + } + + pool.output += `` + pool.actionsmenu.display() + ``; + + if (zfsmanager.configuration.zfs.storagepool.activetab == 2) { + pool.activetab = "snapshots"; + } else if (zfsmanager.configuration.zfs.storagepool.activetab == 3) { + pool.activetab = "status"; + } + + pool.output += ` + + + + + +
    +
    +
    + + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + //Set active tab + $("#tab-storagepool-` + pool.activetab + `-` + pool.id + `").tab("show"); + + $("#btn-storagepool-filesystems-refresh-` + pool.id + `").on("click", function () { + $("#btn-storagepool-filesystems-create-` + pool.id + `").prop("disabled", true); + $("#btn-storagepool-filesystems-refresh-` + pool.id + `").prop("disabled", true); + + $("[id^=btn-storagepool-filesystem-dropdown-` + pool.id + `]").addClass("disabled"); + $("#paneltitle-storagepool-filesystems-` + pool.id + `").addClass("hidden"); + $("#spinner-storagepool-filesystems-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolRefresh({ name: "` + pool.name + `", id: "` + pool.id + `" }, { storagepool: true, filesystems: true, snapshots: false, status: false }); + }); + + $("#btn-storagepool-snapshots-refresh-` + pool.id + `").on("click", function () { + $("#btn-storagepool-snapshots-create-` + pool.id + `").prop("disabled", true); + $("#btn-storagepool-snapshots-refresh-` + pool.id + `").prop("disabled", true); + + $("[id^=btn-storagepool-snapshot-dropdown-` + pool.id + `]").addClass("disabled"); + $("#paneltitle-storagepool-snapshots-` + pool.id + `").addClass("hidden"); + $("#spinner-storagepool-snapshots-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolRefresh({ name: "` + pool.name + `", id: "` + pool.id + `" }, { storagepool: true, filesystems: false, snapshots: true, status: false }); + }); + + $("#btn-storagepool-status-refresh-` + pool.id + `").on("click", function () { + FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); + + $(this).text("Refresh").prop("disabled", true); + $("#btn-storagepool-status-refresh-auto-` + pool.id + `").prop("disabled", true).parent().removeClass("open");; + + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#paneltitle-storagepool-status-` + pool.id + `").addClass("hidden"); + $("#spinner-storagepool-status-` + pool.id + `").removeClass("hidden"); + $("#spinner-storagepool-status-0-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolRefresh({ name: "` + pool.name + `", id: "` + pool.id + `" }, { storagepool: true, filesystems: false, snapshots: false, status: true }); + }); + + $("#dropdown-storagepool-status-refresh-` + pool.id + `").on("click", "li a", function () { + FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); + $("#btn-storagepool-status-refresh-` + pool.id + `").click(); + + if ($(this).attr("data-pool-refresh-interval") > 0) { + let statusrefreshtimer` + _index + ` = setInterval(function () { + $("#btn-storagepool-status-refresh-` + pool.id + `").prop("disabled", true); + $("#btn-storagepool-status-refresh-auto-` + pool.id + `").prop("disabled", true).parent().removeClass("open"); + + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#paneltitle-storagepool-status-` + pool.id + `").addClass("hidden"); + $("#spinner-storagepool-status-` + pool.id + `").removeClass("hidden"); + $("#spinner-storagepool-status-0-` + pool.id + `").removeClass("hidden"); + + setTimeout(function() { + FnStoragePoolRefresh({ name: "` + pool.name + `", id: "` + pool.id + `" }, { storagepool: true, filesystems: false, snapshots: false, status: true }); + }, 200); + }, ($(this).attr("data-pool-refresh-interval") + "000")); + + zfsmanager.zfs.storagepool.refreshid.push(statusrefreshtimer` + _index + `); + + $("#tr-storagepool-` + pool.id + `").attr("data-pool-refresh-id", statusrefreshtimer` + _index + `); + $("#btn-storagepool-status-refresh-` + pool.id + `").text("Refresh: " + $(this).attr("data-pool-refresh-interval") + "s"); + + FnConsole.log[2]("Storage Pools, Refresh, Auto: Enabled, Pool: ` + pool.name + `"); + } + }); + \x3C/script> + + `; + + $("#table-storagepools").append(pool.output); + + $("#progressbar-storagepool-allocated-" + pool.id).css("width", pool.allocatedpercent + "%"); + $("#progressbar-storagepool-free-" + pool.id).css("width", pool.freepercent + "%"); + + //Register storage pool modals + FnModalStoragePoolConfigure({ name: pool.name, id: pool.id, boot: pool.boot, guid: pool.guid, readonly: false, root: pool.root }); + FnModalStoragePoolConfigureFeatures({ name: pool.name, id: pool.id, boot: pool.boot, readonly: false }); + if (pool.actionsmenu.register.destroy) { + FnModalStoragePoolDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot }); + } + if (pool.actionsmenu.register.export) { + FnModalStoragePoolExport({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }); + } + }); + + $("#btn-storagepools-refresh").prop("disabled", false); + + FnCockpitElementsUpdate(); +} + +function FnStoragePoolsImportableBlockDeviceGet(pools = { destroyed: false }) { + let process = { + command: ["/bin/sh", "-c", "/sbin/zpool import -d /dev" + (pools.destroyed ? " -D" : "") + " 2> /dev/null | /bin/grep -E 'pool:\| id:\|state:' | tr '\\\n' ','"] + }; + + FnConsole.log[2]("Storage Pools, Importable, Block Device, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnConsole.log[1]("Storage Pools, Importable, Block Device, Get: Success"); + }) + .fail(function (message, data) { + FnConsole.warn("Storage Pools, Importable, Block Device, Get: Failed, Message: " + (data ? data : message)); + }); +} + +function FnStoragePoolsImportableDiskGet(pools = { destroyed: false }) { + let process = { + command: ["/bin/sh", "-c", "/sbin/zpool import -d /dev/disk/by-id" + (pools.destroyed ? " -D" : "") + " 2> /dev/null | /bin/grep -E 'pool:\| id:\|state:' | tr '\\\n' ','"] + }; + + FnConsole.log[2]("Storage Pools, Importable, Disk / WWN, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnConsole.log[1]("Storage Pools, Importable, Disk / WWN, Get: Success"); + }) + .fail(function (message, data) { + FnConsole.warn("Storage Pools, Importable, Disk / WWN, Get: Failed, Message: " + (data ? data : message)); + }); +} + +function FnStoragePoolsImportableGet(pools = { destroyed: false }) { + let replacement = { + regexp: [ + { pattern: /^(?: )+pool\:/gi, replacement: "pool\:" }, + { pattern: /,(?: )+pool\:/gi, replacement: "\npool\:" }, + { pattern: /,$/g, replacement: "" }, + { pattern: /pool\: /gi, replacement: "" }, + { pattern: /id\: /gi, replacement: "" }, + { pattern: /state\: /gi, replacement: "" }, + { pattern: /,(?: )+/g, replacement: "," } + ] + }; + + pools.importable = { + blockdevice: [], + disk: [], + path: [], + vdev: [] + }; + + $("#listgroup-storagepools-import-storagepools").empty().append(`
  • `); + + FnConsole.log[2]("Storage Pools, Importable, Get: In Progress"); + + FnStoragePoolsImportableDiskGet({ destroyed: pools.destroyed }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Storage Pools, Importable, Disk / WWN, Get:" })); + + if (/no pools available to import/gi.test(data) == false) { + pools.importable.disk = replacement.regexp.reduce((d, r) => d.replace(r.pattern, r.replacement), data).split(/\n/g).filter(v => v); + } + + FnStoragePoolsImportableHardwarePathGet({ destroyed: pools.destroyed }) + .done(function (_data) { + FnConsole.log[4](FnConsoleVerbose({ data: _data, message: "Storage Pools, Importable, Hardware Path, Get:" })); + + if (/no pools available to import/gi.test(_data) == false) { + pools.importable.path = replacement.regexp.reduce((d, r) => d.replace(r.pattern, r.replacement), _data).split(/\n/g).filter(v => v); + } + + FnStoragePoolsImportableVirtualDeviceMappingGet({ destroyed: pools.destroyed }) + .done(function (__data) { + FnConsole.log[4](FnConsoleVerbose({ data: __data, message: "Storage Pools, Importable, Virtual Device Mapping, Get:" })); + + if (/no pools available to import/gi.test(__data) == false) { + pools.importable.vdev = replacement.regexp.reduce((d, r) => d.replace(r.pattern, r.replacement), __data).split(/\n/g).filter(v => v); + } + + FnStoragePoolsImportableBlockDeviceGet({ destroyed: pools.destroyed }) + .done(function (___data) { + FnConsole.log[4](FnConsoleVerbose({ data: ___data, message: "Storage Pools, Importable, Block Device, Get:" })); + + if (/no pools available to import/gi.test(___data) == false) { + pools.importable.blockdevice = replacement.regexp.reduce((d, r) => d.replace(r.pattern, r.replacement), ___data).split(/\n/g).filter(v => v); + + pools.importable.blockdevice.sort().forEach((_value, _index) => { + let pool = { + healthstatus: "", + properties: [], + id: { + blockdevice: true, + disk: false, + path: false, + vdev: false, + }, + idtext: ["Block Device"] + }; + + pool.properties = _value.split(/,/g).filter(v => v); + pool.name = pool.properties[0].trim(); + pool.guid = pool.properties[1].trim(); + pool.health = pool.properties[2].trim(); + + pools.importable.disk.filter(v => { if (v.match(pool.name) && !pool.id.disk) { pool.id.disk = true; pool.idtext.push("Disk / WWN"); } }); + pools.importable.path.filter(v => { if (v.match(pool.name) && !pool.id.path) { pool.id.path = true; pool.idtext.push("Hardware Path"); } }); + pools.importable.vdev.filter(v => { if (v.match(pool.name) && !pool.id.vdev) { pool.id.vdev = true; pool.idtext.push("Virtual Device Mapping"); } }); + + + if (/ONLINE/g.test(pool.health) == false) { + pool.healthstatus = ` `; + + $("#helpblock-storagepools-import-storagepools-warning").html("One or more storage pools are in an unhealthy state." + pool.healthstatus); + } + + pool.output = ` + + `; + + $("#listgroup-storagepools-import-storagepools").append(pool.output); + }); + } + + setTimeout(function () { + $("#spinner-storagepools-import-storagepools").remove(); + $("#listgroup-storagepools-import-storagepools > li").removeClass("hidden"); + if ($("#helpblock-storagepools-import-storagepools-warning").text()) { + $("#helpblock-storagepools-import-storagepools-warning").removeClass("hidden"); + } + + if ($("#listgroup-storagepools-import-storagepools > li").length == 0) { + pools.output = ` +
  • + +
  • + `; + + $("#listgroup-storagepools-import-storagepools").append(pools.output); + } + }, 200); + + FnConsole.log[1]("Storage Pools, Importable, Get: Success"); + }) + .fail(function (___message, ___data) { + if (/no pools available to import/gi.test(___data) == false) { + FnConsole.warn("Storage Pools, Importable, Get: Failed, Message: " + (___data ? ___data : ___message)); + } + + FnStoragePoolsImportableGetFail({ destroyed: pools.destroyed }); + }); + }) + .fail(function (__message, __data) { + if (/no pools available to import/gi.test(__data) == false) { + FnConsole.warn("Storage Pools, Importable, Get: Failed, Message: " + (__data ? __data : __message)); + } + + FnStoragePoolsImportableGetFail({ destroyed: pools.destroyed }); + }); + }) + .fail(function (_message, _data) { + if (/no pools available to import/gi.test(_data) == false) { + FnConsole.warn("Storage Pools, Importable, Get: Failed, Message: " + (_data ? _data : _message)); + } + + FnStoragePoolsImportableGetFail({ destroyed: pools.destroyed }); + }); + }) + .fail(function (message, data) { + if (/no pools available to import/gi.test(data) == false) { + FnConsole.warn("Storage Pools, Importable, Get: Failed, Message: " + (data ? data : message)); + } + + FnStoragePoolsImportableGetFail({ destroyed: pools.destroyed }); + }); +} + +function FnStoragePoolsImportableGetFail(pools = { destroyed: false }) { + setTimeout(function () { + $("#spinner-storagepools-import-storagepools").remove(); + $("#listgroup-storagepools-import-storagepools > li").removeClass("hidden"); + + if ($("#listgroup-storagepools-import-storagepools > li").length == 0) { + pools.output = ` +
  • + +
  • + `; + + $("#listgroup-storagepools-import-storagepools").append(pools.output); + } + }, 200); +} + +function FnStoragePoolsImportableHardwarePathGet(pools = { destroyed: false }) { + let process = { + command: ["/bin/sh", "-c", "/sbin/zpool import -d /dev/disk/by-path" + (pools.destroyed ? " -D" : "") + " 2> /dev/null | /bin/grep -E 'pool:\| id:\|state:' | tr '\\\n' ','"] + }; + + FnConsole.log[2]("Storage Pools, Importable, Hardware Path, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnConsole.log[1]("Storage Pools, Importable, Hardware Path, Get: Success"); + }) + .fail(function (message, data) { + FnConsole.warn("Storage Pools, Importable, Hardware Path, Get: Failed, Message: " + (data ? data : message)); + }); +} + +function FnStoragePoolsImportableVirtualDeviceMappingGet(pools = { destroyed: false }) { + let process = { + command: ["/bin/sh", "-c", "/sbin/zpool import -d /dev/disk/by-vdev" + (pools.destroyed ? " -D" : "") + " 2> /dev/null | /bin/grep -E 'pool:\| id:\|state:' | tr '\\\n' ','"] + }; + + FnConsole.log[2]("Storage Pools, Importable, Virtual Device Mapping, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnConsole.log[1]("Storage Pools, Importable, Virtual Device Mapping, Get: Success"); + }) + .fail(function (message, data) { + FnConsole.warn("Storage Pools, Importable, Virtual Device Mapping, Get: Failed, Message: " + (data ? data : message)); + }); +} + +function FnStoragePoolsSystemReservedGet() { + let filesystems = { + id: [] + }; + let process = { + command: ["/sbin/zfs", "list", "-H", "-o", "name,mountpoint", "-d", "3"] + }; + + FnConsole.log[2]("Storage Pools, System Reserved, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done((data) => { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Storage Pools, System Reserved, Get:" })); + + filesystems.id = data.split(/\n/g).filter(v => v); + + filesystems.id.forEach((_value, _index) => { + let filesystem = { + properties: _value.split(/\t/g).filter(v => v) + }; + + filesystem.name = filesystem.properties[0]; + filesystem.mountpoint = filesystem.properties[1].trim(); + + if (filesystem.mountpoint == "/boot" && !zfsmanager.zfs.storagepool.boot) { + zfsmanager.zfs.storagepool.boot = filesystem.name.split("/")[0]; + } else if (filesystem.mountpoint == "/" && !zfsmanager.zfs.storagepool.root) { + zfsmanager.zfs.storagepool.root = filesystem.name.split("/")[0]; + } + }); + + FnConsole.log[1]("Storage Pools, System Reserved, Get: Success"); + }) + .fail((message, data) => { + FnConsole.warn("Storage Pools, System Reserved, Get: Failed, Message: " + (data ? data : message)); + }); +} + +function FnStoragePoolsTemporaryGet() { + let process = { + command: ["/sbin/zpool", "list", "-H", "-o", "name,readonly,altroot"] + }; + + FnConsole.log[2]("Storage Pools, Temporary, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function () { + FnConsole.log[1]("Storage Pools, Temporary, Get: Success"); + }) + .fail(function (message, data) { + FnConsole.warn("Storage Pools, Temporary, Get: Failed, Message: " + (data ? data : message)); + }); +} + +//#endregion + +//#region Storage Pool + +function FnStoragePoolAlternativeRootGet(pool = { name, id }, modal = { name, id }) { + let process = { + command: ["/sbin/zpool", "list", "-H", "-o", "altroot", pool.name] + }; + + FnConsole.log[2]("Storage Pools, Alternative Root, Get: In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Storage Pools, Alternative Root, Get:" })); + + data = data.replace(/\n+/g, ""); + + $("#input-" + modal.name + "-mountpoint-" + modal.id).attr("data-field-altroot", data); + + FnConsole.log[1]("Storage Pools, Alternative Root, Get: Success, Pool: " + pool.name); + }) + .fail(function (message, data) { + FnConsole.warn("Storage Pools, Alternative Root, Get: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); + }); +} + +function FnStoragePoolClear(pool = { name, id }, modal = { name, id }) { + let process = { + command: ["/sbin/zpool", "clear", pool.name] + }; + + FnConsole.log[2]("Storage Pools, Clear Errors: In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-" + modal.name + "-" + modal.id + " span").text("Clearing storage pool errors..."); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "Storage Pool errors successfully cleared", description: pool.name, breakword: false }, { name: "storagepool-clear", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, Clear Errors: Success, Pool: " + pool.name); + }) + .fail(function (message, data) { + FnDisplayAlert({ status: "danger", title: "Storage Pool errors could not be cleared", description: pool.name, breakword: false }, { name: "storagepool-clear", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, Clear Errors: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); + }) + .finally(function () { + $("#modal-" + modal.name + "-" + modal.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); + }, 200); + }); +} + +function FnStoragePoolConfigurationFeaturesDisabledGet(pool = { name, id }, modal = { name, id }) { + let process = { + command: ["/sbin/zpool", "get", "feature@allocation_classes,feature@async_destroy,feature@bookmark_v2,feature@bookmarks,feature@device_removal,feature@edonr,feature@embedded_data,feature@empty_bpobj,feature@enabled_txg,feature@encryption,feature@extensible_dataset,feature@filesystem_limits,feature@hole_birth,feature@large_blocks,feature@large_dnode,feature@lz4_compress,feature@multi_vdev_crash_dump,feature@obsolete_counts,feature@project_quota,feature@resilver_defer,feature@sha512,feature@skein,feature@spacemap_histogram,feature@spacemap_v2,feature@userobj_accounting,feature@zpool_checkpoint", "-H", "-o", "property,value", pool.name] + }; + + FnConsole.log[2]("Storage Pools, Configuration, Features, Disabled, Get: In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Storage Pools, Configuration, Features, Disabled, Get:" })); + + pool.configuration = data.replace(/\t+/g, "\u22C5").split(/\n/g).filter(v => v); + pool.disabled = []; + + pool.configuration.forEach((_value, _index) => { + _value = _value.split("\u22C5"); + + pool.properties = { + property: _value[0].toLowerCase(), + value: _value[1].toLowerCase() + }; + + switch (pool.properties.property) { + case "feature@allocation_classes": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("Allocation Classes"); + } + break; + case "feature@async_destroy": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("Asynchronous Destroy"); + } + break; + case "feature@bookmark_v2": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("Bookmarks Version 2"); + } + break; + case "feature@bookmarks": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("Bookmarks"); + } + break; + case "feature@device_removal": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("Device Removal"); + } + break; + case "feature@edonr": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("Edon-R"); + } + break; + case "feature@embedded_data": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("Embedded Data"); + } + break; + case "feature@empty_bpobj": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("Empty Block Pointer Objects"); + } + break; + case "feature@enabled_txg": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("Transaction Group Accounting"); + } + break; + case "feature@encryption": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("Encryption"); + } + break; + case "feature@extensible_dataset": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("Extensible Dataset"); + } + break; + case "feature@filesystem_limits": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("File System Limits"); + } + break; + case "feature@hole_birth": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("Hole Birth"); + } + break; + case "feature@large_blocks": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("Large Blocks"); + } + break; + case "feature@large_dnode": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("Large DNode"); + } + break; + case "feature@lz4_compress": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("LZ4 Compression"); + } + break; + case "feature@multi_vdev_crash_dump": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("Multi Virtual Device Crash Dump"); + } + break; + case "feature@obsolete_counts": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("Obsolete Counts"); + } + break; + case "feature@project_quota": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("Project Quota"); + } + break; + case "feature@resilver_defer": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("Resilver Defer"); + } + break; + case "feature@sha512": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("SHA-512"); + } + break; + case "feature@skein": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("Skein"); + } + break; + case "feature@spacemap_histogram": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("Space Map Histogram"); + } + break; + case "feature@spacemap_v2": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("Space Map Version 2"); + } + break; + case "feature@userobj_accounting": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("User Object Accounting"); + } + break; + case "feature@zpool_checkpoint": + if (/disabled/gi.test(pool.properties.value)) { + pool.disabled.push("Checkpoint"); + } + break; + } + }); + + $("#ul-" + modal.name + "-features-" + modal.id).append(`
  • ` + pool.disabled.sort().join(`
  • \n
  • `) + `
  • `); + + FnConsole.log[1]("Storage Pools, Configuration, Features, Disabled, Get: Success, Pool: " + pool.name); + + }) + .fail(function (message, data) { + FnConsole.warn("Storage Pools, Configuration, Features, Disabled, Get: In Progress, Pool: " + pool.name + " , Message: " + (data ? data : message)); + }); +} + +function FnStoragePoolConfigurationFeaturesGet(pool = { name, id, boot: false }, modal = { name, id }) { + let process = { + command: ["/sbin/zpool", "get", "readonly,feature@allocation_classes,feature@async_destroy,feature@bookmark_v2,feature@bookmarks,feature@device_removal,feature@edonr,feature@embedded_data,feature@empty_bpobj,feature@enabled_txg,feature@encryption,feature@extensible_dataset,feature@filesystem_limits,feature@hole_birth,feature@large_blocks,feature@large_dnode,feature@lz4_compress,feature@multi_vdev_crash_dump,feature@obsolete_counts,feature@project_quota,feature@resilver_defer,feature@sha512,feature@skein,feature@spacemap_histogram,feature@spacemap_v2,feature@userobj_accounting,feature@zpool_checkpoint", "-H", "-o", "property,value", pool.name] + }; + + pool.readonly = false; + + FnConsole.log[2]("Storage Pools, Configuration, Features, Get: In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Storage Pools, Configuration, Features, Get:" })); + + pool.configuration = data.replace(/\t+/g, "\u22C5").split(/\n/g).filter(v => v); + + pool.configuration.forEach((_value, _index) => { + _value = _value.split("\u22C5"); + + pool.properties = { + property: _value[0].toLowerCase(), + value: _value[1].toLowerCase() + }; + + switch (pool.properties.property) { + case "feature@allocation_classes": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-allocation_classes-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-allocation_classes-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-allocation_classes-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-allocation_classes-" + modal.id + " input").prop("disabled", true); + } + break; + case "feature@async_destroy": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-async_destroy-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-async_destroy-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-async_destroy-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-async_destroy-" + modal.id + " input").prop("disabled", true); + } + break; + case "feature@bookmark_v2": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-bookmark_v2-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-bookmark_v2-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-bookmark_v2-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-bookmark_v2-" + modal.id + " input").prop("disabled", true); + } + break; + case "feature@bookmarks": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-bookmarks-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-bookmarks-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-bookmarks-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-bookmarks-" + modal.id + " input").prop("disabled", true); + } + break; + case "feature@device_removal": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-device_removal-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-device_removal-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-device_removal-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-device_removal-" + modal.id + " input").prop("disabled", true); + } + break; + case "feature@edonr": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-edonr-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-edonr-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-edonr-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-edonr-" + modal.id + " input").prop("disabled", true); + } + break; + case "feature@embedded_data": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-embedded_data-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-embedded_data-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-embedded_data-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-embedded_data-" + modal.id + " input").prop("disabled", true); + } + break; + case "feature@empty_bpobj": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-empty_bpobj-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-empty_bpobj-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-empty_bpobj-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-empty_bpobj-" + modal.id + " input").prop("disabled", true); + } + break; + case "feature@enabled_txg": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-enabled_txg-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-enabled_txg-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-enabled_txg-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-enabled_txg-" + modal.id + " input").prop("disabled", true); + } + break; + case "feature@encryption": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-encryption-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-encryption-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-encryption-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-encryption-" + modal.id + " input").prop("disabled", true); + } + break; + case "feature@extensible_dataset": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-extensible_dataset-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-extensible_dataset-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-extensible_dataset-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-extensible_dataset-" + modal.id + " input").prop("disabled", true); + } + break; + case "feature@filesystem_limits": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-filesystem_limits-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-filesystem_limits-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-filesystem_limits-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-filesystem_limits-" + modal.id + " input").prop("disabled", true); + } + break; + case "feature@hole_birth": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-hole_birth-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-hole_birth-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-hole_birth-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-hole_birth-" + modal.id + " input").prop("disabled", true); + } + break; + case "feature@large_blocks": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-large_blocks-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-large_blocks-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-large_blocks-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-large_blocks-" + modal.id + " input").prop("disabled", true); + } + break; + case "feature@large_dnode": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-large_dnode-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-large_dnode-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-large_dnode-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-large_dnode-" + modal.id + " input").prop("disabled", true); + } + break; + case "feature@lz4_compress": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-lz4_compress-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-lz4_compress-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-lz4_compress-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-lz4_compress-" + modal.id + " input").prop("disabled", true); + } + break; + case "feature@multi_vdev_crash_dump": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-multi_vdev_crash_dump-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-multi_vdev_crash_dump-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-multi_vdev_crash_dump-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-multi_vdev_crash_dump-" + modal.id + " input").prop("disabled", true); + } + break; + case "feature@obsolete_counts": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-obsolete_counts-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-obsolete_counts-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-obsolete_counts-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-obsolete_counts-" + modal.id + " input").prop("disabled", true); + } + break; + case "feature@project_quota": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-project_quota-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-project_quota-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-project_quota-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-project_quota-" + modal.id + " input").prop("disabled", true); + } + break; + case "feature@resilver_defer": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-resilver_defer-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-resilver_defer-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-resilver_defer-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-resilver_defer-" + modal.id + " input").prop("disabled", true); + } + break; + case "feature@sha512": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-sha512-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-sha512-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-sha512-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-sha512-" + modal.id + " input").prop("disabled", true); + } + break; + case "feature@skein": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-skein-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-skein-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-skein-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-skein-" + modal.id + " input").prop("disabled", true); + } + break; + case "feature@spacemap_histogram": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-spacemap_histogram-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-spacemap_histogram-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-spacemap_histogram-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-spacemap_histogram-" + modal.id + " input").prop("disabled", true); + } + break; + case "feature@spacemap_v2": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-spacemap_v2-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-spacemap_v2-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-spacemap_v2-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-spacemap_v2-" + modal.id + " input").prop("disabled", true); + } + break; + case "feature@userobj_accounting": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-userobj_accounting-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-userobj_accounting-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-userobj_accounting-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-userobj_accounting-" + modal.id + " input").prop("disabled", true); + } + break; + case "feature@zpool_checkpoint": + if (/active|enabled/gi.test(pool.properties.value) && !$("#switch-" + modal.name + "-zpool_checkpoint-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-zpool_checkpoint-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-zpool_checkpoint-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || /active|enabled/gi.test(pool.properties.value)) { + $("#switch-" + modal.name + "-zpool_checkpoint-" + modal.id + " input").prop("disabled", true); + } + break; + case "readonly": //Default is off + if (pool.properties.value == "on" || pool.boot && zfsmanager.configuration.zfs.storagepool.bootlockdown || !zfsmanager.user.admin) { + pool.readonly = true; + } + break; + } + }); + + if (pool.readonly) { + $("#btn-" + modal.name + "-apply-" + modal.id).prop("disabled", true); + } + + FnConsole.log[1]("Storage Pools, Configuration, Features, Get: Success, Pool: " + pool.name); + }) + .fail(function (message, data) { + FnConsole.warn("Storage Pools, Configuration, Features, Get: Failed, Pool: " + pool.name + " , Message: " + (data ? data : message)); + }); +} + +function FnStoragePoolConfigurationGet(pool = { name, id, boot: false, root: false }, modal = { name, id }) { + let process = { + command: ["/sbin/zpool", "get", "readonly,altroot,ashift,autoexpand,autoreplace,autotrim,bootfs,cachefile,comment,delegation,failmode,guid,listsnapshots,multihost,version", "-H", "-o", "property,value", pool.name] + }; + + pool.readonly = false; + + FnConsole.log[2]("Storage Pools, Configuration, Get: In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Storage Pools, Configuration, Get:" })); + + pool.configuration = data.replace(/\t+/g, "\u22C5").split(/\n/g).filter(v => v); + + pool.configuration.forEach((_value, _index) => { + _value = _value.split("\u22C5"); + + pool.properties = { + property: _value[0].toLowerCase(), + value: _value[1].toLowerCase(), + valueraw: _value[1], + }; + + switch (pool.properties.property) { + case "altroot": //Default is empty (-) + if (pool.properties.valueraw && pool.properties.valueraw == "-") { + pool.properties.valueraw = ""; + } + + if (pool.properties.valueraw) { + $("#controllabel-" + modal.name + "-altroot-" + modal.id).removeClass("hidden"); + $("#div-" + modal.name + "-altroot-" + modal.id).removeClass("hidden").text(pool.properties.valueraw); + } + break; + case "ashift": //Default is 0 + pool.property = { + value: "Auto Detect", + }; + + switch (pool.properties.value) { + case "0": + pool.property.value = "Auto Detect"; + break; + case "9": + pool.property.value = "512 B"; + break; + case "12": + pool.property.value = "4 KiB"; + break; + case "13": + pool.property.value = "8 KiB"; + break; + case "14": + pool.property.value = "16 KiB"; + break; + case "15": + pool.property.value = "32 KiB"; + break; + case "16": + pool.property.value = "64 KiB"; + break; + default: + pool.property.value = "Auto Detect"; + break; + } + + $("#btnspan-" + modal.name + "-ashift-" + modal.id).text(pool.property.value).attr("data-field-value", pool.properties.value); + $("#dropdown-" + modal.name + "-ashift-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-ashift-" + modal.id + " li[value='" + pool.properties.valueraw + "']").addClass("active"); + + if (pool.readonly) { + $("#div-" + modal.name + "-ashift-dropdown-" + modal.id + " button").prop("disabled", true); + } + break; + case "autoexpand": //Default is off + if (pool.properties.value == "on" && !$("#switch-" + modal.name + "-autoexpand-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-autoexpand-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-autoexpand-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly) { + $("#switch-" + modal.name + "-autoexpand-" + modal.id + " input").prop("disabled", true); + } + break; + case "autoreplace": //Default is off + if (pool.properties.value == "on" && !$("#switch-" + modal.name + "-autoreplace-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-autoreplace-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-autoreplace-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly) { + $("#switch-" + modal.name + "-autoreplace-" + modal.id + " input").prop("disabled", true); + } + break; + case "autotrim": //Default is off + if (pool.properties.value == "on" && !$("#switch-" + modal.name + "-autotrim-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-autotrim-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-autotrim-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly) { + $("#switch-" + modal.name + "-autotrim-" + modal.id + " input").prop("disabled", true); + } + break; + case "comment": //Default is empty (-) + if (pool.properties.valueraw && pool.properties.valueraw == "-") { + pool.properties.valueraw = ""; + } + + $("#input-" + modal.name + "-comment-" + modal.id).val(pool.properties.valueraw); + $("#input-" + modal.name + "-comment-" + modal.id).attr("data-field-value", pool.properties.valueraw); + + if (pool.readonly) { + $("#input-" + modal.name + "-comment-" + modal.id).prop("disabled", true); + } + + break; + case "delegation": //Default is on + if (pool.properties.value == "off" && $("#switch-" + modal.name + "-delegation-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-delegation-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-delegation-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly) { + $("#switch-" + modal.name + "-delegation-" + modal.id + " input").prop("disabled", true); + } + break; + case "failmode": //Default is wait + pool.property = { + value: pool.properties.value.charAt(0).toUpperCase() + pool.properties.value.slice(1), + }; + + $("#btnspan-" + modal.name + "-failmode-" + modal.id).text(pool.property.value).attr("data-field-value", pool.properties.value); + $("#dropdown-" + modal.name + "-failmode-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-failmode-" + modal.id + " li[value='" + pool.properties.valueraw + "']").addClass("active"); + + if (pool.readonly) { + $("#div-" + modal.name + "-failmode-dropdown-" + modal.id + " button").prop("disabled", true); + } + break; + case "guid": + $("#div-" + modal.name + "-guid-" + modal.id).html(pool.properties.value); + break; + case "listsnapshots": //Default is off + if (pool.properties.value == "on" && !$("#switch-" + modal.name + "-listsnapshots-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-listsnapshots-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-listsnapshots-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly) { + $("#switch-" + modal.name + "-listsnapshots-" + modal.id + " input").prop("disabled", true); + } + break; + case "multihost": //Default is off + if (pool.properties.value == "on" && !$("#switch-" + modal.name + "-multihost-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-multihost-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-multihost-" + modal.id).attr("data-field-value", pool.properties.value); + + if (pool.readonly || pool.boot || pool.root) { + $("#switch-" + modal.name + "-multihost-" + modal.id + " input").prop("disabled", true); + } + break; + case "readonly": //Default is off + if (pool.properties.value == "on" || pool.boot && zfsmanager.configuration.zfs.storagepool.bootlockdown || !zfsmanager.user.admin) { + pool.readonly = true; + } + + $("#div-" + modal.name + "-readonly-" + modal.id).html((pool.properties.value == "on" ? "Yes" : "No")); + break; + } + }); + + if (pool.readonly) { + $("#btn-" + modal.name + "-apply-" + modal.id).prop("disabled", true); + } + + FnConsole.log[1]("Storage Pools, Configuration, Get: Success, Pool: " + pool.name); + }) + .fail(function (message, data) { + FnConsole.warn("Storage Pools, Configuration, Get: Failed, Pool: " + pool.name + " , Message: " + (data ? data : message)); + }); +} + +function FnStoragePoolConfigure(pool = { name, id, ashift, autoexpand, autoreplace, autotrim, comment, delegation, failmode, listsnapshots, multihost, readonly: false }, system = { hostid }, modal = { id }) { + pool.properties = { + new: [] + }; + + if (pool.ashift) { + pool.properties.new.push("ashift=" + pool.ashift); + } + if (pool.autoexpand) { + pool.properties.new.push("autoexpand=" + pool.autoexpand); + } + if (pool.autoreplace) { + pool.properties.new.push("autoreplace=" + pool.autoreplace); + } + if (pool.autotrim) { + pool.properties.new.push("autotrim=" + pool.autotrim); + } + if (pool.comment) { + if (pool.comment == "$empty") { + pool.comment = ""; + } + + pool.properties.new.push("comment=" + pool.comment); + } + if (pool.delegation) { + pool.properties.new.push("delegation=" + pool.delegation); + } + if (pool.failmode) { + pool.properties.new.push("failmode=" + pool.failmode); + } + if (pool.listsnapshots) { + pool.properties.new.push("listsnapshots=" + pool.listsnapshots); + } + if (pool.multihost) { + pool.properties.new.push("multihost=" + pool.multihost); + } + + if (system.hostid) { + FnSystemHostIdSet({ hostid: (system.hostid == "random" ? null : "\$\(hostid\)") }) + .finally(function () { + if (pool.properties.new.length > 0 && !pool.readonly) { + FnConsole.log[2]("Storage Pools, Configure: In Progress, Pool: " + pool.name); + + $("#spinner-storagepool-configure-" + pool.id + " span").text("Configuring storage pool..."); + + FnStoragePoolConfigureCommand({ name: pool.name, id: pool.id, properties: { new: pool.properties.new } }, { id: modal.id }); + } else { + modal.id.modal("hide"); + } + }); + } else { + if (pool.properties.new.length > 0 && !pool.readonly) { + FnConsole.log[2]("Storage Pools, Configure: In Progress, Pool: " + pool.name); + + $("#spinner-storagepool-configure-" + pool.id + " span").text("Configuring storage pool..."); + + FnStoragePoolConfigureCommand({ name: pool.name, id: pool.id, properties: { new: pool.properties.new } }, { id: modal.id }); + } else { + modal.id.modal("hide"); + } + } +} + +function FnStoragePoolConfigureCommand(pool = { name, id, properties: { new: [] } }, modal = { id }) { + let promise = Promise.resolve(); + + pool.properties.errorcount = 0; + + pool.properties.new.forEach((_value, _index) => { + promise = promise.then(_ => new Promise(resolve => + setTimeout(function () { + let process = { + command: ["/sbin/zpool", "set", _value, pool.name] + }; + + FnConsole.log[2]("Storage Pools, Configure: In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + if (_index == (pool.properties.new.length - 1)) { + if (pool.properties.errorcount == 0) { + FnDisplayAlert({ status: "success", title: "Storge Pool successfully configured", description: pool.name, breakword: false }, { name: "storagepool-configure", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, Configure: Success, Pool: " + pool.name); + } else { + FnStoragePoolConfigureFail({ name: pool.name, id: pool.id }); + } + + modal.id.modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: false, status: false }); + }, 200); + } + }) + .fail(function (message, data) { + pool.properties.errorcount++; + + FnConsole.warn("Storage Pools, Property, Set: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); + + if (_index == (pool.properties.new.length - 1)) { + FnStoragePoolConfigureFail({ name: pool.name, id: pool.id }); + + modal.id.modal("hide"); + } + }); + + resolve(); + }, 500) + )); + }); +} + +function FnStoragePoolConfigureFail(pool = { name, id }) { + FnDisplayAlert({ status: "danger", title: "Storge Pool could not be configured", description: pool.name, breakword: false }, { name: "storagepool-configure", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, Configure: Failed, Pool: " + pool.name); +} + +function FnStoragePoolConfigureFeatures(pool = { name, id, feature: { allocation_classes, async_destroy, bookmark_v2, bookmarks, device_removal, edonr, embedded_data, empty_bpobj, enabled_txg, encryption, extensible_dataset, filesystem_limits, hole_birth, large_blocks, large_dnode, lz4_compress, multi_vdev_crash_dump, obsolete_counts, project_quota, resilver_defer, sha512, skein, spacemap_histogram, spacemap_v2, userobj_accounting, zpool_checkpoint }, readonly: false }, modal = { id }) { + pool.features = { + new: [] + }; + + if (pool.feature.allocation_classes) { + pool.features.new.push("feature@allocation_classes=" + pool.feature.allocation_classes); + } + if (pool.feature.async_destroy) { + pool.features.new.push("feature@async_destroy=" + pool.feature.async_destroy); + } + if (pool.feature.bookmark_v2) { + pool.features.new.push("feature@bookmark_v2=" + pool.feature.bookmark_v2); + } + if (pool.feature.bookmarks) { + pool.features.new.push("feature@bookmarks=" + pool.feature.bookmarks); + } + if (pool.feature.device_removal) { + pool.features.new.push("feature@device_removal=" + pool.feature.device_removal); + } + if (pool.feature.edonr) { + pool.features.new.push("feature@edonr=" + pool.feature.edonr); + } + if (pool.feature.embedded_data) { + pool.features.new.push("feature@embedded_data=" + pool.feature.embedded_data); + } + if (pool.feature.empty_bpobj) { + pool.features.new.push("feature@empty_bpobj=" + pool.feature.empty_bpobj); + } + if (pool.feature.enabled_txg) { + pool.features.new.push("feature@enabled_txg=" + pool.feature.enabled_txg); + } + if (pool.feature.encryption) { + pool.features.new.push("feature@encryption=" + pool.feature.encryption); + } + if (pool.feature.extensible_dataset) { + pool.features.new.push("feature@extensible_dataset=" + pool.feature.extensible_dataset); + } + if (pool.feature.filesystem_limits) { + pool.features.new.push("feature@filesystem_limits=" + pool.feature.filesystem_limits); + } + if (pool.feature.hole_birth) { + pool.features.new.push("feature@hole_birth=" + pool.feature.hole_birth); + } + if (pool.feature.large_blocks) { + pool.features.new.push("feature@large_blocks=" + pool.feature.large_blocks); + } + if (pool.feature.large_dnode) { + pool.features.new.push("feature@large_dnode=" + pool.feature.large_dnode); + } + if (pool.feature.lz4_compress) { + pool.features.new.push("feature@lz4_compress=" + pool.feature.lz4_compress); + } + if (pool.feature.multi_vdev_crash_dump) { + pool.features.new.push("feature@multi_vdev_crash_dump=" + pool.feature.multi_vdev_crash_dump); + } + if (pool.feature.obsolete_counts) { + pool.features.new.push("feature@obsolete_counts=" + pool.feature.obsolete_counts); + } + if (pool.feature.project_quota) { + pool.features.new.push("feature@project_quota=" + pool.feature.project_quota); + } + if (pool.feature.resilver_defer) { + pool.features.new.push("feature@resilver_defer=" + pool.feature.resilver_defer); + } + if (pool.feature.sha512) { + pool.features.new.push("feature@sha512=" + pool.feature.sha512); + } + if (pool.feature.skein) { + pool.features.new.push("feature@skein=" + pool.feature.skein); + } + if (pool.feature.spacemap_histogram) { + pool.features.new.push("feature@spacemap_histogram=" + pool.feature.spacemap_histogram); + } + if (pool.feature.spacemap_v2) { + pool.features.new.push("feature@spacemap_v2=" + pool.feature.spacemap_v2); + } + if (pool.feature.userobj_accounting) { + pool.features.new.push("feature@userobj_accounting=" + pool.feature.userobj_accounting); + } + if (pool.feature.zpool_checkpoint) { + pool.features.new.push("feature@zpool_checkpoint=" + pool.feature.zpool_checkpoint); + } + + if (pool.features.new.length > 0 && !pool.readonly) { + FnConsole.log[2]("Storage Pools, Configure, Features: In Progress, Pool: " + pool.name); + + $("#spinner-storagepool-configure-features-" + pool.id + " span").text("Configuring storage pool features..."); + + FnStoragePoolConfigureFeaturesCommand({ name: pool.name, id: pool.id, features: { new: pool.features.new } }, { id: modal.id }); + } else { + modal.id.modal("hide"); + } +} + +function FnStoragePoolConfigureFeaturesCommand(pool = { name, id, features: { new: [] } }, modal = { id }) { + let promise = Promise.resolve(); + + pool.features.errorcount = 0; + + pool.features.new.forEach((_value, _index) => { + promise = promise.then(_ => new Promise(resolve => + setTimeout(function () { + let process = { + command: ["/sbin/zpool", "set", _value, pool.name] + }; + + FnConsole.log[2]("Storage Pools, Configure, Features: In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + if (_index == (pool.features.new.length - 1)) { + if (pool.features.errorcount == 0) { + FnDisplayAlert({ status: "success", title: "Storge Pool features successfully configured", description: pool.name, breakword: false }, { name: "storagepool-configure-features", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, Configure, Features: Success, Pool: " + pool.name); + } else { + FnStoragePoolConfigureFeaturesFail({ name: pool.name, id: pool.id }); + } + + modal.id.modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: true }); + }, 200); + } + }) + .fail(function (message, data) { + pool.features.errorcount++; + + FnConsole.warn("Storage Pools, Feature, Set: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); + + if (_index == (pool.features.new.length - 1)) { + FnStoragePoolConfigureFeaturesFail({ name: pool.name, id: pool.id }); + + modal.id.modal("hide"); + } + }); + + resolve(); + }, 500) + )); + }); +} + +function FnStoragePoolConfigureFeaturesFail(pool = { name, id }) { + FnDisplayAlert({ status: "danger", title: "Storge Pool features could not be configured", description: pool.name, breakword: false }, { name: "storagepool-configure-features", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, Configure, Features: Failed, Pool: " + pool.name); +} + +function FnStoragePoolCreate(pool = { name, ashift, autoexpand, autoreplace, autotrim, force, virtualdevice }, filesystem = { compression, dedup, recordsize, refreservationpercent, selinux }, disks = { id: [] }) { + let process = { + command: ["/sbin/zpool", "create", "-o", "ashift=" + pool.ashift, "-o", "autoexpand=" + pool.autoexpand, "-o", "autoreplace=" + pool.autoreplace, "-o", "autotrim=" + pool.autotrim, "-O", "aclinherit=passthrough", "-O", "acltype=posixacl", "-O", "casesensitivity=sensitive", "-O", "compression=" + filesystem.compression, "-O", "normalization=formD", "-O", "recordsize=" + filesystem.recordsize, "-O", "sharenfs=off", "-O", "sharesmb=off", "-O", "utf8only=on", "-O", "xattr=sa", pool.name] + }; + let modal = { + hide: true + }; + + if (filesystem.selinux) { + process.command.splice((process.command.length - 1), 0, "-O"); + process.command.splice((process.command.length - 1), 0, "context=system_u:object_r:samba_share_t:s0"); + process.command.splice((process.command.length - 1), 0, "-O"); + process.command.splice((process.command.length - 1), 0, "fscontext=system_u:object_r:samba_share_t:s0"); + process.command.splice((process.command.length - 1), 0, "-O"); + process.command.splice((process.command.length - 1), 0, "defcontext=system_u:object_r:samba_share_t:s0"); + process.command.splice((process.command.length - 1), 0, "-O"); + process.command.splice((process.command.length - 1), 0, "rootcontext=system_u:object_r:samba_share_t:s0"); + } + if (filesystem.dedup) { + process.command.splice((process.command.length - 1), 0, "-O"); + process.command.splice((process.command.length - 1), 0, "dedup=" + filesystem.dedup); + } + if (pool.force) { + process.command.splice(2, 0, "-f"); + } + if (pool.virtualdevice) { + process.command.push(pool.virtualdevice); + } + + disks.id.forEach(_value => _value && process.command.push(_value)); + + pool.id = FnGenerateId({ at: false, colon: true, forwardslash: false, period: true, underscore: true, whitespace: true }, { name: pool.name, attribute: true }); + + FnConsole.log[1]("Storage Pools, Create: In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-storagepools-create span").text("Creating storage pool..."); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "Storage Pool successfully created", description: pool.name, breakword: false }, { name: "storagepool-create", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, Create: Success, Pool: " + pool.name); + + if (filesystem.refreservationpercent > 0) { + FnStoragePoolSizeGet({ name: pool.name, id: null }) + .done(function (_data) { + FnConsole.log[4](FnConsoleVerbose({ data: _data, message: "Storage Pools, Size, Get:" })); + + if (_data) { + _data = _data.replace(/\n+/g, ""); + + filesystem.refreservation = ((_data / 100) * filesystem.refreservationpercent); + + FnStoragePoolRefreservationSet({ name: pool.name, id: null }, { refreservation: filesystem.refreservation }); + } + }); + } + }) + .fail(function (message, data) { + if (/pool already exists/gi.test(data)) { + modal.hide = false; + + $("#validationwrapper-storagepools-create-name").addClass("has-error"); + $("#helpblock-storagepools-create-name").addClass("has-error").removeClass("hidden").text("Name already exists."); + $("#input-storagepools-create-name").focus(); + } else if (/contains devices of different sizes/gi.test(data)) { + modal.hide = false; + + $("#validationwrapper-storagepools-create-disks").addClass("has-error"); + $("#helpblock-storagepools-create-disks").addClass("has-error").removeClass("hidden").text("Disks are of different sizes. Forcefully create storage pool to override."); + } else { + FnDisplayAlert({ status: "danger", title: "Storage Pool could not be created", description: pool.name, breakword: false }, { name: "storagepool-create", id: pool.id, timeout: 4 }); + } + + FnConsole.warn("Storage Pools, Create: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); + + if (!modal.hide) { + $("#spinner-storagepools-create").addClass("hidden"); + $("#spinner-storagepools-create span").text(""); + $("#btn-storagepools-create-apply").prop("disabled", false); + } + }) + .finally(function () { + if (modal.hide) { + $("#modal-storagepools-create").modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 200); + } + }); +} + +function FnStoragePoolDestroy(pool = { name, id, altroot: false, force: false, labelclear: false }, samba = { restart: false }) { + let disks = { + attached: [] + }; + + pool.attached = []; + pool.attachedconfig = []; + + if (pool.labelclear) { + FnDisksStoragePoolsAttachedGet({ name: pool.name, id: pool.id }, { id: { blockdevice: true } }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Disks, Storage Pools, Attached, Get:" })); + + pool.attached = data.replace(/\n\t+/g, "[TAB1]").split(/\n/g).filter(v => v); + + pool.attached.forEach((_value, _index) => { + if (/\[TAB1\]NAME/g.test(_value)) { //Config header row + _value = _value.split("upath").slice(1).join("."); //Remove config header row (and any previous text if exists) + + if (new RegExp("^\\[TAB1\\]" + pool.name).test(_value)) { //Confirm config rows + _value.split("[TAB1]").filter(v => v && pool.attachedconfig.push(v)); + } + } + }); + + pool.attachedconfig.forEach((_value, _index) => { + let config = { + disk: { + upath: "" + }, + tier: { + level: (_value.match(/^\s*/g)[0].length / 2) + } + }; + + _value = _value.replace(/ +/g, "\u22C5").replace(/^\u22C5/, "").split("\u22C5").filter(v => v); + + if (/^\/dev\/nvme|^\/dev\/sd/gi.test(_value[5])) { //upath + config.disk.upath = _value[5]; + } else if (!$.isNumeric(_value[0]) && _value[5] != "was") { //upath appears after error messages and before trim messages + for (let i = 5; i < _value.length; i++) { + if (/^\/dev\/nvme|^\/dev\/sd/gi.test(_value[i])) { + config.disk.upath = _value[i]; + } + } + } + + if (config.tier.level > 0) { + if (/^\/dev\/nvme|^\/dev\/sd/gi.test(config.disk.upath)) { //Block Device via upath + disks.attached.push(config.disk.upath.replace(/^\/dev\//gi, "")); + } else if (/^\/dev\/nvme|^\/dev\/sd/gi.test(_value[0])) { //Block Device + if (/^\/dev\/nvme\d+n\d+p\d+$/gi.test(_value[0])) { + disks.attached.push(_value[0].replace(/^\/dev\//gi, "").replace(/p\d+$/, "")); + } else if (/^\/dev\/sd.*\d+$/gi.test(_value[0])) { + disks.attached.push(_value[0].replace(/^\/dev\//gi, "").replace(/\d+$/, "")); + } else { + disks.attached.push(_value[0]); + } + } else if (/^nvme-nvme/gi.test(_value[0]) || /^wwn-/gi.test(_value[0])) { //WWN + if (/^nvme-nvme.*-part\d+$/gi.test(_value[0])) { + disks.attached.push(_value[0].replace(/-part\d+$/, "")); + } else if (/^wwn-.*-part\d+$/gi.test(_value[0])) { + disks.attached.push(_value[0].replace(/-part\d+$/, "")); + } else { + disks.attached.push(_value[0]); + } + } + } + }); + + disks.attached.sort(); + }); + } + + if (samba.restart) { + FnSambaStop() + .finally(function () { + if (zfsmanager.configuration.samba.manage) { + $("#spinner-storagepool-destroy-" + pool.id + " span").text("Retrieving Samba shares..."); + + FnSambaSharesGet({ name: pool.name, id: pool.id }, { name: null, clones: [] }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Shares, Get:" })); + + let filesystems = { + id: data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) + }; + + $("#spinner-storagepool-destroy-" + pool.id + " span").text("Destroying storage pool..."); + + if (filesystems.id.length > 0) { + FnStoragePoolDestroyCommand({ name: pool.name, id: pool.id, force: pool.force }) + .done(function () { + $("#spinner-storagepool-destroy-" + pool.id + " span").text("Destroying Samba shares..."); + + FnSambaSharesDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { id: filesystems.id }, { restart: samba.restart }, { silent: false }) + .finally(function () { + if (pool.labelclear) { + $("#spinner-storagepool-destroy-" + pool.id + " span").text("Clearing disk labels..."); + + FnStoragePoolDestroyLabelClear({ name: pool.name, id: pool.id }, { id: disks.attached }) + .finally(function () { + $("#modal-storagepool-destroy-" + pool.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 200); + }); + } else { + $("#modal-storagepool-destroy-" + pool.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 200); + } + }) + }); + } else { + FnStoragePoolDestroyCommand({ name: pool.name, id: pool.id, force: pool.force }) + .done(function () { + if (pool.labelclear) { + $("#spinner-storagepool-destroy-" + pool.id + " span").text("Clearing disk labels..."); + + FnStoragePoolDestroyLabelClear({ name: pool.name, id: pool.id }, { id: disks.attached }) + .finally(function () { + $("#modal-storagepool-destroy-" + pool.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 200); + }); + } else { + $("#modal-storagepool-destroy-" + pool.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 200); + } + }) + .finally(function () { + FnSambaStart(); + }); + } + }) + .fail(function (message, data) { + FnStoragePoolDestroyFail({ name: pool.name, id: pool.id }, { data: data, message: message }); + FnSambaStart(); + }); + } else { + FnStoragePoolDestroyCommand({ name: pool.name, id: pool.id, force: pool.force }) + .done(function () { + if (pool.labelclear) { + $("#spinner-storagepool-destroy-" + pool.id + " span").text("Clearing disk labels..."); + + FnStoragePoolDestroyLabelClear({ name: pool.name, id: pool.id }, { id: disks.attached }) + .finally(function () { + $("#modal-storagepool-destroy-" + pool.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 200); + }); + } else { + $("#modal-storagepool-destroy-" + pool.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 200); + } + }) + .finally(function () { + FnSambaStart(); + }); + } + }); + } else { + if (zfsmanager.configuration.samba.manage) { + $("#spinner-storagepool-destroy-" + pool.id + " span").text("Retrieving Samba shares..."); + + FnSambaSharesGet({ name: pool.name, id: pool.id }, { name: null, clones: [] }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Shares, Get:" })); + + let filesystems = { + id: data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) + }; + + $("#spinner-storagepool-destroy-" + pool.id + " span").text("Destroying storage pool..."); + + if (filesystems.id.length > 0) { + FnStoragePoolDestroyCommand({ name: pool.name, id: pool.id, force: pool.force }) + .done(function () { + $("#spinner-storagepool-destroy-" + pool.id + " span").text("Destroying Samba shares..."); + + FnSambaSharesDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { id: filesystems.id }, { restart: samba.restart }, { silent: false }) + .finally(function () { + if (pool.labelclear) { + $("#spinner-storagepool-destroy-" + pool.id + " span").text("Clearing disk labels..."); + + FnStoragePoolDestroyLabelClear({ name: pool.name, id: pool.id }, { id: disks.attached }) + .finally(function () { + $("#modal-storagepool-destroy-" + pool.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 200); + }); + } else { + $("#modal-storagepool-destroy-" + pool.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 200); + } + }) + }); + } else { + FnStoragePoolDestroyCommand({ name: pool.name, id: pool.id, force: pool.force }) + .done(function () { + if (pool.labelclear) { + $("#spinner-storagepool-destroy-" + pool.id + " span").text("Clearing disk labels..."); + + FnStoragePoolDestroyLabelClear({ name: pool.name, id: pool.id }, { id: disks.attached }) + .finally(function () { + $("#modal-storagepool-destroy-" + pool.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 200); + }); + } else { + $("#modal-storagepool-destroy-" + pool.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 200); + } + }); + } + }) + .fail(function (message, data) { + FnStoragePoolDestroyFail({ name: pool.name, id: pool.id }, { data: data, message: message }); + }); + } else { + FnStoragePoolDestroyCommand({ name: pool.name, id: pool.id, force: pool.force }) + .done(function () { + if (pool.labelclear) { + $("#spinner-storagepool-destroy-" + pool.id + " span").text("Clearing disk labels..."); + + FnStoragePoolDestroyLabelClear({ name: pool.name, id: pool.id }, { id: disks.attached }) + .finally(function () { + $("#modal-storagepool-destroy-" + pool.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 200); + }); + } else { + $("#modal-storagepool-destroy-" + pool.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 200); + } + }); + } + } +} + +function FnStoragePoolDestroyCommand(pool = { name, id, force: false }) { + let process = { + command: ["/sbin/zpool", "destroy", pool.name] + }; + + if (pool.force) { + process.command.splice(2, 0, "-f"); + } + + FnConsole.log[1]("Storage Pools, Destroy: In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "Storage Pool successfully destroyed", description: pool.name, breakword: false }, { name: "storagepool-destroy", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, Destroy: Success, Pool: " + pool.name); + }) + .fail(function (message, data) { + FnStoragePoolDestroyFail({ name: pool.name, id: pool.id }, { data: data, message: message }); + }); +} + +function FnStoragePoolDestroyFail(pool = { name, id }, process = { data, message }) { + FnDisplayAlert({ status: "danger", title: "Storage Pool could not be destroyed", description: pool.name, breakword: false }, { name: "storagepool-destroy", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, Destroy: Failed, Pool: " + pool.name + ", Message: " + (process.data ? process.data : process.message)); + + $("#modal-storagepool-destroy-" + pool.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 200); +} + +function FnStoragePoolDestroyLabelClear(pool = { name, id }, disks = { id: [] }) { + let process = { + promise: cockpit.defer() + }; + let promise = Promise.resolve(); + + disks.clear = { + error: 0 + }; + + FnConsole.log[2]("Storage Pools, Disk Labels, Clear: In Progress"); + + if (disks.id.length > 0) { + disks.id.forEach((_value, _index) => { + promise = promise.then(_ => new Promise(resolve => + setTimeout(function () { + FnStoragePoolDiskLabelClear({ name: pool.name, id: pool.id }, { id: _value, inactive: true }, { silent: true }) + .fail(function () { + disks.clear.error++; + }); + + if (_index == (disks.id.length - 1)) { + setTimeout(function () { + if (disks.clear.error == 0) { + FnDisplayAlert({ status: "success", title: "Storage Pool disk labels successfully cleared", description: pool.name, breakword: false }, { name: "storagepool-destroy-labelclear", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, Disk Labels, Clear: Success"); + } else { + FnDisplayAlert({ status: "danger", title: "Storage Pool disk labels could not be cleared", description: pool.name, breakword: false }, { name: "storagepool-destroy-labelclear", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, Disk Labels, Clear: Failed"); + } + + process.promise.resolve(); + }, 2000); + } + + resolve(); + }, 2000) + )); + }); + } else { + process.promise.resolve(); + } + + return process.promise.promise(); +} + +function FnStoragePoolDiskAttach(pool = { name, id, force: false }, virtualdevice = { id, disk: true }, disk = { idnew: [] }, modal = { name, id }) { + virtualdevice.mirror = { + start: null, + end: null + }; + + $("#spinner-" + modal.name + "-" + modal.id + " span").text("Attaching disk..."); + + if (!virtualdevice.disk && /^mirror-/.test(virtualdevice.id)) { + disk.id = ""; + + FnDisksStoragePoolsAttachedGet({ name: pool.name, id: pool.id }, { id: { blockdevice: false } }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Disks, Storage Pools, Attached, Get:" })); + + pool.attached = data.replace(/\n\t+/g, "[TAB1]").split(/\n/g).filter(v => v); + pool.attachedconfig = []; + + pool.attached.forEach((_value, _index) => { + if (/\[TAB1\]NAME/g.test(_value)) { //Config header row + _value = _value.split("upath").slice(1).join("."); //Remove config header row (and any previous text if exists) + + if (new RegExp("^\\[TAB1\\]" + pool.name).test(_value)) { //Confirm config rows + _value.split("[TAB1]").filter(v => v && pool.attachedconfig.push(v)); + } + } + }); + + pool.attachedconfig.forEach((_value, _index) => { //Find disks in Mirror virtual device and get hierarchy information + let config = { + tier: { + level: (_value.match(/^\s*/g)[0].length / 2) + } + }; + + _value = _value.replace(/ +/g, "\u22C5").replace(/^\u22C5/, "").split("\u22C5").filter(v => v); + + virtualdevice.mirror.regexp = new RegExp(virtualdevice.id, "g"); + + if (config.tier.level == 1 && virtualdevice.mirror.regexp.test(_value[0])) { + if (!virtualdevice.mirror.start) { + virtualdevice.mirror.start = _index; + } + } + + if (virtualdevice.mirror.start && _index > virtualdevice.mirror.start) { + if (config.tier.level == 1) { + if (!virtualdevice.mirror.end) { + virtualdevice.mirror.end = _index; + } + } + } + }); + + if (!virtualdevice.mirror.end) { + virtualdevice.mirror.end = pool.attachedconfig.length; + } + + pool.attachedconfig.forEach((_value, _index) => { //Find first healthy disk in the mirror virtual device + let config = { + disk: { + upath: "" + }, + tier: { + level: (_value.match(/^\s*/g)[0].length / 2) + } + }; + + _value = _value.replace(/ +/g, "\u22C5").replace(/^\u22C5/, "").split("\u22C5").filter(v => v); + + if (/^\/dev\/nvme|^\/dev\/sd/gi.test(_value[5])) { //upath + config.disk.upath = _value[5]; + } else if (!$.isNumeric(_value[0]) && _value[5] != "was") { //upath appears after error messages and before trim messages + for (let i = 5; i < _value.length; i++) { + if (/^\/dev\/nvme|^\/dev\/sd/gi.test(_value[i])) { + config.disk.upath = _value[i]; + } + } + } + + if (config.tier.level == 2 && _index > virtualdevice.mirror.start && _index < virtualdevice.mirror.end && _value[1] == "ONLINE") { + if (/^\/dev\/nvme|^\/dev\/sd/gi.test(config.disk.upath) || /^\/dev\/nvme|^\/dev\/sd/gi.test(_value[0])) { //Block Device + if (/^\/dev\/nvme\d+n\d+p\d+$/gi.test(_value[0])) { + if (!disk.id) { + disk.id = _value[0].replace(/p\d+$/, ""); + } + } else if (/^\/dev\/sd.*\d+$/gi.test(_value[0])) { + if (!disk.id) { + disk.id = _value[0].replace(/\d+$/, ""); + } + } else { + if (!disk.id) { + disk.id = _value[0].replace(/-part\d+$/, ""); + } + } + } else if (/^nvme-nvme/gi.test(_value[0]) || /^wwn-/gi.test(_value[0])) { //WWN + if (!disk.id) { + disk.id = _value[0].replace(/-part\d+$/, ""); + } + } + } + }); + + if (!disk.id || /^mirror-/g.test(disk.id)) { + FnStoragePoolDiskAttachFail({ name: pool.name, id: pool.id }, { id: virtualdevice.id, disk: virtualdevice.disk }, { idnew: disk.idnew }, { name: modal.name, id: modal.id }, { data: null, message: "There are no healthy disks to attach to." }); + } else { + FnStoragePoolDiskAttachCommand({ name: pool.name, id: pool.id, force: pool.force }, { id: virtualdevice.id, disk: virtualdevice.disk }, { id: disk.id, idnew: disk.idnew }, { name: modal.name, id: modal.id }); + } + }) + .fail(function (message, data) { + FnStoragePoolDiskAttachFail({ name: pool.name, id: pool.id }, { id: virtualdevice.id, disk: virtualdevice.disk }, { idnew: disk.idnew }, { name: modal.name, id: modal.id }, { data: data, message: message }); + }); + } else { + FnStoragePoolDiskAttachCommand({ name: pool.name, id: pool.id, force: pool.force }, { id: virtualdevice.id, disk: virtualdevice.disk }, { id: virtualdevice.id, idnew: disk.idnew }, { name: modal.name, id: modal.id }); + } +} + +function FnStoragePoolDiskAttachCommand(pool = { name, id, force: false }, virtualdevice = { id, disk: true }, disk = { id, idnew }, modal = { name, id }) { + let process = { + command: ["/sbin/zpool", "attach", pool.name, disk.id, disk.idnew] + }; + + if (pool.force) { + process.command.splice(2, 0, "-f"); + } + + FnConsole.log[1]("Storage Pools, Disk, Attach: In Progress, Pool: " + pool.name + ", " + (!virtualdevice.disk ? "Virtual Device: " + virtualdevice.id + ", " : "") + "Disk: " + disk.idnew); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "Disk attached successfully to Storage Pool", description: pool.name, breakword: false }, { name: "storagepool-disk-attach", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, Disk, Attach: Success, Pool: " + pool.name + ", " + (!virtualdevice.disk ? "Virtual Device: " + virtualdevice.id + ", " : "") + "Disk: " + disk.idnew); + }) + .fail(function (message, data) { + FnDisplayAlert({ status: "danger", title: "Disk could not be attached to Storage Pool", description: pool.name, breakword: false }, { name: "storagepool-disk-attach", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, Disk, Attach: Failed, Pool: " + pool.name + ", " + (!virtualdevice.disk ? "Virtual Device: " + virtualdevice.id + ", " : "") + "Disk: " + disk.idnew + ", Message: " + (data ? data : message)); + }) + .finally(function () { + $("#modal-" + modal.name + "-" + modal.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); + }, 200); + });; +} + +function FnStoragePoolDiskAttachFail(pool = { name, id }, virtualdevice = { id, disk: true }, disk = { idnew }, modal = { name, id }, process = { data, message }) { + FnDisplayAlert({ status: "danger", title: "Disk could not be attached to Storage Pool", description: pool.name, breakword: false }, { name: "storagepool-disk-attach", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, Disk, Attach: Failed, Pool: " + pool.name + ", " + (!virtualdevice.disk ? "Virtual Device: " + virtualdevice.id + ", " : "") + "Disk: " + disk.idnew + ", Message: " + (process.data ? process.data : process.message)); + + if (modal.id) { + $("#modal-" + modal.name + "-" + modal.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); + }, 200); + } +} + +function FnStoragePoolDiskClear(pool = { name, id }, disk = { id }, modal = { name, id }) { + let process = { + command: ["/sbin/zpool", "clear", pool.name, disk.id] + }; + + FnConsole.log[2]("Storage Pools, Disk, Clear Errors: In Progress, Pool: " + pool.name + ", Disk: " + disk.id); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-" + modal.name + "-" + modal.id + " span").text("Clearing disk errors..."); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "Disk errors successfully cleared", description: disk.id, breakword: false }, { name: "storagepool-disk-clear", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, Disk, Clear Errors: Success, Pool: " + pool.name + ", Disk: " + disk.id); + }) + .fail(function (message, data) { + FnDisplayAlert({ status: "danger", title: "Disk errors could not be cleared", description: disk.id, breakword: false }, { name: "storagepool-disk-clear", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, Disk, Clear Errors: Failed, Pool: " + pool.name + ", Disk: " + disk.id + ", Message: " + (data ? data : message)); + }) + .finally(function () { + $("#modal-" + modal.name + "-" + modal.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); + }, 200); + }); +} + +function FnStoragePoolDiskDetach(pool = { name, id }, disk = { id, labelclear: false }, modal = { name, id }) { + let process = { + command: ["/sbin/zpool", "detach", pool.name, disk.id] + }; + + modal.hide = true; + + FnConsole.log[1]("Storage Pools, Disk, Detach: In Progress, Pool: " + pool.name + ", Disk: " + disk.id); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-" + modal.name + "-" + modal.id + " span").text("Detaching disk..."); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "Disk detached successfully from Storage Pool", description: pool.name, breakword: false }, { name: "storagepool-disk-detach", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, Disk, Detach: Success, Pool: " + pool.name + ", Disk: " + disk.id); + + if (disk.labelclear) { + modal.hide = false; + + $("#spinner-" + modal.name + "-" + modal.id + " span").text("Clearing disk label..."); + + setTimeout(function () { + FnStoragePoolDiskLabelClear({ name: pool.name, id: pool.id }, { id: disk.id, inactive: false }, { silent: false }) + .finally(function () { + $("#modal-" + modal.name + "-" + modal.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); + }, 200); + }) + }, 2000); + } + }) + .fail(function (message, data) { + FnDisplayAlert({ status: "danger", title: "Disk could not be detached from Storage Pool", description: pool.name, breakword: false }, { name: "storagepool-disk-detach", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, Disk, Detach: Failed, Pool: " + pool.name + ", Disk: " + disk.id + ", Message: " + (data ? data : message)); + }) + .finally(function () { + if (modal.hide) { + $("#modal-" + modal.name + "-" + modal.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); + }, 200); + } + });; +} + +function FnStoragePoolDiskLabelClear(pool = { name, id }, disk = { id, inactive: false }, display = { silent: false }) { + let process = { + command: ["/sbin/zpool", "labelclear", disk.id] + }; + + if (disk.inactive) { + process.command.splice(2, 0, "-f"); + } + + FnConsole.log[2]("Storage Pools, Disk Label, Clear: In Progress, Disk: " + disk.id); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + if (!display.silent) { + FnDisplayAlert({ status: "success", title: "Disk label successfully cleared", description: disk.id, breakword: false }, { name: "storagepool-disk-labelclear", id: pool.id, timeout: 4 }); + } + + FnConsole.log[1]("Storage Pools, Disk Label, Clear: Success, Disk: " + disk.id); + + setTimeout(function () { + FnDisksBlkidGet(); + }, 200); + }) + .fail(function (message, data) { + if (!display.silent) { + FnDisplayAlert({ status: "danger", title: "Disk label could not be cleared", description: disk.id, breakword: false }, { name: "storagepool-disk-labelclear", id: pool.id, timeout: 4 }); + } + + FnConsole.warn("Storage Pools, Disk Label, Clear: Failed, Disk: " + disk.id + ", Message: " + (data ? data : message)); + }); +} + +function FnStoragePoolDiskOffline(pool = { name, id }, disk = { id, force: false, temporary: false }, modal = { name, id }) { + let process = { + command: ["/sbin/zpool", "offline", pool.name, disk.id] + }; + + if (disk.force) { + process.command.splice(2, 0, "-f"); + } + if (disk.temporary) { + process.command.splice(2, 0, "-t"); + } + + FnConsole.log[1]("Storage Pools, Disk, Offline: In Progress, Pool: " + pool.name + ", Disk: " + disk.id); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-" + modal.name + "-" + modal.id + " span").text("Setting disk offline..."); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "Disk successfully set offline", description: disk.id, breakword: false }, { name: "storagepool-disk-offline", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, Disk, Offline: Success, Pool: " + pool.name + ", Disk: " + disk.id); + }) + .fail(function (message, data) { + FnDisplayAlert({ status: "danger", title: "Disk could not be set offline", description: disk.id, breakword: false }, { name: "storagepool-disk-offline", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, Disk, Offline: Failed, Pool: " + pool.name + ", Disk: " + disk.id + ", Message: " + (data ? data : message)); + }) + .finally(function () { + $("#modal-" + modal.name + "-" + modal.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); + }, 200); + });; +} + +function FnStoragePoolDiskOnline(pool = { name, id, scrub: false }, disk = { id, expand: false }, modal = { name, id }) { + let process = { + command: ["/sbin/zpool", "online", pool.name, disk.id] + }; + + if (disk.expand) { + process.command.splice(2, 0, "-e"); + } + + FnConsole.log[1]("Storage Pools, Disk, Online: In Progress, Pool: " + pool.name + ", Disk: " + disk.id); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-" + modal.name + "-" + modal.id + " span").text("Setting disk online..."); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function (data, message) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Storage Pools, Disk, Online:" })); + + if (/^warning:/gi.test(data)) { + FnDisplayAlert({ status: "warning", title: "Disk set online but remains in faulted state", description: disk.id, breakword: false }, { name: "storagepool-disk-online", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, Disk, Online: Warning, Pool: " + pool.name + ", Message: " + (data ? data.replace(/^warning: /gi, "") : message)); + } else { + FnDisplayAlert({ status: "success", title: "Disk successfully set online", description: disk.id, breakword: false }, { name: "storagepool-disk-online", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, Disk, Online: Success, Pool: " + pool.name + ", Disk: " + disk.id); + } + + if (pool.scrub) { + FnStoragePoolScrubStart({ name: pool.name, id: pool.id }, { resume: false }, { refresh: false }); + } + }) + .fail(function (message, data) { + FnDisplayAlert({ status: "danger", title: "Disk could not be set online", description: disk.id, breakword: false }, { name: "storagepool-disk-online", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, Disk, Online: Failed, Pool: " + pool.name + ", Disk: " + disk.id + ", Message: " + (data ? data : message)); + }) + .finally(function () { + $("#modal-" + modal.name + "-" + modal.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); + }, 200); + });; +} + +function FnStoragePoolDiskReplace(pool = { name, id, force: false }, disk = { id, idnew }, modal = { name, id }) { + let process = { + command: ["/sbin/zpool", "replace", pool.name, disk.id, disk.idnew] + }; + + if (pool.force) { + process.command.splice(2, 0, "-f"); + } + + FnConsole.log[1]("Storage Pools, Disk, Replace: In Progress, Pool: " + pool.name + ", Disk: " + disk.id); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-" + modal.name + "-" + modal.id + " span").text("Replacing disk..."); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "Disk replaced successfully on Storage Pool", description: pool.name, breakword: false }, { name: "storagepool-disk-replace", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, Disk, Replace: Success, Pool: " + pool.name + ", Disk: " + disk.id); + }) + .fail(function (message, data) { + FnDisplayAlert({ status: "danger", title: "Disk could not be replaced on Storage Pool", description: pool.name, breakword: false }, { name: "storagepool-disk-replace", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, Disk, Replace: Failed, Pool: " + pool.name + ", Disk: " + disk.id + ", Message: " + (data ? data : message)); + }) + .finally(function () { + $("#modal-" + modal.name + "-" + modal.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); + }, 200); + });; +} + +function FnStoragePoolExport(pool = { name, id, altroot: false, force: false, readonly: false }, samba = { restart: false }) { + if (samba.restart) { + FnSambaStop() + .finally(function () { + if (zfsmanager.configuration.samba.manage) { + $("#spinner-storagepool-export-" + pool.id + " span").text("Retrieving Samba shares..."); + + FnSambaSharesGet({ name: pool.name, id: pool.id }, { name: null, clones: [] }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Shares, Get:" })); + + let filesystems = { + id: data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) + }; + + $("#spinner-storagepool-export-" + pool.id + " span").text("Exporting storage pool..."); + + if (filesystems.id.length > 0) { + FnStoragePoolExportCommand({ name: pool.name, id: pool.id, force: pool.force }, { refresh: false }) + .done(function () { + $("#spinner-storagepool-export-" + pool.id + " span").text("Destroying Samba shares..."); + + FnSambaSharesDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { id: filesystems.id }, { restart: samba.restart }, { silent: false }) + .finally(function () { + $("#modal-storagepool-export-" + pool.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 200); + }); + }); + } else { + FnStoragePoolExportCommand({ name: pool.name, id: pool.id, force: pool.force }, { refresh: true }) + .finally(function () { + FnSambaStart(); + }); + } + }) + .fail(function (message, data) { + FnStoragePoolExportFail({ name: pool.name, id: pool.id }, { data: data, message: message }, { refresh: true }); + FnSambaStart(); + }); + } else { + FnStoragePoolExportCommand({ name: pool.name, id: pool.id, force: pool.force }, { refresh: true }) + .finally(function () { + FnSambaStart(); + }); + } + }); + } else { + if (zfsmanager.configuration.samba.manage) { + $("#spinner-storagepool-export-" + pool.id + " span").text("Retrieving Samba shares..."); + + FnSambaSharesGet({ name: pool.name, id: pool.id }, { name: null, clones: [] }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Shares, Get:" })); + + let filesystems = { + id: data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) + }; + + $("#spinner-storagepool-export-" + pool.id + " span").text("Exporting storage pool..."); + + if (filesystems.id.length > 0) { + FnStoragePoolExportCommand({ name: pool.name, id: pool.id, force: pool.force }, { refresh: false }) + .done(function () { + $("#spinner-storagepool-export-" + pool.id + " span").text("Destroying Samba shares..."); + + FnSambaSharesDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { id: filesystems.id }, { restart: samba.restart }, { silent: false }) + .finally(function () { + $("#modal-storagepool-export-" + pool.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 200); + }); + }); + } else { + FnStoragePoolExportCommand({ name: pool.name, id: pool.id, force: pool.force }, { refresh: true }); + } + }) + .fail(function (message, data) { + FnStoragePoolExportFail({ name: pool.name, id: pool.id }, { data: data, message: message }, { refresh: true }); + }); + } else { + FnStoragePoolExportCommand({ name: pool.name, id: pool.id, force: pool.force }, { refresh: true }); + } + } +} + +function FnStoragePoolExportCommand(pool = { name, id, force: false }, display = { refresh: true }) { + let process = { + command: ["/sbin/zpool", "export", pool.name] + }; + + if (pool.force) { + process.command.splice(2, 0, "-f"); + } + + FnConsole.log[1]("Storage Pools, Export: In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "Storage Pool successfully exported", description: pool.name, breakword: false }, { name: "storagepool-export", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, Export: Success, Pool: " + pool.name); + }) + .fail(function (message, data) { + FnStoragePoolExportFail({ name: pool.name, id: pool.id }, { data: data, message: message }, { refresh: false }); + + display.refresh = true; + }) + .finally(function () { + if (display.refresh) { + $("#modal-storagepool-export-" + pool.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 200); + } + }); +} + +function FnStoragePoolExportFail(pool = { name, id }, process = { data, message }, display = { refresh: true }) { + FnDisplayAlert({ status: "danger", title: "Storage Pool could not be exported", description: pool.name, breakword: false }, { name: "storagepool-export", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, Export: Failed, Pool: " + pool.name + ", Message: " + (process.data ? process.data : process.message)); + + if (display.refresh) { + $("#modal-storagepool-export-" + pool.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 200); + } +} + +function FnStoragePoolHealthIcon(pool = { health }) { + switch (pool.health.toLowerCase()) { + case "online": + pool.healthicon = "pficon pficon-ok list-view-pf-icon-sm"; + break; + case "offline": + pool.healthicon = "fa pficon-info list-view-pf-icon-sm"; + break; + case "split": + pool.healthicon = "fa pficon-info list-view-pf-icon-sm"; + break; + case "degraded": + pool.healthicon = "pficon pficon-warning-triangle-o list-view-pf-icon-sm"; + break; + case "unknown": + pool.healthicon = "pficon pficon-warning-triangle-o list-view-pf-icon-sm"; + break; + case "removed": + pool.healthicon = "pficon pficon-error-circle-o list-view-pf-icon-sm"; + break; + case "faulted": + pool.healthicon = "pficon pficon-error-circle-o list-view-pf-icon-sm"; + break; + case "unavail": + pool.healthicon = "pficon pficon-error-circle-o list-view-pf-icon-sm"; + break; + case "avail": + pool.healthicon = "pficon pficon-ok list-view-pf-icon-sm"; + break; + case "inuse": + pool.healthicon = "pficon pficon-ok list-view-pf-icon-sm"; + break; + case "fail": + pool.healthicon = "pficon pficon-error-circle-o list-view-pf-icon-sm"; + break; + case "destroyed": + pool.healthicon = "pficon pficon-error-circle-o list-view-pf-icon-sm"; + break; + default: + pool.healthicon = "fa pficon-info list-view-pf-icon-sm"; + break; + } + + return pool.healthicon; +} + +function FnStoragePoolImport(pool = { name, altroot, destroyed: false, force: false, guid, ignoremissinglog: false, namenew, readonly: false, recoverymode: false }, filesystem = { mount: true, selinux: true }, disks = { id: { blockdevice: true, disk: false, path: false, vdev: false }, identifier }) { + let process = { + command: ["/sbin/zpool", "import", pool.guid] + }; + let modal = { + hide: true + }; + + disks.devpath = "/dev"; + disks.fallback = false; + disks.identifiertext = "Block Device"; + + if (pool.namenew) { + pool.name = pool.namenew; + } + + process.command.push(pool.name); + + pool.id = FnGenerateId({ at: false, colon: true, forwardslash: false, period: true, underscore: true, whitespace: true }, { name: pool.name, attribute: true }); + pool.imported = false; + + if (!filesystem.mount) { + process.command.splice(2, 0, "-N"); + } + + if (pool.altroot) { + process.command.splice(2, 0, "-o"); + process.command.splice(3, 0, "altroot=" + pool.altroot); + } + if (pool.destroyed) { + process.command.splice(2, 0, "-D"); + } + if (pool.force) { + process.command.splice(2, 0, "-f"); + } + if (pool.recoverymode) { + process.command.splice(2, 0, "-F"); + } + if (pool.ignoremissinglog) { + process.command.splice(2, 0, "-m"); + } + if (pool.readonly) { + process.command.splice(2, 0, "-o"); + process.command.splice(3, 0, "readonly=on"); + } + + process.command.splice(2, 0, "-d"); + + switch (disks.identifier) { //Fallback to block device to prevent import error when selected identifier is not available + case "disk": + if (disks.id.disk) { + disks.devpath = "/dev/disk/by-id"; + } else { + disks.fallback = true; + } + disks.identifiertext = "Disk / WWN"; + break; + case "path": + if (disks.id.path) { + disks.devpath = "/dev/disk/by-path"; + } else { + disks.fallback = true; + } + disks.identifiertext = "Hardware Path"; + break; + case "vdev": + if (disks.id.vdev) { + disks.devpath = "/dev/disk/by-vdev"; + } else { + disks.fallback = true; + } + disks.identifiertext = "Virtual Device Mapping"; + break; + } + + process.command.splice(3, 0, disks.devpath); + + FnConsole.log[1]("Storage Pools, Import: In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-storagepools-import span").text("Importing storage pool..."); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + pool.imported = true; + + if (disks.fallback) { + FnDisplayAlert({ status: "warning", title: "Storage Pool imported with errors", description: pool.name, breakword: false }, { name: "storagepools-import", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, Import: Warning, Pool: " + pool.name + ", Message: " + disks.identifiertext + " disks identifier was not available during import. Block Device disks identifier was used."); + } else { + FnDisplayAlert({ status: "success", title: "Storage Pool successfully imported", description: pool.name, breakword: false }, { name: "storagepools-import", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, Import: Success, Pool: " + pool.name); + } + }) + .fail(function (message, data) { + if (/cannot mount.*directory is not empty|smb add share failed|cannot share/gi.test(data)) { //Storage pool has successfully imported, however a file system error is generated + pool.imported = true; + + FnDisplayAlert({ status: "warning", title: "Storage Pool imported with errors", description: pool.name, breakword: false }, { name: "storagepools-import", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, Import: Warning, Pool: " + pool.name + ", Message: " + (data ? data : message)); + } else if (/cannot import.*pool already exists/gi.test(data)) { + modal.hide = false; + + if (!$("#switch-storagepools-import-rename input").prop("checked")) { + $("#switch-storagepools-import-rename input").click(); + } + $("#validationwrapper-storagepools-import-storagepools").addClass("has-error"); + $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text("Storage pool name already exists. New name is needed."); + $("#input-storagepools-import-namenew").focus(); + } else { + FnDisplayAlert({ status: "danger", title: "Storage Pool could not be imported", description: pool.name, breakword: false }, { name: "storagepools-import", id: pool.id, timeout: 4 }); + } + + if (!modal.hide) { + $("#spinner-storagepools-import").addClass("hidden"); + $("#spinner-storagepools-import span").text(""); + $("#btn-storagepools-import-apply").prop("disabled", false); + } + + if (!pool.imported) { + FnConsole.warn("Storage Pools, Import: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); + } + }) + .finally(function () { + if (pool.imported) { + if (filesystem.selinux && !pool.readonly) { + $("#spinner-storagepools-import span").text("Configuring SELinux contexts for Samba..."); + + FnStoragePoolSelinuxContextsSambaSet({ name: pool.name, id: pool.id }) + .finally(function () { + if (zfsmanager.configuration.samba.manage) { + if (!pool.readonly) { + $("#spinner-storagepools-import span").text("Disabling Samba share inheritance..."); + + FnFileSystemShareSmbInheritedDisable({ name: pool.name, id: pool.id, altroot: (pool.altroot ? true : false) }, { name: null }, { disable: false }) + .finally(function () { + $("#spinner-storagepools-import span").text("Creating Samba shares..."); + + FnSambaSharesEnable({ name: pool.name, id: pool.id, altroot: (pool.altroot ? true : false), readonly: pool.readonly }, { name: null, force: true }, { restart: false }, { refresh: false, silent: false }) + .finally(function () { + if (modal.hide) { + $("#modal-storagepools-import").modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 200); + } + }); + }); + } else { + $("#spinner-storagepools-import span").text("Creating Samba shares..."); + + FnSambaSharesEnable({ name: pool.name, id: pool.id, altroot: (pool.altroot ? true : false), readonly: pool.readonly }, { name: null, force: true }, { restart: false }, { refresh: false, silent: false }) + .finally(function () { + if (modal.hide) { + $("#modal-storagepools-import").modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 200); + } + }); + } + } else { + if (modal.hide) { + $("#modal-storagepools-import").modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 200); + } + } + }); + } else { + if (zfsmanager.configuration.samba.manage) { + if (!pool.readonly) { + $("#spinner-storagepools-import span").text("Disabling Samba share inheritance..."); + + FnFileSystemShareSmbInheritedDisable({ name: pool.name, id: pool.id, altroot: (pool.altroot ? true : false) }, { name: null }, { disable: false }) + .finally(function () { + $("#spinner-storagepools-import span").text("Creating Samba shares..."); + + FnSambaSharesEnable({ name: pool.name, id: pool.id, altroot: (pool.altroot ? true : false), readonly: pool.readonly }, { name: null, force: true }, { restart: false }, { refresh: false, silent: false }) + .finally(function () { + if (modal.hide) { + $("#modal-storagepools-import").modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 200); + } + }); + }); + } else { + $("#spinner-storagepools-import span").text("Creating Samba shares..."); + + FnSambaSharesEnable({ name: pool.name, id: pool.id, altroot: (pool.altroot ? true : false), readonly: pool.readonly }, { name: null, force: true }, { restart: false }, { refresh: false, silent: false }) + .finally(function () { + if (modal.hide) { + $("#modal-storagepools-import").modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 200); + } + }); + } + } else { + if (modal.hide) { + $("#modal-storagepools-import").modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 200); + } + } + } + } else { + if (modal.hide) { + $("#modal-storagepools-import").modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 200); + } + } + }); +} + +function FnStoragePoolRefreservationSet(pool = { name, id }, filesystem = { refreservation }) { + let process = { + command: ["/sbin/zfs", "set", "refreservation=" + filesystem.refreservation, pool.name] + }; + + FnConsole.log[2]("Storage Pools, Refreservation, Set: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnConsole.log[2]("Storage Pools, Refreservation, Set: Success, Pool: " + pool.name); + }) + .fail(function (message, data) { + FnConsole.warn("Storage Pools, Refreservation, Set: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); + }); +} + +function FnStoragePoolRefresh(pool = { name, id }, refresh = { storagepool: true, filesystems: false, snapshots: false, status: false }) { + if (zfsmanager.configuration.zfs.storagepool.refreshall || refresh.storagepool) { + FnStoragePoolRefreshCommand({ name: pool.name, id: pool.id }); + } + + setTimeout(function () { + if (zfsmanager.configuration.zfs.storagepool.refreshall) { + FnStoragePoolRefreshAutoDisable({ name: pool.name, id: pool.id }); + } + + if (zfsmanager.configuration.zfs.storagepool.refreshall || refresh.filesystems) { + $("#btn-storagepool-filesystems-create-" + pool.id).prop("disabled", true); + $("#btn-storagepool-filesystems-refresh-" + pool.id).prop("disabled", true); + $("[id^=btn-storagepool-filesystem-dropdown-" + pool.id + "]").addClass("disabled"); + $("#paneltitle-storagepool-filesystems-" + pool.id).addClass("hidden"); + $("#spinner-storagepool-filesystems-" + pool.id).removeClass("hidden"); + + FnFileSystemsGet({ name: pool.name, id: pool.id }); + } + + if (zfsmanager.configuration.zfs.storagepool.refreshall || refresh.snapshots) { + $("#btn-storagepool-snapshots-create-" + pool.id).prop("disabled", true); + $("#btn-storagepool-snapshots-refresh-" + pool.id).prop("disabled", true); + $("[id^=btn-storagepool-snapshot-dropdown-" + pool.id + "]").addClass("disabled"); + $("#paneltitle-storagepool-snapshots-" + pool.id).addClass("hidden"); + $("#spinner-storagepool-snapshots-" + pool.id).removeClass("hidden"); + + FnSnapshotsGet({ name: pool.name, id: pool.id }); + } + + if (zfsmanager.configuration.zfs.storagepool.refreshall || refresh.status) { + $("#btn-storagepool-status-refresh-" + pool.id).prop("disabled", true); + $("[id^=btn-storagepool-status-dropdown-][id$=" + pool.id + "]").addClass("disabled"); + $("#paneltitle-storagepool-status-" + pool.id).addClass("hidden"); + $("#spinner-storagepool-status-" + pool.id).removeClass("hidden"); + $("#spinner-storagepool-status-0-" + pool.id).removeClass("hidden"); + + FnStatusGet({ name: pool.name, id: pool.id }); + } + }, 200); +} + +function FnStoragePoolRefreshAutoDisable(pool = { name, id }) { + if ($("#tr-storagepool-" + pool.id).attr("data-pool-refresh-id") != "") { + FnConsole.log[2]("Storage Pools, Refresh, Auto: Disabled, Pool: " + pool.name); + } + + clearInterval($("#tr-storagepool-" + pool.id).attr("data-pool-refresh-id")); + + $("#tr-storagepool-" + pool.id).attr("data-pool-refresh-id", ""); + $("#btn-storagepool-status-refresh-" + pool.id).text("Refresh"); +} + +function FnStoragePoolRefreshCommand(pool = { name, id }) { + let process = { + command: ["/sbin/zpool", "list", "-H", "-o", "guid,health,size,alloc,free,fragmentation,autotrim,version,feature@allocation_classes,feature@async_destroy,feature@bookmark_v2,feature@bookmarks,feature@device_removal,feature@edonr,feature@embedded_data,feature@empty_bpobj,feature@enabled_txg,feature@encryption,feature@extensible_dataset,feature@filesystem_limits,feature@hole_birth,feature@large_blocks,feature@large_dnode,feature@lz4_compress,feature@multi_vdev_crash_dump,feature@obsolete_counts,feature@project_quota,feature@resilver_defer,feature@sha512,feature@skein,feature@spacemap_histogram,feature@spacemap_v2,feature@userobj_accounting,feature@zpool_checkpoint", "-p", pool.name] + }; + + FnConsole.log[2]("Storage Pools, Refresh: In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Storage Pools, Refresh:" })); + + pool.properties = data.trim().split(/\t/g).filter(v => v); + + //0=guid, 1=health, 2=size, 3=alloc, 4=free, 5=fragmentation, 6=autotrim, 7=version, 8=feature@allocation_classes, 9=feature@async_destroy, 10=feature@bookmark_v2, 11=feature@bookmarks, 12=feature@device_removal, 13=feature@edonr, 14=feature@embedded_data, 15=feature@empty_bpobj, 16=feature@enabled_txg, 17=feature@encryption, 18=feature@extensible_dataset, 19=feature@filesystem_limits, 20=feature@hole_birth, 21=feature@large_blocks, 22=feature@large_dnode, 23=feature@lz4_compress, 24=feature@multi_vdev_crash_dump, 25=feature@obsolete_counts, 26=feature@project_quota, 27=feature@resilver_defer, 28=feature@sha512, 29=feature@skein, 30=feature@spacemap_histogram, 31=feature@spacemap_v2, 32=feature@userobj_accounting, 33=feature@zpool_checkpoint + + pool.allocated = FnFormatBytes({ base2: true, decimals: 2, value: pool.properties[3] }); + pool.allocatedpercent = FnRound({ decimals: 2, value: (pool.properties[3] / pool.properties[2]) * 100 }); + pool.autotrim = (pool.properties[6].toLowerCase() == "on" ? true : false); + pool.boot = (zfsmanager.zfs.storagepool.boot && pool.name == zfsmanager.zfs.storagepool.boot ? true : false); + pool.feature = { + allocation_classes: (/active|enabled/gi.test(pool.properties[8]) ? true : false), + async_destroy: (/active|enabled/gi.test(pool.properties[9]) ? true : false), + bookmark_v2: (/active|enabled/gi.test(pool.properties[10]) ? true : false), + bookmarks: (/active|enabled/gi.test(pool.properties[11]) ? true : false), + device_removal: (/active|enabled/gi.test(pool.properties[12]) ? true : false), + edonr: (/active|enabled/gi.test(pool.properties[13]) ? true : false), + embedded_data: (/active|enabled/gi.test(pool.properties[14]) ? true : false), + empty_bpobj: (/active|enabled/gi.test(pool.properties[15]) ? true : false), + enabled_txg: (/active|enabled/gi.test(pool.properties[16]) ? true : false), + encryption: (/active|enabled/gi.test(pool.properties[17]) ? true : false), + extensible_dataset: (/active|enabled/gi.test(pool.properties[18]) ? true : false), + filesystem_limits: (/active|enabled/gi.test(pool.properties[19]) ? true : false), + hole_birth: (/active|enabled/gi.test(pool.properties[20]) ? true : false), + large_blocks: (/active|enabled/gi.test(pool.properties[21]) ? true : false), + large_dnode: (/active|enabled/gi.test(pool.properties[22]) ? true : false), + lz4_compress: (/active|enabled/gi.test(pool.properties[23]) ? true : false), + multi_vdev_crash_dump: (/active|enabled/gi.test(pool.properties[24]) ? true : false), + obsolete_counts: (/active|enabled/gi.test(pool.properties[25]) ? true : false), + project_quota: (/active|enabled/gi.test(pool.properties[26]) ? true : false), + resilver_defer: (/active|enabled/gi.test(pool.properties[27]) ? true : false), + sha512: (/active|enabled/gi.test(pool.properties[28]) ? true : false), + skein: (/active|enabled/gi.test(pool.properties[29]) ? true : false), + spacemap_histogram: (/active|enabled/gi.test(pool.properties[30]) ? true : false), + spacemap_v2: (/active|enabled/gi.test(pool.properties[31]) ? true : false), + userobj_accounting: (/active|enabled/gi.test(pool.properties[32]) ? true : false), + zpool_checkpoint: (/active|enabled/gi.test(pool.properties[33]) ? true : false) + }; + pool.fragmentation = (pool.properties[5] == "-" ? 0 : pool.properties[5]); + pool.free = FnFormatBytes({ base2: true, decimals: 2, value: pool.properties[4] }); + pool.freepercent = FnRound({ decimals: 2, value: (pool.properties[4] / pool.properties[2]) * 100 }); + pool.guid = pool.properties[0]; + pool.health = pool.properties[1]; + pool.healthicon = FnStoragePoolHealthIcon({ health: pool.health }); + pool.root = (zfsmanager.zfs.storagepool.root && pool.name == zfsmanager.zfs.storagepool.root ? true : false); + pool.size = FnFormatBytes({ base2: true, decimals: 2, value: pool.properties[2] }); + pool.upgrade = ($.isNumeric(pool.properties[6] && !pool.boot) ? true : false); + pool.version = pool.properties[7]; + + //Upgrade available if a requested feature flag returns false + if (!pool.boot) { + for (var x in pool.feature) { + if (!pool.feature[x] && !pool.upgrade) { + pool.upgrade = true; + } + } + } + + if (pool.upgrade) { + $("#span-storagepool-upgrade-" + pool.id).removeClass("hidden"); + } else { + $("#span-storagepool-upgrade-" + pool.id).addClass("hidden"); + } + + $("#div-storagepool-health-" + pool.id).empty().html(` ` + pool.health); + $("#div-storagepool-size-" + pool.id).text(pool.size); + $("#div-storagepool-allocated-" + pool.id).text(pool.allocated); + $("#div-storagepool-free-" + pool.id).text(pool.free); + $("#div-storagepool-fragmentation-" + pool.id).text(pool.fragmentation + " %"); + + $("#progressbar-storagepool-allocated-" + pool.id).attr("aria-valuenow", pool.allocatedpercent); + $("#progressbar-storagepool-allocated-" + pool.id).attr("title", pool.allocatedpercent + "% Allocated"); + $("#progressbar-storagepool-allocated-" + pool.id).attr("data-original-title", pool.allocatedpercent + "% Allocated"); + $("#progressbar-storagepool-allocated-" + pool.id).css("width", pool.allocatedpercent + "%"); + $("#progressbar-storagepool-allocated-" + pool.id + " .sr-only").text(pool.allocatedpercent + "% Allocated"); + + $("#progressbar-storagepool-free-" + pool.id).attr("aria-valuenow", pool.freepercent); + $("#progressbar-storagepool-free-" + pool.id).attr("title", pool.freepercent + "% Free"); + $("#progressbar-storagepool-free-" + pool.id).attr("data-original-title", pool.freepercent + "% Free"); + $("#progressbar-storagepool-free-" + pool.id).css("width", pool.freepercent + "%"); + $("#progressbar-storagepool-free-" + pool.id + " .sr-only").text(pool.freepercent + "% Free"); + + $("#tr-storagepool-" + pool.id).attr("data-pool-autotrim", pool.autotrim); + $("#tr-storagepool-" + pool.id).attr("data-pool-feature-allocation_classes", pool.feature.allocation_classes); + $("#tr-storagepool-" + pool.id).attr("data-pool-feature-device_removal", pool.feature.device_removal); + $("#tr-storagepool-" + pool.id).attr("data-pool-feature-edonr", pool.feature.edonr); + $("#tr-storagepool-" + pool.id).attr("data-pool-feature-encryption", pool.feature.encryption); + $("#tr-storagepool-" + pool.id).attr("data-pool-feature-large_blocks", pool.feature.large_blocks); + $("#tr-storagepool-" + pool.id).attr("data-pool-feature-lz4_compress", pool.feature.lz4_compress); + $("#tr-storagepool-" + pool.id).attr("data-pool-feature-resilver_defer", pool.feature.resilver_defer); + $("#tr-storagepool-" + pool.id).attr("data-pool-feature-sha512", pool.feature.sha512); + $("#tr-storagepool-" + pool.id).attr("data-pool-feature-skein", pool.feature.skein); + $("#tr-storagepool-" + pool.id).attr("data-pool-guid", pool.guid); + $("#tr-storagepool-" + pool.id).attr("data-pool-version", pool.version); + + FnConsole.log[1]("Storage Pools, Refresh: Success, Pool: " + pool.name); + }) + .fail(function (message, data) { + FnConsole.warn("Storage Pools, Refresh: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); + }); +} + +function FnStoragePoolRegenerateGuid(pool = { name, id }, modal = { name, id }) { + let process = { + command: ["/sbin/zpool", "reguid", pool.name] + }; + + FnConsole.log[2]("Storage Pools, Regenerate GUID: In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-" + modal.name + "-" + modal.id + " span").text("Regenerating storage pool GUID..."); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "Storage Pool GUID successfully regenerated", description: pool.name, breakword: false }, { name: "storagepool-regenerateguid", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, Regenerate GUID: Success, Pool: " + pool.name); + }) + .fail(function (message, data) { + FnDisplayAlert({ status: "danger", title: "Storage Pool GUID could not be regenerated", description: pool.name, breakword: false }, { name: "storagepool-regenerateguid", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, Regenerate GUID: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); + }) + .finally(function () { + $("#modal-" + modal.name + "-" + modal.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); + }, 200); + });; +} + +function FnStoragePoolResilver(pool = { name, id }, modal = { name, id }) { + let process = { + command: ["/sbin/zpool", "resilver", pool.name] + }; + + FnConsole.log[1]("Storage Pools, Resilver, Start: In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-" + modal.name + "-" + modal.id + " span").text("Starting storage pool resilver..."); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "Storage Pool resilver successfully started", description: pool.name, breakword: false }, { name: "storagepool-resilver", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, Resilver, Start: Success, Pool: " + pool.name); + }) + .fail(function (message, data) { + FnDisplayAlert({ status: "danger", title: "Storage Pool resilver could not be started", description: pool.name, breakword: false }, { name: "storagepool-resilver", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, Resilver, Start: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); + }) + .finally(function () { + $("#modal-" + modal.name + "-" + modal.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); + }, 200); + }); +} + +function FnStoragePoolScrubPause(pool = { name, id }, display = { refresh: true }) { + let process = { + command: ["/sbin/zpool", "scrub", "-p", pool.name] + }; + + FnConsole.log[2]("Storage Pools, Scrub, Pause: In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "Storage Pool scrub successfully paused", description: pool.name, breakword: false }, { name: "storagepool-scrub-pause", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, Scrub, Pause: Success, Pool: " + pool.name); + }) + .fail(function (message, data) { + FnDisplayAlert({ status: "danger", title: "Storage Pool scrub could not be paused", description: pool.name, breakword: false }, { name: "storagepool-scrub-pause", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, Scrub, Pause: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); + }) + .finally(function () { + if (display.refresh) { + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); + }, 200); + } + });; +} + +function FnStoragePoolScrubStart(pool = { name, id }, scrub = { resume: false }, display = { refresh: true }) { + let process = { + command: ["/sbin/zpool", "scrub", pool.name] + }; + + FnConsole.log[2]("Storage Pools, Scrub, " + (scrub.resume ? "Resume" : "Start") + ": In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "Storage Pool scrub successfully " + (scrub.resume ? "resumed" : "started"), description: pool.name, breakword: false }, { name: "storagepool-scrub-start", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, Scrub, " + (scrub.resume ? "Resume" : "Start") + ": Success, Pool: " + pool.name); + }) + .fail(function (message, data) { + if (/currently scrubbing/gi.test(data)) { //Start scrub will fail if the storage pool has already initiated scrub + FnDisplayAlert({ status: "success", title: "Storage Pool scrub successfully " + (scrub.resume ? "resumed" : "started"), description: pool.name, breakword: false }, { name: "storagepool-scrub-start", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, Scrub, " + (scrub.resume ? "Resume" : "Start") + ": Success, Pool: " + pool.name); + } else { + if (/currently resilvering/gi.test(data)) { //Start scrub will fail if the storage pool has initiated resilver + FnDisplayAlert({ status: "warning", title: "Storage Pool scrub could not be " + (scrub.resume ? "resumed" : "started") + ". Resilver in progress", description: pool.name, breakword: false }, { name: "storagepool-scrub-start", id: pool.id, timeout: 4 }); + } else { + FnDisplayAlert({ status: "danger", title: "Storage Pool scrub could not be " + (scrub.resume ? "resumed" : "started"), description: pool.name, breakword: false }, { name: "storagepool-scrub-start", id: pool.id, timeout: 4 }); + } + + FnConsole.warn("Storage Pools, Scrub, " + (scrub.resume ? "Resume" : "Start") + ": Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); + } + }) + .finally(function () { + if (display.refresh) { + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); + }, 200); + } + }); +} + +function FnStoragePoolScrubStop(pool = { name, id }, display = { refresh: true }) { + let process = { + command: ["/sbin/zpool", "scrub", "-s", pool.name] + }; + + FnConsole.log[2]("Storage Pools, Scrub, Stop: In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "Storage Pool scrub successfully stopped", description: pool.name, breakword: false }, { name: "storagepool-scrub-stop", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, Scrub, Stop: Success, Pool: " + pool.name); + }) + .fail(function (message, data) { + FnDisplayAlert({ status: "danger", title: "Storage Pool scrub could not be stopped", description: pool.name, breakword: false }, { name: "storagepool-scrub-stop", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, Scrub, Stop: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); + }) + .finally(function () { + if (display.refresh) { + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); + }, 200); + } + });; +} + +function FnStoragePoolSelinuxContextsSambaSet(pool = { name, id }, display = { silent: false }) { + let process = { + command: ["/sbin/zfs", "list", "-H", "-o", "name", "-r", "-t", "filesystem", pool.name], + promise: cockpit.defer() + }; + + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Storage Pools, SELinux Contexts, Samba, Set:" })); + + let filesystems = data.split(/\n/g).filter(v => v); + let promise = Promise.resolve(); + + if (filesystems.length > 0) { + filesystems.forEach((_value, _index) => { + promise = promise.then(_ => new Promise(resolve => + setTimeout(function () { + FnFileSystemSelinuxContextsSambaSet({ name: pool.name, id: pool.id }, { name: _value }) + .finally(function () { + if (_index == (filesystems.length - 1)) { + if (!display.silent) { + FnDisplayAlert({ status: "success", title: "SELinux contexts for Samba successfully configured", description: pool.name, breakword: false }, { name: "selinux-enable", id: pool.id, timeout: 4 }); + } + + process.promise.resolve(); + } + }); + + resolve(); + }, 500) + )); + }); + } else { + if (!display.silent) { + FnDisplayAlert({ status: "success", title: "SELinux contexts for Samba successfully configured", description: pool.name, breakword: false }, { name: "selinux-enable", id: pool.id, timeout: 4 }); + } + + process.promise.resolve(); + } + }) + .fail(function (message, data) { + if (!display.silent) { + FnDisplayAlert({ status: "danger", title: "SELinux contexts for Samba could not be configured", description: pool.name, breakword: false }, { name: "selinux-enable", id: pool.id, timeout: 4 }); + } + + FnConsole.warn("Storage Pools, SELinux Contexts, Samba, Set: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); + + process.promise.resolve(); + }); + + return process.promise.promise(); +} + +function FnStoragePoolSizeGet(pool = { name, id }) { + let process = { + command: ["/sbin/zpool", "get", "size", "-H", "-o", "value", "-p", pool.name] + }; + + FnConsole.log[2]("Storage Pools, Size, Get: In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function () { + FnConsole.log[2]("Storage Pools, Size, Get: Success, Pool: " + pool.name); + }) + .fail(function (message, data) { + FnConsole.warn("Storage Pools, Size. Get: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); + }); +} + +function FnStoragePoolSpinnerHide(pool = { name, id }) { + if ($("#tr-storagepool-" + pool.id).attr("data-pool-refresh-filesystems") == "true" && $("#tr-storagepool-" + pool.id).attr("data-pool-refresh-snapshots") == "true" && $("#tr-storagepool-" + pool.id).attr("data-pool-refresh-status") == "true") { + setTimeout(function () { + $("#spinner-storagepool-" + pool.id).addClass("hidden"); + $("#listingcthead-storagepool-" + pool.id).removeClass("hidden"); + $("#listingctbody-storagepool-" + pool.id).removeClass("hidden"); + }, 200); + } +} + +function FnStoragePoolTrimCancel(pool = { name, id }, disk = { id }) { + let process = { + command: ["/sbin/zpool", "trim", "-c", pool.name] + }; + + if (disk.id) { + process.command.push(disk.id); + } + + FnConsole.log[2]("Storage Pools, " + (disk.id ? "Disk, " : "") + "TRIM, Cancel: In Progress, Pool: " + pool.name + (disk.id ? ", Disk: " + disk.id : "")); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: (disk.id ? "Disk" : "Storage Pool") + " TRIM successfully cancelled", description: (disk.id ? disk.id : pool.name), breakword: false }, { name: "storagepool-" + (disk.id ? "disk-" : "") + "trim-cancel", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, " + (disk.id ? "Disk, " : "") + "TRIM, Cancel: Success, Pool: " + pool.name + (disk.id ? ", Disk: " + disk.id : "")); + }) + .fail(function (message, data) { + FnDisplayAlert({ status: "danger", title: (disk.id ? "Disk" : "Storage Pool") + " TRIM could not be cancelled", description: (disk.id ? disk.id : pool.name), breakword: false }, { name: "storagepool-" + (disk.id ? "disk-" : "") + "trim-cancel", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, " + (disk.id ? "Disk, " : "") + "TRIM, Cancel: Failed, Pool: " + pool.name + (disk.id ? ", Disk: " + disk.id : "") + ", Message: " + (data ? data : message)); + }) + .finally(function () { + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); + }, 200); + }); +} + +function FnStoragePoolTrimStart(pool = { name, id }, disk = { id }, trim = { resume: false, secure: false }, modal = { name, id }) { + let process = { + command: ["/sbin/zpool", "trim", pool.name] + }; + + if (trim.secure) { + process.command.splice(2, 0, "-d"); + } + if (disk.id) { + process.command.push(disk.id); + } + + FnConsole.log[2]("Storage Pools, " + (disk.id ? "Disk, " : "") + "TRIM, " + (trim.resume ? "Resume" : "Start") + ": In Progress, Pool: " + pool.name + (disk.id ? ", Disk: " + disk.id : "")); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + if (!trim.resume) { + $("#spinner-" + modal.name + "-" + modal.id + " span").text("Starting " + (disk.id ? "disk" : "storage pool") + " TRIM..."); + } + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: (disk.id ? "Disk" : "Storage Pool") + " TRIM successfully " + (trim.resume ? "resumed" : "started"), description: (disk.id ? disk.id : pool.name), breakword: false }, { name: "storagepool-" + (disk.id ? "disk-" : "") + "trim-start", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, " + (disk.id ? "Disk, " : "") + "TRIM, " + (trim.resume ? "Resume" : "Start") + ": Success, Pool: " + pool.name + (disk.id ? ", Disk: " + disk.id : "")); + }) + .fail(function (message, data) { + FnDisplayAlert({ status: "danger", title: (disk.id ? "Disk" : "Storage Pool") + " TRIM could not be " + (trim.resume ? "resumed" : "started"), description: (disk.id ? disk.id : pool.name), breakword: false }, { name: "storagepool-" + (disk.id ? "disk-" : "") + "trim-start", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, " + (disk.id ? "Disk, " : "") + "TRIM, " + (trim.resume ? "Resume" : "Start") + ": Failed, Pool: " + pool.name + (disk.id ? ", Disk: " + disk.id : "") + ", Message: " + (data ? data : message)); + }) + .finally(function () { + if (modal.name && modal.id) { + $("#modal-" + modal.name + "-" + modal.id).modal("hide"); + } + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); + }, 200); + }); +} + +function FnStoragePoolTrimSuspend(pool = { name, id }, disk = { id }) { + let process = { + command: ["/sbin/zpool", "trim", "-s", pool.name] + }; + + if (disk.id) { + process.command.push(disk.id); + } + + FnConsole.log[2]("Storage Pools, " + (disk.id ? "Disk, " : "") + "TRIM, Suspend: In Progress, Pool: " + pool.name + (disk.id ? ", Disk: " + disk.id : "")); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: (disk.id ? "Disk" : "Storage Pool") + " TRIM successfully suspended", description: (disk.id ? disk.id : pool.name), breakword: false }, { name: "storagepool-" + (disk.id ? "disk-" : "") + "trim-suspend", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, " + (disk.id ? "Disk, " : "") + "TRIM, Suspend: Success, Pool: " + pool.name + (disk.id ? ", Disk: " + disk.id : "")); + }) + .fail(function (message, data) { + FnDisplayAlert({ status: "danger", title: (disk.id ? "Disk" : "Storage Pool") + " TRIM could not be suspended", description: (disk.id ? disk.id : pool.name), breakword: false }, { name: "storagepool-" + (disk.id ? "disk-" : "") + "trim-suspend", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, " + (disk.id ? "Disk, " : "") + "TRIM, Suspend: Failed, Pool: " + pool.name + (disk.id ? ", Disk: " + disk.id : "") + ", Message: " + (data ? data : message)); + }) + .finally(function () { + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); + }, 200); + }); +} + +function FnStoragePoolUpgrade(pool = { name, id }, modal = { name, id }) { + let process = { + command: ["/sbin/zpool", "upgrade", pool.name] + }; + + FnConsole.log[1]("Storage Pools, Upgrade: In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-" + modal.name + "-" + modal.id + " span").text("Upgrading storage pool..."); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function (data, message) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Storage Pools, Upgrade:" })); + + if (/Successfully upgraded|Enabled the following features/gi.test(data)) { + FnDisplayAlert({ status: "success", title: "Storage Pool successfully upgraded", description: pool.name, breakword: false }, { name: "storagepool-upgrade", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, Upgrade: Success, Pool: " + pool.name); + } else { + FnStoragePoolUpgradeFail({ name: pool.name, id: pool.id }, { data: data, message: message }); + } + }) + .fail(function (message, data) { + FnStoragePoolUpgradeFail({ name: pool.name, id: pool.id }, { data: data, message: message }); + }) + .finally(function () { + $("#modal-" + modal.name + "-" + modal.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true , snapshots: true, status: true }); + }, 200); + });; +} + +function FnStoragePoolUpgradeFail(pool = { name, id }, process = { data, message }) { + FnDisplayAlert({ status: "danger", title: "Storage Pool could not be upgraded", description: pool.name, breakword: false }, { name: "storagepool-upgrade", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, Upgrade: Failed, Pool: " + pool.name + ", Message: " + (process.data ? process.data : process.message)); +} + +function FnStoragePoolVirtualDeviceAdd(pool = { name, id, force: false, virtualdevice }, disks = { id: [] }, modal = { name, id }) { + let process = { + command: ["/sbin/zpool", "add", pool.name] + }; + + modal.hide = true; + + if (pool.force) { + process.command.splice(2, 0, "-f"); + } + if (pool.virtualdevice) { + if (pool.virtualdevice == "dedup mirror") { + process.command.push("dedup"); + process.command.push("mirror"); + } else if (pool.virtualdevice == "log mirror") { + process.command.push("log"); + process.command.push("mirror"); + } else if (pool.virtualdevice == "special mirror") { + process.command.push("special"); + process.command.push("mirror"); + } else { + process.command.push(pool.virtualdevice); + } + } + + disks.id.forEach(_value => _value && process.command.push(_value)); + + FnConsole.log[1]("Storage Pools, Virtual Device, Add: In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-" + modal.name + "-" + modal.id + " span").text("Adding virtual device..."); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "Virtual Device successfully added to Storage Pool", description: pool.name, breakword: false }, { name: "storagepool-virtualdevice-add", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, Virtual Device, Add: Success, Pool: " + pool.name); + }) + .fail(function (message, data) { + if (/contains devices of different sizes/gi.test(data)) { + modal.hide = false; + + $("#validationwrapper-" + modal.name + "-disks-" + modal.id).addClass("has-error"); + $("#helpblock-" + modal.name + "-disks-" + modal.id).addClass("has-error").removeClass("hidden").text("Disks are of different sizes. Forcefully add virtual device to override."); + } else if (/mismatched replication level/gi.test(data)) { + modal.hide = false; + + $("#validationwrapper-" + modal.name + "-disks-" + modal.id).addClass("has-error"); + $("#helpblock-" + modal.name + "-disks-" + modal.id).addClass("has-error").removeClass("hidden").text("Mismatched replication level. Forcefully add virtual device to override."); + } + + if (!modal.hide) { + $("#spinner-" + modal.name + "-" + modal.id).addClass("hidden"); + $("#btn-" + modal.name + "-apply-" + modal.id).prop("disabled", false); + + $("[id^=btn-storagepool-status-dropdown-][id$=" + pool.id + "]").removeClass("disabled"); + $("#spinner-storagepool-status-" + modal.id).addClass("hidden"); + } + + if (modal.hide) { + FnDisplayAlert({ status: "danger", title: "Virtual Device could not be added to Storage Pool", description: pool.name, breakword: false }, { name: "storagepool-virtualdevice-add", id: pool.id, timeout: 4 }); + } + + FnConsole.warn("Storage Pools, Virtual Device, Add: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); + }) + .finally(function () { + if (modal.hide) { + $("#modal-" + modal.name + "-" + modal.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: true }); + }, 200); + } + }); +} + +function FnStoragePoolVirtualDeviceClear(pool = { name, id }, virtualdevice = { id }, modal = { name, id }) { + let process = { + command: ["/sbin/zpool", "clear", pool.name, virtualdevice.id] + }; + + FnConsole.log[2]("Storage Pools, Virtual Device, Clear Errors: In Progress, Pool: " + pool.name + ", Virtual Device: " + virtualdevice.id); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-" + modal.name + "-" + modal.id + " span").text("Clearing virtual device errors..."); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "Virtual Device errors successfully cleared", description: virtualdevice.id, breakword: false }, { name: "storagepool-virtualdevice-clear", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, Virtual Device, Clear Errors: Success, Pool: " + pool.name + ", Virtual Device: " + virtualdevice.id); + }) + .fail(function (message, data) { + FnDisplayAlert({ status: "danger", title: "Virtual Device errors could not be cleared", description: virtualdevice.id, breakword: false }, { name: "storagepool-virtualdevice-clear", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, Virtual Device, Clear Errors: Failed, Pool: " + pool.name + ", Virtual Device: " + virtualdevice.id + ", Message: " + (data ? data : message)); + }) + .finally(function () { + $("#modal-" + modal.name + "-" + modal.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: false, snapshots: false, status: true }); + }, 200); + }); +} + +function FnStoragePoolVirtualDeviceRemove(pool = { name, id }, virtualdevice = { id, labelclear: false }, modal = { name, id }) { + let process = { + command: ["/sbin/zpool", "remove", pool.name, virtualdevice.id] + }; + + modal.hide = true; + + FnConsole.log[1]("Storage Pools, Virtual Device, Remove: In Progress, Pool: " + pool.name + ", Virtual Device: " + virtualdevice.id); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-" + modal.name + "-" + modal.id + " span").text("Removing virtual device..."); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "Virtual Device successfully removed from Storage Pool", description: pool.name, breakword: false }, { name: "storagepool-virtualdevice-remove", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Storage Pools, Virtual Device, Remove: Success, Pool: " + pool.name + ", Virtual Device: " + virtualdevice.id); + + if (virtualdevice.labelclear) { + modal.hide = false; + + $("#spinner-" + modal.name + "-" + modal.id + " span").text("Clearing disk label..."); + + setTimeout(function () { + FnStoragePoolDiskLabelClear({ name: pool.name, id: pool.id }, { id: virtualdevice.id, inactive: true }, { silent: false }) + .finally(function () { + $("#modal-" + modal.name + "-" + modal.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: true }); + }, 200); + }); + }, 2000); + } + }) + .fail(function (message, data) { + FnDisplayAlert({ status: "danger", title: "Virtual Device could not be removed from Storage Pool", description: pool.name, breakword: false }, { name: "storagepool-virtualdevice-remove", id: pool.id, timeout: 4 }); + + FnConsole.warn("Storage Pools, Virtual Device, Remove: Failed, Pool: " + pool.name + ", Virtual Device: " + virtualdevice.id + ", Message: " + (data ? data : message)); + }) + .finally(function () { + if (modal.hide) { + $("#modal-" + modal.name + "-" + modal.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: true }); + }, 200); + } + }); +} + +//#endregion + +//#region File Systems + +function FnFileSystemsGet(pool = { name, id }) { + let process = { + command: ["/sbin/zfs", "list", "-H", "-o", "readonly,name,avail,used,usedsnap,usedrefreserv,recordsize,compression,dedup,sharenfs,sharesmb,mountpoint,mounted,origin,encryption,encryptionroot,keyformat,keystatus", "-r", "-p", pool.name] + }; + let filesystems = { + empty: true + }; + + pool.altroot = (($("#tr-storagepool-" + pool.id).attr("data-pool-altroot") == "true") ? true : false); + pool.boot = (($("#tr-storagepool-" + pool.id).attr("data-pool-boot") == "true") ? true : false); + pool.readonly = (($("#tr-storagepool-" + pool.id).attr("data-pool-readonly") == "true") ? true : false); + pool.feature = { + allocation_classes: (($("#tr-storagepool-" + pool.id).attr("data-pool-feature-allocation_classes") == "true") ? true : false), + edonr: (($("#tr-storagepool-" + pool.id).attr("data-pool-feature-edonr") == "true") ? true : false), + encryption: (($("#tr-storagepool-" + pool.id).attr("data-pool-feature-encryption") == "true") ? true : false), + large_blocks: (($("#tr-storagepool-" + pool.id).attr("data-pool-feature-large_blocks") == "true") ? true : false), + large_dnode: (($("#tr-storagepool-" + pool.id).attr("data-pool-feature-large_dnode") == "true") ? true : false), + lz4_compress: (($("#tr-storagepool-" + pool.id).attr("data-pool-feature-lz4_compress") == "true") ? true : false), + sha512: (($("#tr-storagepool-" + pool.id).attr("data-pool-feature-sha512") == "true") ? true : false), + skein: (($("#tr-storagepool-" + pool.id).attr("data-pool-feature-skein") == "true") ? true : false) + }; + + FnConsole.log[2]("File Systems, Get: In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data, message) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Get:" })); + + if (data) { + filesystems.empty = false; + + FnStoragePoolSizeGet({ name: pool.name, id: pool.id }) + .done(function (_data) { + FnConsole.log[4](FnConsoleVerbose({ data: _data, message: "Storage Pools, Size, Get:" })); + + if (_data) { + pool.sizeraw = _data.replace(/\n+/g, ""); + + FnFileSystemsGetCommand({ name: pool.name, id: pool.id, altroot: pool.altroot, boot: pool.boot, feature: { allocation_classes: pool.feature.allocation_classes, edonr: pool.feature.edonr, encryption: pool.feature.encryption, large_blocks: pool.feature.large_blocks, large_dnode: pool.feature.large_dnode, lz4_compress: pool.feature.lz4_compress, sha512: pool.feature.sha512, skein: pool.feature.skein }, readonly: pool.readonly, sizeraw: pool.sizeraw }, { data: data, message: message }); + } + }) + .fail(function () { + FnFileSystemsGetCommand({ name: pool.name, id: pool.id, altroot: pool.altroot, boot: pool.boot, feature: { allocation_classes: pool.feature.allocation_classes, edonr: pool.feature.edonr, encryption: pool.feature.encryption, large_blocks: pool.feature.large_blocks, large_dnode: pool.feature.large_dnode, lz4_compress: pool.feature.lz4_compress, sha512: pool.feature.sha512, skein: pool.feature.skein }, readonly: pool.readonly, sizeraw: null }, { data: data, message: message }); + }); + } + + FnConsole.log[1]("File Systems, Get: Success, Pool: " + pool.name); + }) + .fail(function (message, data) { + FnConsole.warn("File Systems, Get: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); + }) + .finally(function () { + if (filesystems.empty) { + $("#tbody-storagepool-filesystems-" + pool.id).empty(); + $("#tbody-storagepool-filesystems-" + pool.id).append(`No file systems found.`); + $("#modals-storagepool-filesystems-" + pool.id).remove(); + $("#modals-storagepool-filesystem-" + pool.id).remove(); + $("#modals").append(`
    `); + + //Register file systems modals + if (!pool.readonly) { + FnModalFileSystemsCreate({ name: pool.name, id: pool.id, altroot: pool.altroot, feature: { allocation_classes: pool.feature.allocation_classes, edonr: pool.feature.edonr, encryption: pool.feature.encryption, large_blocks: pool.feature.large_blocks, large_dnode: pool.feature.large_dnode, lz4_compress: pool.feature.lz4_compress, sha512: pool.feature.sha512, skein: pool.feature.skein } }); + } + + $("#tr-storagepool-" + pool.id).attr("data-pool-refresh-filesystems", "true"); + + $("#spinner-storagepool-filesystems-" + pool.id).addClass("hidden"); + $("#paneltitle-storagepool-filesystems-" + pool.id).removeClass("hidden").text(FnDateTime()); + $("#btn-storagepool-filesystems-create-" + pool.id).prop("disabled", false); + $("#btn-storagepool-filesystems-refresh-" + pool.id).prop("disabled", false); + } + + FnStoragePoolSpinnerHide({ name: pool.name, id: pool.id }); + FnCockpitElementsUpdate(); + }); +} + +function FnFileSystemsGetCommand(pool = { name, id, altroot: false, boot: false, feature: { allocation_classes: true, edonr: true, encryption: true, large_blocks: true, large_dnode: true, lz4_compress: true, sha512: true, skein: true }, readonly: false, sizeraw: 0 }, process = { data, message }) { + let filesystems = process.data.split(/\n/g).filter(v => v); + + $("#tbody-storagepool-filesystems-" + pool.id).empty(); + $("#modals-storagepool-filesystems-" + pool.id).remove(); + $("#modals-storagepool-filesystem-" + pool.id).remove(); + $("#modals").append(`
    `); + $("#modals").append(`
    `); + + filesystems.forEach((_value, _index) => { + let filesystem = { + properties: _value.split(/\t/g).filter(v => v), + clone: false, + compression: "", + dedup: "", + encryption: false, + encryptionroot: "", + id: "", + keyformat: "", + keystatus: "", + mounted: false, + mountpoint: "", + name: "", + origin: "", + readonly: false, + recordsize: "", + shares: [], + sharenfs: false, + sharesmb: false, + type: "File System", + actionsmenu: { + register: { + samba: {}, + snapshot: {} + } + } + }; + + filesystem.output = ``; + + filesystem.properties.forEach((__value, __index) => { + //0=readonly, 1=name, 2=avail, 3=used, 4=usedsnap, 5=usedrefreserv, 6=recordsize, 7=compression, 8=dedup, 9=sharenfs, 10=sharesmb, 11=mountpoint, 12=mounted, 13=origin, 14=encryption, 15=encryptionroot, 16=keyformat, 17=keystatus + + switch (__index) { + case 0: //0=readonly + if (__value.toLowerCase() == "on" || pool.boot && zfsmanager.configuration.zfs.storagepool.bootlockdown) { + filesystem.readonly = true; + } + + break; + case 1: //1=name + filesystem.name = __value; + filesystem.id = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: filesystem.name, attribute: true }); + + filesystem.output += `Name:` + __value + (filesystem.readonly ? ` ` : ``) + ``; + + break; + case 2: //2=avail + filesystem.output += `Available:` + FnFormatBytes({ base2: true, decimals: 2, value: __value }) + ``; + + break; + case 3: //3=used + filesystem.output += `Used:` + FnFormatBytes({ base2: true, decimals: 2, value: __value }) + ``; + + break; + case 4: //4=usedsnap + filesystem.output += `Snapshots:` + FnFormatBytes({ base2: true, decimals: 2, value: __value }) + ``; + + break; + case 5: //5=usedrefreserv + if (pool.sizeraw) { + filesystem.usedrefreservpercent = FnRound({ decimals: 1, value: (__value / pool.sizeraw) * 100 }); + + __value = FnFormatBytes({ base2: true, decimals: 2, value: __value }); + + if ($.isNumeric(filesystem.usedrefreservpercent) && filesystem.usedrefreservpercent > 0) { + __value += " (" + filesystem.usedrefreservpercent + " %)"; + } + } else { + __value = FnFormatBytes({ base2: true, decimals: 2, value: __value }); + } + + filesystem.output += `Refreservation:` + __value + ``; + + break; + case 6: //6=recordsize + filesystem.recordsize = __value; + + filesystem.output += `Record Size:` + FnFormatBytes({ base2: true, decimals: 0, value: __value }) + ``; + + break; + case 7: //7=compression + filesystem.compression = __value; + + if (/off|on/gi.test(__value)) { + __value = __value.charAt(0).toUpperCase() + __value.slice(1); + } else { + __value = __value.toUpperCase(); + } + + filesystem.output += `Compression:` + __value + ``; + + break; + case 8: //8=dedup + filesystem.dedup = __value; + + if (/sha256|sha512/gi.test(__value)) { + __value = __value.replace(/sha/gi, "SHA-"); + } + if (/off|on|verify|skein/gi.test(__value)) { + __value = __value.charAt(0).toUpperCase() + __value.slice(1); + } + if (/edonr/gi.test(__value)) { + __value = __value.replace(/edonr/gi, "Edon-R"); + } + + filesystem.output += `Deduplication:` + __value.replace(/,verify/g, " + Verify") + ``; + + break; + case 9: //9=sharenfs + filesystem.sharenfs = __value; + + if (__value.toLowerCase() != "off" && __value.toLowerCase() != "-") { + filesystem.sharenfs = true; + filesystem.shares.push("NFS"); + } else { + filesystem.sharenfs = false; + } + + break; + case 10: //10=sharesmb + filesystem.sharesmb = __value; + + if (__value.toLowerCase() == "on") { + filesystem.sharesmb = true; + filesystem.shares.push("SMB"); + } else { + filesystem.sharesmb = false; + } + + if (/off|on/gi.test(__value)) { + __value = __value.charAt(0).toUpperCase() + __value.slice(1); + } else { + __value = __value.toUpperCase(); + } + + filesystem.output += `Share:` + (filesystem.shares.length > 0 ? filesystem.shares.join(" + ") : "Off") + ``; + + break; + case 11: //11=mountpoint + filesystem.mountpoint = __value; + break; + case 12: //12=mounted + if (__value.toLowerCase() == "yes") { + filesystem.mounted = true; + } else { + filesystem.mounted = false; + } + + if (/yes|no/gi.test(__value)) { + __value = __value.charAt(0).toUpperCase() + __value.slice(1); + } + + filesystem.output += `Mounted:` + __value + ``; + + break; + case 13: //13=origin + if (__value != "-") { + filesystem.origin = __value; + filesystem.clone = true; + filesystem.type = "Clone File System"; + } else { + filesystem.clone = false; + filesystem.type = "File System"; + } + + break; + case 14: //14=encryption + if (__value.toLowerCase() != "off") { + filesystem.encryption = true; + } else { + filesystem.encryption = false; + } + + break; + case 15: //15=encryptionroot + filesystem.encryptionroot = __value; + + break; + case 16: //16=keyformat + if (filesystem.encryption && __value.toLowerCase() == "passphrase") { + filesystem.keyformat = "passphrase"; + } + + break; + case 17: //17=keystatus + if (__value != "-") { + filesystem.keystatus = __value; + } else { + filesystem.keystatus = ""; + } + + break; + } + + //Add icons and actions menu at end of array + if (__index >= (filesystem.properties.length - 1)) { + filesystem.icons = { + clone: ``, + keystatus: { + locked: ``, + unlocked: `` + } + }; + + filesystem.output += `Clone:` + (filesystem.clone ? `Yes` + filesystem.icons.clone : `No`) + ``; + filesystem.output += `Encrypted:` + (/available|unavailable/.test(filesystem.keystatus) ? `Yes` : `No`) + ``; + + if (filesystem.keystatus == "unavailable") { + filesystem.output += filesystem.icons.keystatus.locked; + } else if (filesystem.keystatus == "available") { + filesystem.output += filesystem.icons.keystatus.unlocked; + } + + filesystem.output += ``; + + //Actions menu + filesystem.actionsmenu.items = { + itemconfigure: [], + itemconfiguredivider: function () { + if (this.itemconfigure.length > 0 && this.item.length > 0) { + this.itemconfigure.push(this.divider); + } + }, + item: [], + itemdivider: function () { + if (this.item.length > 0 && this.itemencrypted.length > 0) { + this.item.push(this.divider); + } + }, + itemencrypted: [], + itemencrypteddivider: function () { + if ((this.item.length > 0 || this.itemencrypted.length > 0) && (this.itemsamba.length > 0 || this.itemsnapshot.length > 0)) { + this.itemencrypted.push(this.divider); + } + }, + itemsamba: [], + itemsambadivider: function () { + if ((this.item.length > 0 || this.itemencrypted.length > 0) && this.itemsamba.length > 0 && this.itemsnapshot.length > 0) { + this.itemsamba.push(this.divider); + } + }, + itemsnapshot: [], + divider: `` + }; + filesystem.actionsmenu.display = function () { + if (/@/g.test(filesystem.name) == false && (this.items.itemconfigure.length + this.items.item.length + this.items.itemencrypted.length + this.items.itemsamba.length + this.items.itemsnapshot.length) > 0) { + this.items.itemconfiguredivider(); + this.items.itemdivider(); + this.items.itemencrypteddivider(); + this.items.itemsambadivider(); + + return this.header + this.items.itemconfigure.join("\n") + this.items.item.join("\n") + this.items.itemencrypted.join("\n") + this.items.itemsamba.join("\n") + this.items.itemsnapshot.join("\n") + this.footer; + } else { + return ""; + } + }; + filesystem.actionsmenu.header = ` + + `; + + //Configure File System + filesystem.actionsmenu.items.itemconfigure.push(`
  • Configure ` + filesystem.type + `
  • `); + + //Rename File System + if (!pool.readonly && (!filesystem.readonly || filesystem.readonly && !zfsmanager.configuration.zfs.filesystem.readonlylockdown) && filesystem.name != pool.name) { + filesystem.actionsmenu.items.item.push(`
  • Rename ` + filesystem.type + `
  • `); + + filesystem.actionsmenu.register.rename = true; + } + + //Promote Clone File System + if (!pool.readonly && (!filesystem.readonly || filesystem.readonly && !zfsmanager.configuration.zfs.filesystem.readonlylockdown) && filesystem.clone && filesystem.origin.replace(/^(.*)\@.*$/, "$1") != pool.name) { + filesystem.actionsmenu.items.item.push(`
  • Promote ` + filesystem.type + `
  • `); + + filesystem.actionsmenu.register.promote = true; + } + + //Mount File System / Unmount File System + if (!pool.boot || pool.boot && !zfsmanager.configuration.zfs.storagepool.bootlockdown) { + if (!filesystem.mounted && filesystem.keystatus != "unavailable") { + filesystem.actionsmenu.items.item.push(`
  • Mount ` + filesystem.type + `
  • `); + + filesystem.actionsmenu.register.mount = true; + } else if (filesystem.mounted) { + filesystem.actionsmenu.items.item.push(`
  • Unmount ` + filesystem.type + `
  • `); + + filesystem.actionsmenu.register.unmount = true; + } + } + + //Unlock File System / Lock File System + if (filesystem.keystatus == "unavailable" && !filesystem.clone && filesystem.encryptionroot == filesystem.name) { + filesystem.actionsmenu.items.item.push(`
  • Unlock File System
  • `); + + filesystem.actionsmenu.register.unlock = true; + } else if (filesystem.keystatus == "available" && !filesystem.mounted && !filesystem.clone && filesystem.encryptionroot == filesystem.name) { + filesystem.actionsmenu.items.item.push(`
  • Lock File System
  • `); + + filesystem.actionsmenu.register.lock = true; + } + + //Change Passphrase + if (!pool.readonly && (!filesystem.readonly || filesystem.readonly && !zfsmanager.configuration.zfs.filesystem.readonlylockdown) && filesystem.keystatus == "available" && !filesystem.clone && filesystem.encryptionroot == filesystem.name) { + filesystem.actionsmenu.items.itemencrypted.push(`
  • Change Passphrase
  • `); + + filesystem.actionsmenu.register.changepassphrase = true; + } + + //Destroy File System + if (!pool.readonly && (!filesystem.readonly || filesystem.readonly && !zfsmanager.configuration.zfs.filesystem.readonlylockdown) && filesystem.name != pool.name) { + if (!filesystem.clone || filesystem.clone && new RegExp("^" + filesystem.name + "/").test(filesystem.origin.replace(/^(.*)\@.*$/, "$1")) == false) { //Do not display if clone origin is a child file system - will generate recursive dependency error + filesystem.actionsmenu.items.item.push(`
  • Destroy ` + filesystem.type + `
  • `); + + filesystem.actionsmenu.register.destroy = true; + } + } + + //Enable Samba Share + if (!pool.readonly && (!filesystem.readonly || filesystem.readonly && !zfsmanager.configuration.zfs.filesystem.readonlylockdown) && !filesystem.sharesmb && zfsmanager.configuration.samba.manage) { + filesystem.actionsmenu.items.itemsamba.push(`
  • Enable Samba Share
  • `); + + filesystem.actionsmenu.register.samba.enable = true; + } + + //Configure Samba Share + if (filesystem.sharesmb && zfsmanager.configuration.samba.manage) { + filesystem.actionsmenu.items.itemsamba.push(`
  • Configure Samba Share
  • `); + + filesystem.actionsmenu.register.samba.configure = true; + } + + //Disable Samba Share + if (!pool.readonly && (!filesystem.readonly || filesystem.readonly && !zfsmanager.configuration.zfs.filesystem.readonlylockdown) && filesystem.sharesmb && zfsmanager.configuration.samba.manage) { + filesystem.actionsmenu.items.itemsamba.push(`
  • Disable Samba Share
  • `); + + filesystem.actionsmenu.register.samba.disable = true; + } + + //Create Snapshot + if (!pool.readonly && zfsmanager.configuration.zfs.filesystem.snapshotactions) { + filesystem.actionsmenu.items.itemsnapshot.push(`
  • Create Snapshot
  • `); + + filesystem.actionsmenu.register.snapshot.create = true; + } + + filesystem.output += `` + filesystem.actionsmenu.display() + ``; + } + }); + + filesystem.output += ``; + + $("#tbody-storagepool-filesystems-" + pool.id).append(filesystem.output); + + //Register file system modals + FnModalFileSystemConfigure({ name: pool.name, id: pool.id, altroot: pool.altroot, feature: { allocation_classes: pool.feature.allocation_classes, edonr: pool.feature.edonr, large_blocks: pool.feature.large_blocks, large_dnode: pool.feature.large_dnode, lz4_compress: pool.feature.lz4_compress, sha512: pool.feature.sha512, skein: pool.feature.skein }, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, origin: filesystem.origin, type: filesystem.type }); + if (filesystem.actionsmenu.register.changepassphrase) { + FnModalFileSystemChangePassphrase({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }); + } + if (filesystem.actionsmenu.register.destroy) { + FnModalFileSystemDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, sharesmb: filesystem.sharesmb, type: filesystem.type }); + } + if (filesystem.actionsmenu.register.lock) { + FnModalFileSystemLock({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, type: filesystem.type }); + } + if (filesystem.actionsmenu.register.mount) { + FnModalFileSystemMount({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, sharesmb: filesystem.sharesmb, type: filesystem.type }); + } + if (filesystem.actionsmenu.register.promote) { + FnModalFileSystemPromote({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, origin: filesystem.origin, type: filesystem.type }); + } + if (filesystem.actionsmenu.register.rename) { + FnModalFileSystemRename({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: filesystem.name, id: filesystem.id, clone: filesystem.clone, encryption: filesystem.encryption, encryptionroot: filesystem.encryptionroot, origin: filesystem.origin, sharesmb: filesystem.sharesmb, type: filesystem.type }); + } + if (filesystem.actionsmenu.register.samba.configure) { + FnModalFileSystemSambaConfigure({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, mountpoint: filesystem.mountpoint }); + } + if (filesystem.actionsmenu.register.samba.disable) { + FnModalFileSystemSambaDisable({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, type: filesystem.type }); + } + if (filesystem.actionsmenu.register.samba.enable) { + FnModalFileSystemSambaEnable({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, mounted: filesystem.mounted, mountpoint: filesystem.mountpoint }); + } + if (filesystem.actionsmenu.register.snapshot.create) { + FnModalFileSystemSnapshotCreate({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }); + } + if (filesystem.actionsmenu.register.unlock) { + FnModalFileSystemUnlock({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, sharesmb: filesystem.sharesmb, type: filesystem.type }); + } + if (filesystem.actionsmenu.register.unmount) { + FnModalFileSystemUnmount({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, encryptionroot: filesystem.encryptionroot, keystatus: filesystem.keystatus, sharesmb: filesystem.sharesmb, type: filesystem.type }); + } + }); + + //Register file systems modals + if (!pool.readonly) { + FnModalFileSystemsCreate({ name: pool.name, id: pool.id, altroot: pool.altroot, feature: { allocation_classes: pool.feature.allocation_classes, edonr: pool.feature.edonr, encryption: pool.feature.encryption, large_blocks: pool.feature.large_blocks, large_dnode: pool.feature.large_dnode, lz4_compress: pool.feature.lz4_compress, sha512: pool.feature.sha512, skein: pool.feature.skein } }); + } + + $("#tr-storagepool-" + pool.id).attr("data-pool-refresh-filesystems", "true"); + + $("#spinner-storagepool-filesystems-" + pool.id).addClass("hidden"); + $("#paneltitle-storagepool-filesystems-" + pool.id).removeClass("hidden").html(FnDateTime() + (zfsmanager.configuration.zfs.storagepool.count ? ` ` + filesystems.length + `` : ``)); + $("#btn-storagepool-filesystems-create-" + pool.id).prop("disabled", false); + $("#btn-storagepool-filesystems-refresh-" + pool.id).prop("disabled", false); + + FnStoragePoolSpinnerHide({ name: pool.name, id: pool.id }); + FnCockpitElementsUpdate(); +} + +function FnFileSystemsLockedGet() { + let filesystems = { + id: [] + }; + let process = { + command: ["/sbin/zfs", "list", "-H", "-o", "name,encryption,encryptionroot,keyformat,keystatus", "-r", "-t", "filesystem"] + }; + + $("#listgroup-storagepools-filesystems-unlock-filesystems").empty().append(`
  • `); + + FnConsole.log[2]("File Systems, Locked, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Locked, Get:" })); + + filesystems.id = data.split(/\n/g).filter(v => { + if (!zfsmanager.configuration.zfs.storagepool.boot && zfsmanager.zfs.storagepool.boot && new RegExp("^" + zfsmanager.zfs.storagepool.boot + "\t|^" + zfsmanager.zfs.storagepool.boot + "/").test(v)) { + //Do not display boot + } else if (!zfsmanager.configuration.zfs.storagepool.root && zfsmanager.zfs.storagepool.root && new RegExp("^" + zfsmanager.zfs.storagepool.root + "\t|^" + zfsmanager.zfs.storagepool.root + "/").test(v)) { + //Do not display root + } else { + return v; + } + }); + + filesystems.id.forEach((_value, _index) => { + let filesystem = { + properties: _value.split(/\t/g).filter(v => v) + }; + + filesystem.name = filesystem.properties[0]; + filesystem.encryption = filesystem.properties[1]; + filesystem.encryptionroot = filesystem.properties[2]; + filesystem.keyformat = filesystem.properties[3]; + filesystem.keystatus = filesystem.properties[4]; + + if (filesystem.encryptionroot == filesystem.name && filesystem.keyformat == "passphrase" && filesystem.keystatus == "unavailable") { + filesystems.output = ` + + `; + + $("#listgroup-storagepools-filesystems-unlock-filesystems").append(filesystems.output); + } + }); + + setTimeout(function () { + $("#spinner-storagepools-filesystems-unlock-filesystems").remove(); + $("#listgroup-storagepools-filesystems-unlock-filesystems > li").removeClass("hidden"); + if ($("#helpblock-storagepools-filesystems-unlock-filesystems-warning").text()) { + $("#helpblock-storagepools-filesystems-unlock-filesystems-warning").removeClass("hidden"); + } + + if ($("#listgroup-storagepools-filesystems-unlock-filesystems > li").length == 0) { + filesystems.output = ` +
  • + +
  • + `; + + $("#listgroup-storagepools-filesystems-unlock-filesystems").append(filesystems.output); + } + }, 200); + + FnConsole.log[1]("File Systems, Locked, Get: Success"); + }) + .fail(function (message, data) { + $("#spinner-storagepools-filesystems-unlock-filesystems").remove(); + $("#listgroup-storagepools-filesystems-unlock-filesystems > li").removeClass("hidden"); + + if ($("#listgroup-storagepools-filesystems-unlock-filesystems > li").length == 0) { + filesystems.output = ` +
  • + +
  • + `; + + $("#listgroup-storagepools-filesystems-unlock-filesystems").append(filesystems.output); + } + + FnConsole.warn("File Systems, Locked, Get: Failed, Message: " + (data ? data : message)); + }); +} + +function FnFileSystemsMountedGet(pool = { name, id }, filesystem = { name, id }, modal = { alert: { id, mount: true } }) { + let process = { + command: ["/sbin/zfs", "list", "-H", "-o", "name,mounted", "-r", "-t", "filesystem", filesystem.name] + }; + + filesystem.children = { + mounted: false + } + + FnConsole.log[2]("File Systems, Mounted, Get: In Progress: Success, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Mounted, Get:" })); + + let filesystems = data.split(/\n/g).filter((v, i) => v && i > 0); + + filesystems.forEach((_value, _index) => { + filesystem.properties = _value.split(/\t/g).filter(v => v); + + if (filesystem.properties[1] == "yes" && !filesystem.children.mount) { + filesystem.children.mounted = true; + } + }); + + if (filesystem.children.mounted) { + modal.alert.id.html(FnDisplayInlineAlert({ status: "warning", title: "There are child file systems currently mounted. " + (modal.alert.mount ? "Mounting" : "Unmounting") + " this file system may adversely affect the child file systems.", description: null }, { name: null, id: null, hidden: false })); + } + + FnConsole.log[1]("File Systems, Mounted, Get: Success, Pool: " + pool.name); + }) + .fail(function (message, data) { + FnConsole.warn("File Systems, Mounted, Get: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); + }); +} + +function FnFileSystemsNamesGet(pool = { name, id }, filesystem = { existing: { name, clone: false, encryption: false, encryptionroot, origin }, override: false }, modal = { dropdown: { id, selected } }) { + let process = { + command: ["/sbin/zfs", "list", "-H", "-o", "name,encryption,encryptionroot,keystatus", "-r", "-t", "filesystem", pool.name] + }; + + FnConsole.log[2]("File Systems, Names, Get: In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Names, Get:" })); + + let filesystems = data.split(/\n/g).filter(v => v); + + modal.dropdown.items = []; + + modal.dropdown.id.empty(); + + filesystems.forEach((_value, _index) => { + filesystem.properties = _value.split(/\t/g).filter(v => v); + filesystem.name = filesystem.properties[0]; + filesystem.encryption = (filesystem.properties[1].toLowerCase() != "off" ? true : false); + filesystem.encryptionroot = (filesystem.properties[2] && filesystem.properties[2] != "-" ? filesystem.properties[2] : ""); + filesystem.encryptionstatus = ""; + filesystem.existing.regexp = { + name: new RegExp("^" + filesystem.existing.name + "/", "g") + }; + filesystem.keystatus = filesystem.properties[3].toLowerCase(); + + if (filesystem.encryption && /^available$|^unavailable$/.test(filesystem.keystatus)) { + filesystem.encryptionstatus = `` + } + + modal.dropdown.add = false; + modal.dropdown.item = `
  • ` + filesystem.name + filesystem.encryptionstatus + `
  • `; + + if ((filesystem.override || filesystem.existing.encryption) && filesystem.existing.clone) { //Encrypted clone file systems can only move within origin and child file systems + filesystem.existing.regexp.origin = new RegExp("^" + filesystem.existing.origin.replace(/^(.*)\@.*$/, "$1\/"), "g"); + + if (filesystem.name == filesystem.existing.origin.replace(/^(.*)\@.*$/, "$1")) { //Origin file system + modal.dropdown.add = true; + } else if (filesystem.name == filesystem.existing.name.replace(/\/[^\/]+$/, "")) { //File System parent + modal.dropdown.add = true; + } else if (filesystem.name != filesystem.existing.name && filesystem.existing.regexp.origin.test(filesystem.name) && !filesystem.existing.regexp.name.test(filesystem.name)) { //Origin child file systems + modal.dropdown.add = true; + } + } else if (filesystem.override || filesystem.existing.encryption) { //Encrypted file systems that are their own encryption root can move anywhere, child file system of the encryption root can only move within encryption root and its child file systems + if (filesystem.name != filesystem.existing.name && !filesystem.existing.regexp.name.test(filesystem.name)) { + if (filesystem.existing.name == filesystem.existing.encryptionroot) { //File system is its own encryption root + modal.dropdown.add = true; + } else if (filesystem.encryptionroot == filesystem.existing.encryptionroot) { //File system is a child of the encryption root + modal.dropdown.add = true; + } + } + } else { //Unencrypted file systems can only move to unencrypted file systems + if (!filesystem.encryption && filesystem.name != filesystem.existing.name && !filesystem.existing.regexp.name.test(filesystem.name)) { + modal.dropdown.add = true; + } + } + + if (modal.dropdown.add) { + modal.dropdown.items.push(modal.dropdown.item); + } + }); + + modal.dropdown.id.append(modal.dropdown.items.join("\n")); + + FnConsole.log[1]("File Systems, Names, Get: Success, Pool: " + pool.name); + }) + .fail(function (message, data) { + FnConsole.warn("File Systems, Names, Get: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); + }); +} + +function FnFileSystemsUnlock(filesystems = { id: [] }, filesystem = { mount: true, overlay: true, passphrase }, modal = { name, id }) { + let promise = Promise.resolve(); + + filesystems.count = { + available: 0, + error: 0, + success: 0 + }; + + $("#listgroup-" + modal.name + modal.id + "-filesystems > li.list-group-item > label > span.pficon").removeClass("list-group-ct-warning"); + + if (filesystems.id.length > 0) { + FnConsole.log[2]("File Systems, Unlock: In Progress"); + + $("#spinner-" + modal.name + modal.id + " span").text("Unlocking file system" + (filesystems.id.length > 1 ? "s" : "") + "..."); + + filesystems.id.forEach((_value, _index) => { + promise = promise.then(_ => new Promise(resolve => + setTimeout(function () { + let pool = { + name: _value.replace(/\/.*$/, ""), + id: FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: _value.replace(/\/.*$/, ""), attribute: true }) + }; + + filesystem.name = _value; + filesystem.id = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: _value, attribute: true }); + + FnFileSystemUnlock({ name: pool.name, id: pool.id, altroot: false, readonly: false }, { name: filesystem.name, id: filesystem.id, mount: filesystem.mount, overlay: filesystem.overlay, passphrase: filesystem.passphrase, type: "File System" }, { enable: false }, { name: modal.name, id: modal.id }, { refresh: false }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Unlock:" })); + + if (/error|Incorrect key/i.test(data)) { + filesystems.count.error++; + + $("#listgroup-" + modal.name + modal.id + "-filesystems > li.list-group-item[data-filesystem-name='" + filesystem.name + "'] > label > span.pficon").addClass("list-group-ct-warning"); + } else { + filesystems.count.success++; + + $("#listgroup-" + modal.name + modal.id + "-filesystems > li.list-group-item[data-filesystem-name='" + filesystem.name + "']").remove(); + } + }) + .fail(function (message, data) { + if (/Key already loaded/i.test(data)) { + filesystems.count.success++; + + $("#listgroup-" + modal.name + modal.id + "-filesystems > li.list-group-item[data-filesystem-name='" + filesystem.name + "']").remove(); + } else { + filesystems.count.error++; + + $("#listgroup-" + modal.name + modal.id + "-filesystems > li.list-group-item[data-filesystem-name='" + filesystem.name + "'] > label > span.pficon").addClass("list-group-ct-warning"); + } + }) + .finally(function () { + if (_index == (filesystems.id.length - 1)) { + $("#listgroup-storagepools-filesystems-unlock-filesystems input[name='checkbox-storagepools-filesystems-unlock-filesystems']").map(function () { + filesystems.count.available++; + }); + + if (filesystems.count.error == 0) { + FnConsole.log[1]("File Systems, Unlock: Success"); + } else { + FnConsole.warn("File Systems, Unlock: Failed"); + } + + if (filesystems.count.available == 0) { + $("#modal-" + modal.name + modal.id).modal("hide"); + } else { + $("#spinner-" + modal.name + modal.id).addClass("hidden"); + $("#spinner-" + modal.name + modal.id + " span").text(""); + $("#btn-" + modal.name + "-apply" + modal.id).prop("disabled", false); + } + + setTimeout(function () { + FnStoragePoolsGet(); + }, 1000); + } + }); + + resolve(); + }, 1000) + )); + }); + } else { + $("#modal-" + modal.name + modal.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolsGet(); + }, 1000); + } +} + +//#endregion + +//#region File System + +function FnFileSystemChangePassphrase(pool = { name, id }, filesystem = { name, id, passphrase }) { + let process = { + command: [] + }; + + if (!filesystem.passphrase || filesystem.passphrase.length < 8) { + FnFileSystemChangePassphraseFail({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }, { data: "Passphrase requires a minimum of 8 characters.", message: null }); + return; + } + + //Escape percentage and single quote special character for printf + if (/\%/g.test(filesystem.passphrase)) { + filesystem.passphrase = filesystem.passphrase.replace(/\%/g, "\%\%"); + } + if (/\'/g.test(filesystem.passphrase)) { + filesystem.passphrase = filesystem.passphrase.replace(/\'/g, "\'\"\'\"\'"); + } + + process.command = ["/bin/sh", "-c", "printf '" + filesystem.passphrase + "' | /sbin/zfs change-key \"" + filesystem.name + "\""]; + + FnConsole.log[2]("File Systems, Change Passphrase: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-storagepool-filesystem-changepassphrase-" + filesystem.id + " span").text("Changing passphrase..."); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function (data, message) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Change Passphrase:" })); + + if (/error|Key must be loaded/i.test(data)) { + FnFileSystemChangePassphraseFail({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }, { data: data, message: message }); + return; + } + + FnDisplayAlert({ status: "success", title: "File System passphrase successfully changed", description: filesystem.name, breakword: false }, { name: "filesystem-changepassphrase", id: filesystem.id, timeout: 4 }); + + FnConsole.log[1]("File Systems, Change Passphrase: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + + $("#modal-storagepool-filesystem-changepassphrase-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + }) + .fail(function (message, data) { + FnFileSystemChangePassphraseFail({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }, { data: data, message: message }); + }); +} + +function FnFileSystemChangePassphraseFail(pool = { name, id }, filesystem = { name, id }, process = { data, message }) { + let modal = { + hide: true + }; + + if (/Passphrase requires a minimum of 8 characters./i.test(process.data)) { + modal.hide = false; + + $("#validationwrapper-storagepool-filesystem-changepassphrase-passphrase-" + filesystem.id).addClass("has-error"); + $("#helpblock-storagepool-filesystem-changepassphrase-passphrase-" + filesystem.id).addClass("has-error").removeClass("hidden").text("Passphrase requires a minimum of 8 characters."); + $("#input-storagepool-filesystem-changepassphrase-passphrase-" + filesystem.id).focus(); + } else if (/Key must be loaded/i.test(process.data)) { + modal.hide = false; + + $("#validationwrapper-storagepool-filesystem-changepassphrase-filesystem-" + filesystem.id).addClass("has-error"); + $("#helpblock-storagepool-filesystem-changepassphrase-filesystem-" + filesystem.id).addClass("has-error").removeClass("hidden").text("File System is locked."); + $("#input-storagepool-filesystem-changepassphrase-filesystem-" + filesystem.id).focus(); + } else if (/encryption failure/i.test(process.data)) { //Error message when pool is read only + modal.hide = true; + } else if (/error/i.test(process.data)) { + modal.hide = false; + + $("#validationwrapper-storagepool-filesystem-changepassphrase-passphrase-" + filesystem.id).addClass("has-error"); + $("#helpblock-storagepool-filesystem-changepassphrase-passphrase-" + filesystem.id).addClass("has-error").removeClass("hidden").text("Passphrase is incorrect."); + $("#input-storagepool-filesystem-changepassphrase-passphrase-" + filesystem.id).focus(); + } + + if (!modal.hide) { + $("#spinner-storagepool-filesystem-changepassphrase-" + filesystem.id).addClass("hidden"); + $("#spinner-storagepool-filesystem-changepassphrase-" + filesystem.id + " span").text(""); + $("#btn-storagepool-filesystem-changepassphrase-apply-" + filesystem.id).prop("disabled", false); + } + + FnConsole.warn("File Systems, Change Passphrase: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (process.data ? process.data : process.message)); + + if (modal.hide) { + FnDisplayAlert({ status: "danger", title: "File System passphrase could not be changed", description: filesystem.name, breakword: false }, { name: "filesystem-changepassphrase", id: filesystem.id, timeout: 4 }); + + $("#modal-storagepool-filesystem-changepassphrase-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + } +} + +function FnFileSystemChildDatasetsGet(pool = { name, id }, filesystem = { name, id, clones: true }, modal = { name, id }) { + let process = { + command: ["/sbin/zfs", "list", "-H", "-o", "name,clones", "-r", "-t", "filesystem,snapshot", filesystem.name] + }; + + FnConsole.log[2]("File Systems, Child, Datasets, Get: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Child, Datasets, Get:" })); + + data = data.split(/\n/g).filter(v => v); + + let filesystems = { + id: [] + }; + let snapshots = { + id: [] + }; + + if (data.length > 0) { + data.forEach((_value, _index) => { + let dataset = { + properties: _value.split(/\t/g).filter(v => v) + }; + + dataset.name = dataset.properties[0]; + dataset.clones = (dataset.properties[1] ? dataset.properties[1] : ""); + + if (new RegExp("^" + filesystem.name + ".*@").test(dataset.name)) { + snapshots.id.push(dataset.name); + + if (dataset.clones && filesystem.clones) { + dataset.clones = dataset.clones.split(",").filter(v => v); + + dataset.clones.forEach((_value, _index) => { + filesystems.id.push(_value); + }); + } + + } else if (new RegExp("^" + filesystem.name + ".*@").test(dataset.name) == false) { + filesystems.id.push(dataset.name); + } + }); + } + + filesystems.id.sort(); + snapshots.id.sort(); + + FnConsole.log[1]("File Systems, Child, Datasets, Get: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + + FnFileSystemChildFileSystemsGet({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }, { id: filesystems.id }, { name: modal.name, id: modal.id }); + FnFileSystemChildSnapshotsGet({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }, { id: filesystems.id }, { name: modal.name, id: modal.id }); + }) + .fail(function (message, data) { + FnConsole.warn("File Systems, Child, Datasets, Get: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); + }); +} + +function FnFileSystemChildFileSystemsGet(pool = { name, id }, filesystem = { name, id }, filesystems = { id: [] }, modal = { name, id }) { + let process = { + command: ["/sbin/zfs", "list", "-H", "-o", "name", "-r", "-t", "filesystem"] + }; + + filesystems.id.forEach(_value => _value && process.command.push(_value)); + + FnConsole.log[2]("File Systems, Child, File Systems, Get: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Child, File Systems, Get:" })); + + let filesystems = { + id: data.split(/\n/g).filter(v => v), + count: { + filesystems: 0, + filesystemswithclones: 0 + } + }; + + if (filesystems.id.length > 0) { + filesystems.id.forEach((_value, _index) => { + if (new RegExp("^" + filesystem.name + "/").test(_value)) { + filesystems.count.filesystems++; + + $("#ul-" + modal.name + "-child-filesystems-" + modal.id).append("
  • " + _value + "
  • \n"); + } + + if (_value != filesystem.name) { + filesystems.count.filesystemswithclones++; + + $("#ul-" + modal.name + "-child-filesystemswithclones-" + modal.id).append("
  • " + _value + "
  • \n"); + } + }); + + $("#panelgroup-" + modal.name + "-" + modal.id).attr("data-filesystem-child-filesystems", filesystems.count.filesystems); + $("#panelgroup-" + modal.name + "-" + modal.id).attr("data-filesystem-child-filesystemswithclones", filesystems.count.filesystemswithclones); + } + + FnConsole.log[1]("File Systems, Child, File Systems, Get: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + }) + .fail(function (message, data) { + FnConsole.warn("File Systems, Child, File Systems, Get: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); + }); +} + +function FnFileSystemChildSnapshotsGet(pool = { name, id }, filesystem = { name, id }, snapshots = { id: [] }, modal = { name, id }) { + let process = { + command: ["/sbin/zfs", "list", "-H", "-o", "name", "-r", "-t", "snapshot"] + }; + + snapshots.id.forEach(_value => _value && process.command.push(_value)); + + FnConsole.log[2]("File Systems, Child, Snapshots, Get: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Child, Snapshots, Get:" })); + + let snapshots = { + id: data.split(/\n/g).filter(v => v), + count: { + snapshots: 0, + snapshotswithclones: 0 + } + }; + + if (snapshots.id.length > 0) { + snapshots.id.forEach((_value, _index) => { + if (new RegExp("^" + filesystem.name + ".*@").test(_value)) { + snapshots.count.snapshots++; + + $("#ul-" + modal.name + "-child-snapshots-" + modal.id).append("
  • " + _value + "
  • \n"); + } + + snapshots.count.snapshotswithclones++; + + $("#ul-" + modal.name + "-child-snapshotswithclones-" + modal.id).append("
  • " + _value + "
  • \n"); + }); + + $("#panelgroup-" + modal.name + "-" + modal.id).attr("data-filesystem-child-snapshots", snapshots.count.snapshots); + $("#panelgroup-" + modal.name + "-" + modal.id).attr("data-filesystem-child-snapshotswithclones", snapshots.count.snapshotswithclones); + } + + FnConsole.log[1]("File Systems, Child, Snapshots, Get: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + }) + .fail(function (message, data) { + FnConsole.warn("File Systems, Child, Snapshots, Get: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); + }); +} + +function FnFileSystemConfigurationGet(pool = { name, id, readonly: false }, filesystem = { name, id }, modal = { name, id }) { + let process = { + command: ["/sbin/zfs", "get", "readonly,aclinherit,acltype,atime,available,canmount,casesensitivity,checksum,compression,context,dedup,dnodesize,defcontext,encryption,encryptionroot,fscontext,guid,mountpoint,quota,recordsize,refreservation,rootcontext,sharenfs,sharesmb,special_small_blocks,used,xattr", "-H", "-o", "property,value,source", "-p", filesystem.name] + }; + + if (!zfsmanager.user.admin) { + pool.readonly = true; + } + + filesystem.available = ""; + filesystem.context = false; + filesystem.fscontext = false; + filesystem.defcontext = false; + filesystem.readonly = false; + filesystem.rootcontext = false; + + FnConsole.log[2]("File Systems, Configuration, Get: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Configuration, Get:" })); + + process.data = data.replace(/\t+/g, "\u22C5").split(/\n/g).filter(v => v); + + process.data.forEach((_value, _index) => { + _value = _value.split("\u22C5"); + + filesystem.properties = { + property: _value[0].toLowerCase(), + value: _value[1].toLowerCase(), + valueraw: _value[1], + source: _value[2] + }; + + let size = {}; + + switch (filesystem.properties.property) { + case "aclinherit": //Default is restricted + filesystem.property = { + value: "Restricted", + valueinherited: "" + }; + + switch (filesystem.properties.value) { + case "discard": + filesystem.property.value = "Discard"; + break; + case "noallow": + filesystem.property.value = "No Allow"; + break; + case "restricted": + filesystem.property.value = "Restricted"; + break; + case "passthrough": + filesystem.property.value = "Passthrough"; + break; + case "passthrough-x": + filesystem.property.value = "Passthrough-X"; + break; + default: + filesystem.property.value = "Restricted"; + break; + } + + if (/^inherited/gi.test(filesystem.properties.source)) { + filesystem.property.source = "inherited"; + filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; + + $("#dropdown-" + modal.name + "-aclinherit-" + modal.id + " li[value='Inherited']").removeClass("hidden"); + $("#dropdown-" + modal.name + "-aclinherit-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); + } else if (/^default|^local/gi.test(filesystem.properties.source)) { + $("#dropdown-" + modal.name + "-aclinherit-" + modal.id + " li[value='InheritedReset']").removeClass("hidden"); + + if (/^default/gi.test(filesystem.properties.source)) { + filesystem.property.source = "default"; + filesystem.property.valueinherited = "Default (Restricted)"; + + $("#dropdown-" + modal.name + "-aclinherit-" + modal.id + " li[value='InheritedReset'] a").text(filesystem.property.valueinherited); + } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name == pool.name) { + filesystem.property.source = "local"; + + $("#dropdown-" + modal.name + "-aclinherit-" + modal.id + " li[value='InheritedReset'] a").text("Default (Restricted)"); + } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name != pool.name) { + filesystem.property.source = "local"; + + FnFileSystemConfigurationInheritedPropertyGet({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, property: "aclinherit" }, { name: modal.name, id: modal.id }); + } + } + + $("#btnspan-" + modal.name + "-aclinherit-" + modal.id).text((filesystem.property.valueinherited ? filesystem.property.valueinherited : filesystem.property.value)).attr("data-field-value", filesystem.properties.valueraw).attr("data-field-source", filesystem.property.source); + $("#dropdown-" + modal.name + "-aclinherit-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-aclinherit-" + modal.id + " li[value='" + (filesystem.property.valueinherited ? (filesystem.property.source == "inherited" ? "Inherited" : "InheritedReset") : filesystem.properties.valueraw) + "']").addClass("active"); + + if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { + $("#div-" + modal.name + "-aclinherit-dropdown-" + modal.id + " button").prop("disabled", true); + } + + break; + case "acltype": //Default is off + filesystem.property = { + value: "Off", + valueinherited: "" + }; + + switch (filesystem.properties.value) { + case "off": + filesystem.property.value = "Off"; + break; + case "noacl": + filesystem.property.value = "No ACL"; + break; + case "posixacl": + filesystem.property.value = "POSIX ACL"; + break; + default: + filesystem.property.value = "Off"; + break; + } + + if (/^inherited/gi.test(filesystem.properties.source)) { + filesystem.property.source = "inherited"; + filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; + + $("#dropdown-" + modal.name + "-acltype-" + modal.id + " li[value='Inherited']").removeClass("hidden"); + $("#dropdown-" + modal.name + "-acltype-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); + } else if (/^default|^local/gi.test(filesystem.properties.source)) { + $("#dropdown-" + modal.name + "-acltype-" + modal.id + " li[value='InheritedReset']").removeClass("hidden"); + + if (/^default/gi.test(filesystem.properties.source)) { + filesystem.property.source = "default"; + filesystem.property.valueinherited = "Default (Off)"; + + $("#dropdown-" + modal.name + "-acltype-" + modal.id + " li[value='InheritedReset'] a").text(filesystem.property.valueinherited); + } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name == pool.name) { + filesystem.property.source = "local"; + + $("#dropdown-" + modal.name + "-acltype-" + modal.id + " li[value='InheritedReset'] a").text("Default (Off)"); + } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name != pool.name) { + filesystem.property.source = "local"; + + FnFileSystemConfigurationInheritedPropertyGet({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, property: "acltype" }, { name: modal.name, id: modal.id }); + } + } + + $("#btnspan-" + modal.name + "-acltype-" + modal.id).text((filesystem.property.valueinherited ? filesystem.property.valueinherited : filesystem.property.value)).attr("data-field-value", filesystem.properties.valueraw).attr("data-field-source", filesystem.property.source); + $("#dropdown-" + modal.name + "-acltype-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-acltype-" + modal.id + " li[value='" + (filesystem.property.valueinherited ? (filesystem.property.source == "inherited" ? "Inherited" : "InheritedReset") : filesystem.properties.valueraw) + "']").addClass("active"); + + if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { + $("#div-" + modal.name + "-acltype-dropdown-" + modal.id + " button").prop("disabled", true); + } + break; + case "atime": //Default is on + filesystem.property = { + source: "", + value: "On", + valueinherited: "" + }; + + switch (filesystem.properties.value) { + case "off": + filesystem.property.value = "Off"; + break; + case "on": + filesystem.property.value = "On"; + break; + default: + filesystem.property.value = "On"; + break; + } + + if (/^inherited/gi.test(filesystem.properties.source)) { + filesystem.property.source = "inherited"; + filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; + + $("#dropdown-" + modal.name + "-atime-" + modal.id + " li[value='Inherited']").removeClass("hidden"); + $("#dropdown-" + modal.name + "-atime-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); + } else if (/^default|^local/gi.test(filesystem.properties.source)) { + $("#dropdown-" + modal.name + "-atime-" + modal.id + " li[value='InheritedReset']").removeClass("hidden"); + + if (/^default/gi.test(filesystem.properties.source)) { + filesystem.property.source = "default"; + filesystem.property.valueinherited = "Default (On)"; + + $("#dropdown-" + modal.name + "-atime-" + modal.id + " li[value='InheritedReset'] a").text(filesystem.property.valueinherited); + } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name == pool.name) { + filesystem.property.source = "local"; + + $("#dropdown-" + modal.name + "-atime-" + modal.id + " li[value='InheritedReset'] a").text("Default (On)"); + } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name != pool.name) { + filesystem.property.source = "local"; + + FnFileSystemConfigurationInheritedPropertyGet({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, property: "atime" }, { name: modal.name, id: modal.id }); + } + } + + $("#btnspan-" + modal.name + "-atime-" + modal.id).text((filesystem.property.valueinherited ? filesystem.property.valueinherited : filesystem.property.value)).attr("data-field-value", filesystem.properties.valueraw).attr("data-field-source", filesystem.property.source); + $("#dropdown-" + modal.name + "-atime-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-atime-" + modal.id + " li[value='" + (filesystem.property.valueinherited ? (filesystem.property.source == "inherited" ? "Inherited" : "InheritedReset") : filesystem.properties.valueraw) + "']").addClass("active"); + + if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { + $("#div-" + modal.name + "-atime-dropdown-" + modal.id + " button").prop("disabled", true); + } + break; + case "available": + filesystem.available = filesystem.properties.value; + + filesystem.property = { + value: "0 B" + }; + + if (filesystem.properties.value == "none" || filesystem.properties.value == "0" || filesystem.properties.value == "0b") { + filesystem.property.value = "0 B"; + } else { + filesystem.property.value = FnFormatBytes({ base2: true, decimals: 2, value: filesystem.properties.value }); + } + + $("#helpblock-" + modal.name + "-available-" + modal.id).text("Available size: " + filesystem.property.value); + break; + case "canmount": //Default is on + filesystem.property = { + value: "On" + }; + + switch (filesystem.properties.value) { + case "on": + filesystem.property.value = "On"; + break; + case "off": + filesystem.property.value = "Off"; + break; + case "noauto": + filesystem.property.value = "No Auto"; + break; + default: + filesystem.property.value = "On"; + break; + } + + $("#btnspan-" + modal.name + "-canmount-" + modal.id).text(filesystem.property.value).attr("data-field-value", filesystem.properties.value); + $("#dropdown-" + modal.name + "-canmount-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-canmount-" + modal.id + " li[value='" + filesystem.properties.valueraw + "']").addClass("active"); + + if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { + $("#div-" + modal.name + "-canmount-dropdown-" + modal.id + " button").prop("disabled", true); + } + break; + case "casesensitivity": //Default is sensitive + $("#div-" + modal.name + "-casesensitivity-" + modal.id).text(filesystem.properties.value.charAt(0).toUpperCase() + filesystem.properties.value.slice(1)); + break; + case "checksum": //Default is on + filesystem.property = { + value: "On", + valueinherited: "" + }; + + switch (filesystem.properties.value) { + case "on": + filesystem.property.value = "On"; + break; + case "off": + filesystem.property.value = "Off"; + break; + case "edonr": + filesystem.property.value = "Edon-R"; + break; + case "fletcher2": + filesystem.property.value = "Fletcher2"; + break; + case "fletcher4": + filesystem.property.value = "Fletcher4"; + break; + case "noparity": + filesystem.property.value = "No Parity"; + break; + case "sha256": + filesystem.property.value = "SHA-256"; + break; + case "sha512": + filesystem.property.value = "SHA-512"; + break; + case "skein": + filesystem.property.value = "Skein"; + break; + default: + filesystem.property.value = "On"; + break; + } + + if (/^inherited/gi.test(filesystem.properties.source)) { + filesystem.property.source = "inherited"; + filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; + + $("#dropdown-" + modal.name + "-checksum-" + modal.id + " li[value='Inherited']").removeClass("hidden"); + $("#dropdown-" + modal.name + "-checksum-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); + } else if (/^default|^local/gi.test(filesystem.properties.source)) { + $("#dropdown-" + modal.name + "-checksum-" + modal.id + " li[value='InheritedReset']").removeClass("hidden"); + + if (/^default/gi.test(filesystem.properties.source)) { + filesystem.property.source = "default"; + filesystem.property.valueinherited = "Default (On)"; + + $("#dropdown-" + modal.name + "-checksum-" + modal.id + " li[value='InheritedReset'] a").text(filesystem.property.valueinherited); + } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name == pool.name) { + filesystem.property.source = "local"; + + $("#dropdown-" + modal.name + "-checksum-" + modal.id + " li[value='InheritedReset'] a").text("Default (On)"); + } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name != pool.name) { + filesystem.property.source = "local"; + + FnFileSystemConfigurationInheritedPropertyGet({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, property: "checksum" }, { name: modal.name, id: modal.id }); + } + } + + $("#btnspan-" + modal.name + "-checksum-" + modal.id).text((filesystem.property.valueinherited ? filesystem.property.valueinherited : filesystem.property.value)).attr("data-field-value", filesystem.properties.valueraw).attr("data-field-source", filesystem.property.source); + $("#dropdown-" + modal.name + "-checksum-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-checksum-" + modal.id + " li[value='" + (filesystem.property.valueinherited ? (filesystem.property.source == "inherited" ? "Inherited" : "InheritedReset") : filesystem.properties.valueraw) + "']").addClass("active"); + + if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { + $("#div-" + modal.name + "-checksum-dropdown-" + modal.id + " button").prop("disabled", true); + } + break; + case "compression": //Default is off + filesystem.property = { + value: "Off", + valueinherited: "" + }; + + switch (filesystem.properties.value) { + case "on": + filesystem.property.value = "On"; + break; + case "gzip": + filesystem.property.value = "GZIP"; + break; + case "lz4": + filesystem.property.value = "LZ4"; + break; + case "lzjb": + filesystem.property.value = "LZJB"; + break; + case "zle": + filesystem.property.value = "ZLE"; + break; + default: + filesystem.property.value = "Off"; + break; + } + + if (/^inherited/gi.test(filesystem.properties.source)) { + filesystem.property.source = "inherited"; + filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; + + $("#dropdown-" + modal.name + "-compression-" + modal.id + " li[value='Inherited']").removeClass("hidden"); + $("#dropdown-" + modal.name + "-compression-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); + } else if (/^default|^local/gi.test(filesystem.properties.source)) { + $("#dropdown-" + modal.name + "-compression-" + modal.id + " li[value='InheritedReset']").removeClass("hidden"); + + if (/^default/gi.test(filesystem.properties.source)) { + filesystem.property.source = "default"; + filesystem.property.valueinherited = "Default (Off)"; + + $("#dropdown-" + modal.name + "-compression-" + modal.id + " li[value='InheritedReset'] a").text(filesystem.property.valueinherited); + } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name == pool.name) { + filesystem.property.source = "local"; + + $("#dropdown-" + modal.name + "-compression-" + modal.id + " li[value='InheritedReset'] a").text("Default (Off)"); + } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name != pool.name) { + filesystem.property.source = "local"; + + FnFileSystemConfigurationInheritedPropertyGet({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, property: "compression" }, { name: modal.name, id: modal.id }); + } + } + + $("#btnspan-" + modal.name + "-compression-" + modal.id).text((filesystem.property.valueinherited ? filesystem.property.valueinherited : filesystem.property.value)).attr("data-field-value", filesystem.properties.valueraw).attr("data-field-source", filesystem.property.source); + $("#dropdown-" + modal.name + "-compression-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-compression-" + modal.id + " li[value='" + (filesystem.property.valueinherited ? (filesystem.property.source == "inherited" ? "Inherited" : "InheritedReset") : filesystem.properties.valueraw) + "']").addClass("active"); + + if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { + $("#div-" + modal.name + "-compression-dropdown-" + modal.id + " button").prop("disabled", true); + } + break; + case "context": //Default is empty + if (filesystem.properties.value == "system_u:object_r:samba_share_t:s0") { + filesystem.context = true; + } + break; + case "dedup": //Default is off + filesystem.property = { + value: "Off", + valueinherited: "" + }; + + switch (filesystem.properties.value) { + case "on": + filesystem.property.value = "On"; + break; + case "off": + filesystem.property.value = "Off"; + break; + case "edonr,verify": + filesystem.property.value = "Edon-R + Verify"; + break; + case "sha256": + filesystem.property.value = "SHA-256"; + break; + case "sha256,verify": + filesystem.property.value = "SHA-256 + Verify"; + break; + case "sha512": + filesystem.property.value = "SHA-512"; + break; + case "sha512,verify": + filesystem.property.value = "SHA-512 + Verify"; + break; + case "skein": + filesystem.property.value = "Skein"; + break; + case "skein,verify": + filesystem.property.value = "Skein + Verify"; + break; + case "verify": + filesystem.property.value = "Verify"; + break; + default: + filesystem.property.value = "Off"; + break; + } + + if (/^inherited/gi.test(filesystem.properties.source)) { + filesystem.property.source = "inherited"; + filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; + + $("#dropdown-" + modal.name + "-dedup-" + modal.id + " li[value='Inherited']").removeClass("hidden"); + $("#dropdown-" + modal.name + "-dedup-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); + } else if (/^default|^local/gi.test(filesystem.properties.source)) { + $("#dropdown-" + modal.name + "-dedup-" + modal.id + " li[value='InheritedReset']").removeClass("hidden"); + + if (/^default/gi.test(filesystem.properties.source)) { + filesystem.property.source = "default"; + filesystem.property.valueinherited = "Default (Off)"; + + $("#dropdown-" + modal.name + "-dedup-" + modal.id + " li[value='InheritedReset'] a").text(filesystem.property.valueinherited); + } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name == pool.name) { + filesystem.property.source = "local"; + + $("#dropdown-" + modal.name + "-dedup-" + modal.id + " li[value='InheritedReset'] a").text("Default (Off)"); + } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name != pool.name) { + filesystem.property.source = "local"; + + FnFileSystemConfigurationInheritedPropertyGet({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, property: "dedup" }, { name: modal.name, id: modal.id }); + } + } + + $("#btnspan-" + modal.name + "-dedup-" + modal.id).text((filesystem.property.valueinherited ? filesystem.property.valueinherited : filesystem.property.value)).attr("data-field-value", filesystem.properties.valueraw).attr("data-field-source", filesystem.property.source); + $("#dropdown-" + modal.name + "-dedup-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-dedup-" + modal.id + " li[value='" + (filesystem.property.valueinherited ? (filesystem.property.source == "inherited" ? "Inherited" : "InheritedReset") : filesystem.properties.valueraw) + "']").addClass("active"); + + if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { + $("#div-" + modal.name + "-dedup-dropdown-" + modal.id + " button").prop("disabled", true); + } + break; + case "dnodesize": //Default is legacy + filesystem.property = { + value: "Off", + valueinherited: "" + }; + + switch (filesystem.properties.value) { + case "1k": + filesystem.property.value = "1 KiB"; + break; + case "2k": + filesystem.property.value = "2 KiB"; + break; + case "4k": + filesystem.property.value = "4 KiB"; + break; + case "8k": + filesystem.property.value = "8 KiB"; + break; + case "16k": + filesystem.property.value = "16 KiB"; + break; + case "auto": + filesystem.property.value = "Auto"; + break; + case "legacy": + filesystem.property.value = "Legacy"; + break; + default: + filesystem.property.value = "Legacy"; + break; + } + + if (/^inherited/gi.test(filesystem.properties.source)) { + filesystem.property.source = "inherited"; + filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; + + $("#dropdown-" + modal.name + "-dnodesize-" + modal.id + " li[value='Inherited']").removeClass("hidden"); + $("#dropdown-" + modal.name + "-dnodesize-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); + } else if (/^default|^local/gi.test(filesystem.properties.source)) { + $("#dropdown-" + modal.name + "-dnodesize-" + modal.id + " li[value='InheritedReset']").removeClass("hidden"); + + if (/^default/gi.test(filesystem.properties.source)) { + filesystem.property.source = "default"; + filesystem.property.valueinherited = "Default (Legacy)"; + + $("#dropdown-" + modal.name + "-dnodesize-" + modal.id + " li[value='InheritedReset'] a").text(filesystem.property.valueinherited); + } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name == pool.name) { + filesystem.property.source = "local"; + + $("#dropdown-" + modal.name + "-dnodesize-" + modal.id + " li[value='InheritedReset'] a").text("Default (Legacy)"); + } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name != pool.name) { + filesystem.property.source = "local"; + + FnFileSystemConfigurationInheritedPropertyGet({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, property: "dnodesize" }, { name: modal.name, id: modal.id }); + } + } + + $("#btnspan-" + modal.name + "-dnodesize-" + modal.id).text((filesystem.property.valueinherited ? filesystem.property.valueinherited : filesystem.property.value)).attr("data-field-value", filesystem.properties.valueraw).attr("data-field-source", filesystem.property.source); + $("#dropdown-" + modal.name + "-dnodesize-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-dnodesize-" + modal.id + " li[value='" + (filesystem.property.valueinherited ? (filesystem.property.source == "inherited" ? "Inherited" : "InheritedReset") : filesystem.properties.valueraw) + "']").addClass("active"); + + if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { + $("#div-" + modal.name + "-dnodesize-dropdown-" + modal.id + " button").prop("disabled", true); + } + break; + case "defcontext": //Default is empty + if (filesystem.properties.value == "system_u:object_r:samba_share_t:s0") { + filesystem.defcontext = true; + } + break; + case "encryption": //Default is off + filesystem.property = { + value: "Off" + }; + + switch (filesystem.properties.value) { + case "on": + filesystem.property.value = "On"; + break; + case "off": + filesystem.property.value = "Off"; + break; + case "aes-128-ccm": + filesystem.property.value = "AES-128-CCM"; + break; + case "aes-192-ccm": + filesystem.property.value = "AES-192-CCM"; + break; + case "aes-256-ccm": + filesystem.property.value = "AES-256-CCM"; + break; + case "aes-128-gcm": + filesystem.property.value = "AES-128-GCM"; + break; + case "aes-192-gcm": + filesystem.property.value = "AES-192-GCM"; + break; + case "aes-256-gcm": + filesystem.property.value = "AES-256-GCM"; + break; + default: + filesystem.property.value = "Off"; + break; + } + + $("#div-" + modal.name + "-encryption-" + modal.id).text(filesystem.property.value); + + if (filesystem.property.value != "Off") { + $("#controllabel-" + modal.name + "-encryption-" + modal.id).removeClass("hidden"); + $("#div-" + modal.name + "-encryption-" + modal.id).removeClass("hidden"); + } + break; + case "encryptionroot": + if (filesystem.properties.valueraw && filesystem.properties.valueraw == "-") { + filesystem.properties.valueraw = ""; + } + + if (filesystem.properties.valueraw && filesystem.properties.valueraw != filesystem.name) { + $("#controllabel-" + modal.name + "-encryptionroot-" + modal.id).removeClass("hidden"); + $("#div-" + modal.name + "-encryptionroot-" + modal.id).text(filesystem.properties.valueraw).removeClass("hidden"); + } + break; + case "fscontext": //Default is empty + if (filesystem.properties.value == "system_u:object_r:samba_share_t:s0") { + filesystem.fscontext = true; + } + break; + case "guid": + $("#div-" + modal.name + "-guid-" + modal.id).text(filesystem.properties.value); + break; + case "mountpoint": + $("#input-" + modal.name + "-mountpoint-" + modal.id).val(filesystem.properties.valueraw).attr("data-field-value", filesystem.properties.valueraw); + + if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { + $("#input-" + modal.name + "-mountpoint-" + modal.id).prop("disabled", true); + } + break; + case "quota": //Default is none + filesystem.property = { + value: "0 B", + valueraw: "0", + valueunit: "KiB" + }; + + if (filesystem.properties.value == "none" || filesystem.properties.value == "0" || filesystem.properties.value == "0b") { + filesystem.property.value = "0 B"; + } else { + filesystem.property.value = FnFormatBytes({ base2: true, decimals: 1, value: filesystem.properties.value }); + + if (/KiB/g.test(filesystem.property.value)) { + filesystem.property.valueunit = "KiB"; + } else if (/MiB/g.test(filesystem.property.value)) { + filesystem.property.valueunit = "MiB"; + } else if (/GiB/g.test(filesystem.property.value)) { + filesystem.property.valueunit = "GiB"; + } else if (/TiB/g.test(filesystem.property.value)) { + filesystem.property.valueunit = "TiB"; + } + + filesystem.property.valueraw = filesystem.property.value.toString().replace(" " + filesystem.property.valueunit, ""); + } + + $("#input-" + modal.name + "-quota-" + modal.id).val(filesystem.property.valueraw); + + size.quota = { + quota: parseInt(filesystem.properties.value), + max: { + raw: 1099511627776000, + unit: "", + unitnumber: 0 + }, + slider: { + valuemax: 1000 + }, + property: filesystem.property + }; + + FnStoragePoolSizeGet({ name: pool.name, id: null }) + .done(function (_data) { + FnConsole.log[4](FnConsoleVerbose({ data: _data, message: "Storage Pools, Size, Get:" })); + + if (_data && zfsmanager.configuration.zfs.filesystem.quotarestrict) { + size.quota.max.raw = parseInt(_data.replace(/\n+/g, "")); + } + }) + .finally(function () { + size.quota.max.raw = (size.quota.max.raw > size.quota.quota ? size.quota.max.raw : size.quota.quota); + size.quota.max.unitnumber = FnFormatBytes({ base2: true, decimals: 2, value: size.quota.max.raw }).replace(/ .*$/g, ""); + size.quota.max.unit = FnFormatBytes({ base2: true, decimals: 2, value: size.quota.max.raw }).replace(/ /g, "").replace(/^[0-9.]/, ""); + + if (size.quota.max.raw <= 1024000) { + $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-kib", size.quota.max.unitnumber); + } + if (size.quota.max.raw > 1024000) { + $("#dropdown-" + modal.name + "-quota-" + modal.id + " li[value='MiB']").removeClass("hidden"); + + $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-kib", size.quota.slider.valuemax); + $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-mib", size.quota.max.unitnumber); + } + if (size.quota.max.raw > 1048576000) { + $("#dropdown-" + modal.name + "-quota-" + modal.id + " li[value='GiB']").removeClass("hidden"); + + $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-kib", size.quota.slider.valuemax); + $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-mib", size.quota.slider.valuemax); + $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-gib", size.quota.max.unitnumber); + } + if (size.quota.max.raw > 1073741824000) { + $("#dropdown-" + modal.name + "-quota-" + modal.id + " li[value='TiB']").removeClass("hidden"); + + $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-kib", size.quota.slider.valuemax); + $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-mib", size.quota.slider.valuemax); + $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-gib", size.quota.slider.valuemax); + $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-tib", size.quota.max.unitnumber); + } + + if (size.quota.property.valueunit == "KiB") { + size.quota.slider.valuemax = $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-kib"); + } + if (size.quota.property.valueunit == "MiB") { + size.quota.slider.valuemax = $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-mib"); + } + if (size.quota.property.valueunit == "GiB") { + size.quota.slider.valuemax = $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-gib"); + } + if (size.quota.property.valueunit == "TiB") { + size.quota.slider.valuemax = $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-tib"); + } + + $("#slider-" + modal.name + "-quota-" + modal.id).data("slider").options.max = size.quota.slider.valuemax; + $("#slider-" + modal.name + "-quota-" + modal.id).data("slider").options.step = (size.quota.slider.valuemax < 10 ? "0.1" : "1"); + $("#slider-" + modal.name + "-quota-" + modal.id).slider("setValue", size.quota.property.valueraw); + + $("#btnspan-" + modal.name + "-quota-" + modal.id).text(size.quota.property.valueunit).attr("data-field-value", size.quota.property.valueunit); + $("#dropdown-" + modal.name + "-quota-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-quota-" + modal.id + " li[value='" + size.quota.property.valueunit + "']").addClass("active"); + $("#input-" + modal.name + "-quota-" + modal.id).attr("data-field-value", size.quota.property.value.toString().replace(/ /g, "").replace(/iB$/g, "")); + }); + + if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { + $("#input-" + modal.name + "-quota-" + modal.id).prop("disabled", true); + $("#div-" + modal.name + "-quota-dropdown-" + modal.id + " button").prop("disabled", true); + $("#validationwrapper-" + modal.name + "-quota-" + modal.id + " .slider-pf .slider *").addClass("disabled"); + $("#slider-" + modal.name + "-quota-" + modal.id).slider("disable"); + } + break; + case "readonly": //Default is off + if (filesystem.properties.value == "on") { + filesystem.readonly = true; + } + + if (filesystem.properties.value == "on" && !$("#switch-" + modal.name + "-readonly-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-readonly-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-readonly-" + modal.id).attr("data-field-value", filesystem.properties.value); + + if (pool.readonly) { + $("#switch-" + modal.name + "-readonly-" + modal.id + " input").prop("disabled", true); + } + break; + case "recordsize": //Default is 128K + filesystem.property = { + value: FnFormatBytes({ base2: true, decimals: 0, value: filesystem.properties.value }), + valueinherited: "" + }; + + if (/^inherited/gi.test(filesystem.properties.source)) { + filesystem.property.source = "inherited"; + filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; + + $("#dropdown-" + modal.name + "-recordsize-" + modal.id + " li[value='Inherited']").removeClass("hidden"); + $("#dropdown-" + modal.name + "-recordsize-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); + } else if (/^default|^local/gi.test(filesystem.properties.source)) { + $("#dropdown-" + modal.name + "-recordsize-" + modal.id + " li[value='InheritedReset']").removeClass("hidden"); + + if (/^default/gi.test(filesystem.properties.source)) { + filesystem.property.source = "default"; + filesystem.property.valueinherited = "Default (128 KiB)"; + + $("#dropdown-" + modal.name + "-recordsize-" + modal.id + " li[value='InheritedReset'] a").text(filesystem.property.valueinherited); + } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name == pool.name) { + filesystem.property.source = "local"; + + $("#dropdown-" + modal.name + "-recordsize-" + modal.id + " li[value='InheritedReset'] a").text("Default (128 KiB)"); + } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name != pool.name) { + filesystem.property.source = "local"; + + FnFileSystemConfigurationInheritedPropertyGet({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, property: "recordsize" }, { name: modal.name, id: modal.id }); + } + } + + $("#btnspan-" + modal.name + "-recordsize-" + modal.id).text((filesystem.property.valueinherited ? filesystem.property.valueinherited : filesystem.property.value)).attr("data-field-value", filesystem.properties.valueraw).attr("data-field-source", filesystem.property.source); + $("#dropdown-" + modal.name + "-recordsize-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-recordsize-" + modal.id + " li[value='" + (filesystem.property.valueinherited ? (filesystem.property.source == "inherited" ? "Inherited" : "InheritedReset") : filesystem.properties.valueraw) + "']").addClass("active"); + + if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { + $("#div-" + modal.name + "-recordsize-dropdown-" + modal.id + " button").prop("disabled", true); + } + break; + case "refreservation": //Default is none / 0 + filesystem.property = { + value: "0 B", + valueraw: "0", + valueunit: "KiB" + }; + + if (filesystem.properties.value == "none" || filesystem.properties.value == "0" || filesystem.properties.value == "0b") { + filesystem.property.value = "0 B"; + } else { + filesystem.property.value = FnFormatBytes({ base2: true, decimals: 1, value: filesystem.properties.value }); + + if (/KiB/g.test(filesystem.property.value)) { + filesystem.property.valueunit = "KiB"; + } else if (/MiB/g.test(filesystem.property.value)) { + filesystem.property.valueunit = "MiB"; + } else if (/GiB/g.test(filesystem.property.value)) { + filesystem.property.valueunit = "GiB"; + } else if (/TiB/g.test(filesystem.property.value)) { + filesystem.property.valueunit = "TiB"; + } + + filesystem.property.valueraw = filesystem.property.value.toString().replace(" " + filesystem.property.valueunit, ""); + } + + $("#input-" + modal.name + "-refreservation-" + modal.id).val(filesystem.property.valueraw); + + size.refreservation = { + available: parseInt(filesystem.available), + refreservation: parseInt(filesystem.properties.value), + max: { + raw: 0, + unit: "", + unitnumber: 0 + }, + slider: { + valuemax: 1000 + } + }; + + size.refreservation.max.raw = (size.refreservation.available > size.refreservation.refreservation ? size.refreservation.available : size.refreservation.refreservation); + size.refreservation.max.unitnumber = FnFormatBytes({ base2: true, decimals: 2, value: size.refreservation.max.raw }).replace(/ .*$/g, ""); + size.refreservation.max.unit = FnFormatBytes({ base2: true, decimals: 2, value: size.refreservation.max.raw }).replace(/ /g, "").replace(/^[0-9.]/, ""); + + if (size.refreservation.max.raw <= 1024000) { + $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-kib", size.refreservation.max.unitnumber); + } + if (size.refreservation.max.raw > 1024000) { + $("#dropdown-" + modal.name + "-refreservation-" + modal.id + " li[value='MiB']").removeClass("hidden"); + + $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-kib", size.refreservation.slider.valuemax); + $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-mib", size.refreservation.max.unitnumber); + } + if (size.refreservation.max.raw > 1048576000) { + $("#dropdown-" + modal.name + "-refreservation-" + modal.id + " li[value='GiB']").removeClass("hidden"); + + $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-kib", size.refreservation.slider.valuemax); + $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-mib", size.refreservation.slider.valuemax); + $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-gib", size.refreservation.max.unitnumber); + } + if (size.refreservation.max.raw > 1073741824000) { + $("#dropdown-" + modal.name + "-refreservation-" + modal.id + " li[value='TiB']").removeClass("hidden"); + + $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-kib", size.refreservation.slider.valuemax); + $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-mib", size.refreservation.slider.valuemax); + $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-gib", size.refreservation.slider.valuemax); + $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-tib", size.refreservation.max.unitnumber); + } + + if (filesystem.property.valueunit == "KiB") { + size.refreservation.slider.valuemax = $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-kib"); + } + if (filesystem.property.valueunit == "MiB") { + size.refreservation.slider.valuemax = $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-mib"); + } + if (filesystem.property.valueunit == "GiB") { + size.refreservation.slider.valuemax = $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-gib"); + } + if (filesystem.property.valueunit == "TiB") { + size.refreservation.slider.valuemax = $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-filesystem-refreservation-max-tib"); + } + + $("#slider-" + modal.name + "-refreservation-" + modal.id).data("slider").options.max = size.refreservation.slider.valuemax; + $("#slider-" + modal.name + "-refreservation-" + modal.id).data("slider").options.step = (size.refreservation.slider.valuemax < 10 ? "0.1" : "1"); + $("#slider-" + modal.name + "-refreservation-" + modal.id).slider("setValue", filesystem.property.valueraw); + + $("#btnspan-" + modal.name + "-refreservation-" + modal.id).text(filesystem.property.valueunit).attr("data-field-value", filesystem.property.valueunit); + $("#dropdown-" + modal.name + "-refreservation-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-refreservation-" + modal.id + " li[value='" + filesystem.property.valueunit + "']").addClass("active"); + $("#input-" + modal.name + "-refreservation-" + modal.id).attr("data-field-value", filesystem.property.value.toString().replace(/ /g, "").replace(/iB$/g, "")); + + if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { + $("#input-" + modal.name + "-refreservation-" + modal.id).prop("disabled", true); + $("#div-" + modal.name + "-refreservation-dropdown-" + modal.id + " button").prop("disabled", true); + $("#validationwrapper-" + modal.name + "-refreservation-" + modal.id + " .slider-pf .slider *").addClass("disabled"); + $("#slider-" + modal.name + "-refreservation-" + modal.id).slider("disable"); + } + break; + case "rootcontext": //Default is empty + if (filesystem.properties.value == "system_u:object_r:samba_share_t:s0") { + filesystem.rootcontext = true; + } + break; + case "sharenfs": //Default is off + if (filesystem.properties.value != "off") { + if (!$("#switch-" + modal.name + "-sharenfs-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-sharenfs-" + modal.id + " input").click(); + } + + $("#controllabel-" + modal.name + "-sharenfs-options-" + modal.id).removeClass("hidden"); + $("#validationwrapper-" + modal.name + "-sharenfs-options-" + modal.id).removeClass("hidden"); + $("#input-" + modal.name + "-sharenfs-options-" + modal.id).val((filesystem.properties.value == "on" ? "sec=sys,rw,crossmnt,no_subtree_check,no_root_squash" : filesystem.properties.value)); + + FnSystemNfsVersionGet({ alert: { id: $("#alert-" + modal.name + "-sharenfs-options-" + modal.id) } }); + } + + $("#input-" + modal.name + "-sharenfs-options-" + modal.id).attr("data-field-value", filesystem.properties.value); + + if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { + $("#switch-" + modal.name + "-sharenfs-" + modal.id + " input").prop("disabled", true); + $("#input-" + modal.name + "-sharenfs-options-" + modal.id).prop("disabled", true); + } + break; + case "sharesmb": + if (filesystem.properties.value == "on" && !$("#switch-" + modal.name + "-sharesmb-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-sharesmb-" + modal.id + " input").click(); + } + + if (pool.readonly || zfsmanager.configuration.samba.manage) { + $("#switch-" + modal.name + "-sharesmb-" + modal.id + " input").prop("disabled", true); + } + + $("#switch-" + modal.name + "-sharesmb-" + modal.id).attr("data-field-value", filesystem.properties.value); + break; + case "special_small_blocks": //Default is 0 + filesystem.property = { + value: FnFormatBytes({ base2: true, decimals: 0, value: filesystem.properties.value }), + valueinherited: "" + }; + + if (/^inherited/gi.test(filesystem.properties.source)) { + filesystem.property.source = "inherited"; + filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; + + $("#dropdown-" + modal.name + "-special_small_blocks-" + modal.id + " li[value='Inherited']").removeClass("hidden"); + $("#dropdown-" + modal.name + "-special_small_blocks-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); + } else if (/^default|^local/gi.test(filesystem.properties.source)) { + $("#dropdown-" + modal.name + "-special_small_blocks-" + modal.id + " li[value='InheritedReset']").removeClass("hidden"); + + if (/^default/gi.test(filesystem.properties.source)) { + filesystem.property.source = "default"; + filesystem.property.valueinherited = "Default (0 B)"; + + $("#dropdown-" + modal.name + "-special_small_blocks-" + modal.id + " li[value='InheritedReset'] a").text(filesystem.property.valueinherited); + } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name == pool.name) { + filesystem.property.source = "local"; + + $("#dropdown-" + modal.name + "-special_small_blocks-" + modal.id + " li[value='InheritedReset'] a").text("Default (0 B)"); + } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name != pool.name) { + filesystem.property.source = "local"; + + FnFileSystemConfigurationInheritedPropertyGet({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, property: "special_small_blocks" }, { name: modal.name, id: modal.id }); + } + } + + $("#btnspan-" + modal.name + "-special_small_blocks-" + modal.id).text((filesystem.property.valueinherited ? filesystem.property.valueinherited : filesystem.property.value)).attr("data-field-value", filesystem.properties.valueraw).attr("data-field-source", filesystem.property.source); + $("#dropdown-" + modal.name + "-special_small_blocks-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-special_small_blocks-" + modal.id + " li[value='" + (filesystem.property.valueinherited ? (filesystem.property.source == "inherited" ? "Inherited" : "InheritedReset") : filesystem.properties.valueraw) + "']").addClass("active"); + + if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { + $("#div-" + modal.name + "-special_small_blocks-dropdown-" + modal.id + " button").prop("disabled", true); + } + break; + case "used": + filesystem.used = filesystem.properties.value; + + filesystem.property = { + value: "0 B" + }; + + if (filesystem.properties.value == "none" || filesystem.properties.value == "0" || filesystem.properties.value == "0b") { + filesystem.property.value = "0 B"; + } else { + filesystem.property.value = FnFormatBytes({ base2: true, decimals: 2, value: filesystem.properties.value }); + } + + $("#helpblock-" + modal.name + "-used-" + modal.id).text("Used size: " + filesystem.property.value); + break; + case "xattr": //Default is on + filesystem.property = { + value: "On", + valueinherited: "" + }; + + switch (filesystem.properties.value) { + case "off": + filesystem.property.value = "Off"; + break; + case "sa": + filesystem.property.value = "System Attribute"; + break; + default: + filesystem.property.value = "On"; + break; + } + + if (/^inherited/gi.test(filesystem.properties.source)) { + filesystem.property.source = "inherited"; + filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; + + $("#dropdown-" + modal.name + "-xattr-" + modal.id + " li[value='Inherited']").removeClass("hidden"); + $("#dropdown-" + modal.name + "-xattr-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); + } else if (/^default|^local/gi.test(filesystem.properties.source)) { + $("#dropdown-" + modal.name + "-xattr-" + modal.id + " li[value='InheritedReset']").removeClass("hidden"); + + if (/^default/gi.test(filesystem.properties.source)) { + filesystem.property.source = "default"; + filesystem.property.valueinherited = "Default (On)"; + + $("#dropdown-" + modal.name + "-xattr-" + modal.id + " li[value='InheritedReset'] a").text(filesystem.property.valueinherited); + } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name == pool.name) { + filesystem.property.source = "local"; + + $("#dropdown-" + modal.name + "-xattr-" + modal.id + " li[value='InheritedReset'] a").text("Default (On)"); + } else if (/^local/gi.test(filesystem.properties.source) && filesystem.name != pool.name) { + filesystem.property.source = "local"; + + FnFileSystemConfigurationInheritedPropertyGet({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, property: "xattr" }, { name: modal.name, id: modal.id }); + } + } + + $("#btnspan-" + modal.name + "-xattr-" + modal.id).text((filesystem.property.valueinherited ? filesystem.property.valueinherited : filesystem.property.value)).attr("data-field-value", filesystem.properties.valueraw).attr("data-field-source", filesystem.property.source); + $("#dropdown-" + modal.name + "-xattr-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-xattr-" + modal.id + " li[value='" + (filesystem.property.valueinherited ? (filesystem.property.source == "inherited" ? "Inherited" : "InheritedReset") : filesystem.properties.valueraw) + "']").addClass("active"); + + if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { + $("#div-" + modal.name + "-xattr-dropdown-" + modal.id + " button").prop("disabled", true); + } + break; + } + }); + + if (filesystem.context && filesystem.fscontext && filesystem.defcontext && filesystem.rootcontext) { + if (!$("#switch-" + modal.name + "-selinux-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-selinux-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-selinux-" + modal.id).attr("data-field-value", "true"); + } else { + $("#switch-" + modal.name + "-selinux-" + modal.id).attr("data-field-value", "false"); + } + + if (filesystem.readonly && zfsmanager.configuration.zfs.filesystem.readonlylockdown || pool.readonly) { + $("#switch-" + modal.name + "-selinux-" + modal.id + " input").prop("disabled", true); + } + if (pool.readonly) { + $("#btn-" + modal.name + "-apply-" + modal.id).prop("disabled", true); + } + + FnConsole.log[1]("File Systems, Configuration, Get: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + }) + .fail(function (message, data) { + FnConsole.warn("File Systems, Configuration, Get: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + " , Message: " + (data ? data : message)); + }); +} + +function FnFileSystemConfigurationInheritedGet(pool = { name, id }, filesystem = { name }, modal = { name, id }) { + let process = { + command: ["/sbin/zfs", "get", "atime,casesensitivity,compression,dedup,dnodesize,encryption,recordsize,special_small_blocks,xattr", "-H", "-o", "property,value,source", "-p", filesystem.name] + }; + + FnConsole.log[2]("File Systems, Configuration, Inherited, Get: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Configuration, Inherited, Get:" })); + + process.data = data.replace(/\t+/g, "\u22C5").split(/\n/g).filter(v => v); + + process.data.forEach((_value, _index) => { + _value = _value.split("\u22C5"); + + filesystem.properties = { + property: _value[0].toLowerCase(), + value: _value[1].toLowerCase(), + valueraw: _value[1], + source: _value[2] + }; + + switch (filesystem.properties.property) { + case "atime": //Default is on + filesystem.property = { + value: "On", + valueinherited: "" + }; + + switch (filesystem.properties.value) { + case "on": + filesystem.property.value = "On"; + break; + case "gzip": + filesystem.property.value = "GZIP"; + break; + case "lz4": + filesystem.property.value = "LZ4"; + break; + case "lzjb": + filesystem.property.value = "LZJB"; + break; + case "zle": + filesystem.property.value = "ZLE"; + break; + default: + filesystem.property.value = "Off"; + break; + } + + filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; + + $("#btnspan-" + modal.name + "-atime-" + modal.id).text(filesystem.property.valueinherited).attr("data-field-value", "Inherited"); + $("#dropdown-" + modal.name + "-atime-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-atime-" + modal.id + " li[value='Inherited']").removeClass("hidden"); + $("#dropdown-" + modal.name + "-atime-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); + $("#dropdown-" + modal.name + "-atime-" + modal.id + " li[value='Inherited']").addClass("active"); + break; case "casesensitivity": //Default is sensitive + filesystem.property = { + value: "Sensitive", + valueinherited: "" + }; + + switch (filesystem.properties.value) { + case "insensitive": + filesystem.property.value = "Insensitive"; + break; + case "mixed": + filesystem.property.value = "Mixed"; + break; + case "sensitive": + filesystem.property.value = "Sensitive"; + break; + default: + filesystem.property.value = "Sensitive"; + break; + } + + filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; + + $("#btnspan-" + modal.name + "-casesensitivity-" + modal.id).text(filesystem.property.valueinherited).attr("data-field-value", "Inherited"); + $("#dropdown-" + modal.name + "-casesensitivity-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-casesensitivity-" + modal.id + " li[value='Inherited']").removeClass("hidden"); + $("#dropdown-" + modal.name + "-casesensitivity-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); + $("#dropdown-" + modal.name + "-casesensitivity-" + modal.id + " li[value='Inherited']").addClass("active"); + break; + case "compression": //Default is off + filesystem.property = { + value: "Off", + valueinherited: "" + }; + + switch (filesystem.properties.value) { + case "on": + filesystem.property.value = "On"; + break; + case "gzip": + filesystem.property.value = "GZIP"; + break; + case "lz4": + filesystem.property.value = "LZ4"; + break; + case "lzjb": + filesystem.property.value = "LZJB"; + break; + case "zle": + filesystem.property.value = "ZLE"; + break; + default: + filesystem.property.value = "Off"; + break; + } + + filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; + + $("#btnspan-" + modal.name + "-compression-" + modal.id).text(filesystem.property.valueinherited).attr("data-field-value", "Inherited"); + $("#dropdown-" + modal.name + "-compression-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-compression-" + modal.id + " li[value='Inherited']").removeClass("hidden"); + $("#dropdown-" + modal.name + "-compression-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); + $("#dropdown-" + modal.name + "-compression-" + modal.id + " li[value='Inherited']").addClass("active"); + break; + case "dedup": //Default is off + filesystem.property = { + value: "Off", + valueinherited: "" + }; + + switch (filesystem.properties.value) { + case "on": + filesystem.property.value = "On"; + break; + case "off": + filesystem.property.value = "Off"; + break; + case "verify": + filesystem.property.value = "Verify"; + break; + case "sha256": + filesystem.property.value = "SHA-256"; + break; + case "sha256,verify": + filesystem.property.value = "SHA-256 + Verify"; + break; + case "sha512": + filesystem.property.value = "SHA-512"; + break; + case "sha512,verify": + filesystem.property.value = "SHA-512 + Verify"; + break; + case "skein": + filesystem.property.value = "Skein"; + break; + case "skein,verify": + filesystem.property.value = "Skein + Verify"; + break; + case "edonr,verify": + filesystem.property.value = "Edon-R + Verify"; + break; + default: + filesystem.property.value = "Off"; + break; + } + + filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; + + $("#btnspan-" + modal.name + "-dedup-" + modal.id).text(filesystem.property.valueinherited).attr("data-field-value", "Inherited"); + $("#dropdown-" + modal.name + "-dedup-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-dedup-" + modal.id + " li[value='Inherited']").removeClass("hidden"); + $("#dropdown-" + modal.name + "-dedup-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); + $("#dropdown-" + modal.name + "-dedup-" + modal.id + " li[value='Inherited']").addClass("active"); + break; + case "dnodesize": //Default is legacy + filesystem.property = { + value: "Off", + valueinherited: "" + }; + + switch (filesystem.properties.value) { + case "1k": + filesystem.property.value = "1 KiB"; + break; + case "2k": + filesystem.property.value = "2 KiB"; + break; + case "4k": + filesystem.property.value = "4 KiB"; + break; + case "8k": + filesystem.property.value = "8 KiB"; + break; + case "16k": + filesystem.property.value = "16 KiB"; + break; + case "auto": + filesystem.property.value = "Auto"; + break; + case "legacy": + filesystem.property.value = "Legacy"; + break; + default: + filesystem.property.value = "Legacy"; + break; + } + + filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; + + $("#btnspan-" + modal.name + "-dnodesize-" + modal.id).text(filesystem.property.valueinherited).attr("data-field-value", "Inherited"); + $("#dropdown-" + modal.name + "-dnodesize-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-dnodesize-" + modal.id + " li[value='Inherited']").removeClass("hidden"); + $("#dropdown-" + modal.name + "-dnodesize-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); + $("#dropdown-" + modal.name + "-dnodesize-" + modal.id + " li[value='Inherited']").addClass("active"); + break; + case "encryption": //Default is off + filesystem.property = { + value: "Off", + valueinherited: "" + }; + + switch (filesystem.properties.value) { + case "on": + filesystem.property.value = "On"; + break; + case "off": + filesystem.property.value = "Off"; + break; + case "aes-128-ccm": + filesystem.property.value = "AES-128-CCM"; + break; + case "aes-192-ccm": + filesystem.property.value = "AES-192-CCM"; + break; + case "aes-256-ccm": + filesystem.property.value = "AES-256-CCM"; + break; + case "aes-128-gcm": + filesystem.property.value = "AES-128-GCM"; + break; + case "aes-192-gcm": + filesystem.property.value = "AES-192-GCM"; + break; + case "aes-256-gcm": + filesystem.property.value = "AES-256-GCM"; + break; + } + + filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; + + if (filesystem.properties.value != "off") { + if (!$("#switch-" + modal.name + "-encryption-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-encryption-" + modal.id + " input").click(); + } + + $("#switch-" + modal.name + "-encryption-" + modal.id + " input").prop("disabled", true); + $("#btnspan-" + modal.name + "-encryption-cipher-" + modal.id).text(filesystem.property.valueinherited).attr("data-field-value", "Inherited"); + $("#dropdown-" + modal.name + "-encryption-cipher-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-encryption-cipher-" + modal.id + " li[value='Inherited']").removeClass("hidden"); + $("#dropdown-" + modal.name + "-encryption-cipher-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); + $("#dropdown-" + modal.name + "-encryption-cipher-" + modal.id + " li[value='Inherited']").addClass("active"); + $("#helpblock-" + modal.name + "-encryption-passphrase-" + modal.id).removeClass("has-error").removeClass("hidden").text("Passphrase is not required."); + } else if (filesystem.properties.value == "off") { + $("#switch-" + modal.name + "-encryption-" + modal.id + " input").prop("disabled", false); + + if ($("#switch-" + modal.name + "-encryption-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-encryption-" + modal.id + " input").click(); + } + + $("#btnspan-" + modal.name + "-encryption-cipher-" + modal.id).text("AES-256-GCM").attr("data-field-value", "aes-256-gcm"); + $("#dropdown-" + modal.name + "-encryption-cipher-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-encryption-cipher-" + modal.id + " li[value='aes-256-gcm']").addClass("active"); + $("#dropdown-" + modal.name + "-encryption-cipher-" + modal.id + " li[value='Inherited']").addClass("hidden"); + $("#dropdown-" + modal.name + "-encryption-cipher-" + modal.id + " li[value='Inherited'] a").text("Inherited"); + + if ($("#input-" + modal.name + "-encryption-passphrase-" + modal.id).val().length == 0) { + $("#validationwrapper-" + modal.name + "-encryption-passphrase-" + modal.id).removeClass("has-error"); + $("#helpblock-" + modal.name + "-encryption-passphrase-" + modal.id).removeClass("has-error").addClass("hidden").text(""); + $("#validationwrapper-" + modal.name + "-encryption-passphrase-confirm-" + modal.id).removeClass("has-error"); + $("#helpblock-" + modal.name + "-encryption-passphrase-" + modal.id).removeClass("has-error").addClass("hidden").text(""); + } + } + break; + case "recordsize": //Default is 128K + filesystem.property = { + value: FnFormatBytes({ base2: true, decimals: 0, value: filesystem.properties.value }), + valueinherited: "" + }; + + filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; + + $("#btnspan-" + modal.name + "-recordsize-" + modal.id).text(filesystem.property.valueinherited).attr("data-field-value", "Inherited"); + $("#dropdown-" + modal.name + "-recordsize-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-recordsize-" + modal.id + " li[value='Inherited']").removeClass("hidden"); + $("#dropdown-" + modal.name + "-recordsize-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); + $("#dropdown-" + modal.name + "-recordsize-" + modal.id + " li[value='Inherited']").addClass("active"); + break; + case "special_small_blocks": //Default is 0 + filesystem.property = { + value: FnFormatBytes({ base2: true, decimals: 0, value: filesystem.properties.value }), + valueinherited: "" + }; + + filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; + + $("#btnspan-" + modal.name + "-special_small_blocks-" + modal.id).text(filesystem.property.valueinherited).attr("data-field-value", "Inherited"); + $("#dropdown-" + modal.name + "-special_small_blocks-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-special_small_blocks-" + modal.id + " li[value='Inherited']").removeClass("hidden"); + $("#dropdown-" + modal.name + "-special_small_blocks-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); + $("#dropdown-" + modal.name + "-special_small_blocks-" + modal.id + " li[value='Inherited']").addClass("active"); + break; + case "xattr": //Default is on + filesystem.property = { + value: "On", + valueinherited: "" + }; + + switch (filesystem.properties.value) { + case "on": + filesystem.property.value = "On"; + break; + case "off": + filesystem.property.value = "Off"; + break; + case "sa": + filesystem.property.value = "System Attribute"; + break; + default: + filesystem.property.value = "On"; + break; + } + + filesystem.property.valueinherited = "Inherited (" + filesystem.property.value + ")"; + + $("#btnspan-" + modal.name + "-xattr-" + modal.id).text(filesystem.property.valueinherited).attr("data-field-value", "Inherited"); + $("#dropdown-" + modal.name + "-xattr-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-xattr-" + modal.id + " li[value='Inherited']").removeClass("hidden"); + $("#dropdown-" + modal.name + "-xattr-" + modal.id + " li[value='Inherited'] a").text(filesystem.property.valueinherited); + $("#dropdown-" + modal.name + "-xattr-" + modal.id + " li[value='Inherited']").addClass("active"); + break; + } + }); + + //Quota + let size = { + quota: { + max: { + raw: 1099511627776000, + unit: "", + unitnumber: 0 + }, + slider: { + valuemax: 1000 + }, + property: { + value: "0 B", + valueraw: "0", + valueunit: "KiB" + } + } + }; + + FnStoragePoolSizeGet({ name: pool.name, id: null }) + .done(function (_data) { + FnConsole.log[4](FnConsoleVerbose({ data: _data, message: "Storage Pools, Size, Get:" })); + + if (_data && zfsmanager.configuration.zfs.filesystem.quotarestrict) { + size.quota.max.raw = parseInt(_data.replace(/\n+/g, "")); + } + }) + .finally(function () { + size.quota.max.unitnumber = FnFormatBytes({ base2: true, decimals: 2, value: size.quota.max.raw }).replace(/ .*$/g, ""); + size.quota.max.unit = FnFormatBytes({ base2: true, decimals: 2, value: size.quota.max.raw }).replace(/ /g, "").replace(/^[0-9.]/, ""); + + if (size.quota.max.raw <= 1024000) { + $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-kib", size.quota.max.unitnumber); + } + if (size.quota.max.raw > 1024000) { + $("#dropdown-" + modal.name + "-quota-" + modal.id + " li[value='MiB']").removeClass("hidden"); + + $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-kib", size.quota.slider.valuemax); + $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-mib", size.quota.max.unitnumber); + } + if (size.quota.max.raw > 1048576000) { + $("#dropdown-" + modal.name + "-quota-" + modal.id + " li[value='GiB']").removeClass("hidden"); + + $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-kib", size.quota.slider.valuemax); + $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-mib", size.quota.slider.valuemax); + $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-gib", size.quota.max.unitnumber); + } + if (size.quota.max.raw > 1073741824000) { + $("#dropdown-" + modal.name + "-quota-" + modal.id + " li[value='TiB']").removeClass("hidden"); + + $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-kib", size.quota.slider.valuemax); + $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-mib", size.quota.slider.valuemax); + $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-gib", size.quota.slider.valuemax); + $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-tib", size.quota.max.unitnumber); + } + + if (size.quota.property.valueunit == "KiB") { + size.quota.slider.valuemax = $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-kib"); + } + if (size.quota.property.valueunit == "MiB") { + size.quota.slider.valuemax = $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-mib"); + } + if (size.quota.property.valueunit == "GiB") { + size.quota.slider.valuemax = $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-gib"); + } + if (size.quota.property.valueunit == "TiB") { + size.quota.slider.valuemax = $("#input-" + modal.name + "-quota-" + modal.id).attr("data-filesystem-quota-max-tib"); + } + + $("#slider-" + modal.name + "-quota-" + modal.id).data("slider").options.max = size.quota.slider.valuemax; + $("#slider-" + modal.name + "-quota-" + modal.id).data("slider").options.step = (size.quota.slider.valuemax < 10 ? "0.1" : "1"); + $("#slider-" + modal.name + "-quota-" + modal.id).slider("setValue", size.quota.property.valueraw); + + $("#btnspan-" + modal.name + "-quota-" + modal.id).text(size.quota.property.valueunit).attr("data-field-value", size.quota.property.valueunit); + $("#dropdown-" + modal.name + "-quota-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-quota-" + modal.id + " li[value='" + size.quota.property.valueunit + "']").addClass("active"); + $("#input-" + modal.name + "-quota-" + modal.id).attr("data-field-value", size.quota.property.value.toString().replace(/ /g, "").replace(/iB$/g, "")); + }); + + FnConsole.log[1]("File Systems, Configuration, Inherited, Get: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + }) + .fail(function (message, data) { + FnConsole.warn("File Systems, Configuration, Inherited, Get: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + " , Message: " + (data ? data : message)); + }); +} + +function FnFileSystemConfigurationInheritedPropertyGet(pool = { name, id }, filesystem = { name, id, property }, modal = { name, id }) { + let process = { + command: ["/sbin/zfs", "get", filesystem.property, "-H", "-o", "value", "-p", "-d", "0", filesystem.name.replace(/\/[^\/]+$/, "")] + }; + + FnConsole.log[2]("File Systems, Configuration, Property, Inherited, Get: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Configuration, Property, Get:" })); + + filesystem.properties = { + value: data.trim() + }; + + switch (filesystem.properties.value) { + case "edonr": + filesystem.properties.value = "Edon-R"; + break; + case "edonr,verify": + filesystem.properties.value = "Edon-R + Verify"; + break; + case "gzip": + filesystem.properties.value = "GZIP"; + break; + case "lz4": + filesystem.properties.value = "LZ4"; + break; + case "lzjb": + filesystem.properties.value = "LZJB"; + break; + case "noacl": + filesystem.properties.value = "No ACL"; + break; + case "noallow": + filesystem.properties.value = "No Allow"; + break; + case "noparity": + filesystem.properties.value = "No Parity"; + break; + case "passthrough-x": + filesystem.properties.value = "Passthrough-X"; + break; + case "posixacl": + filesystem.properties.value = "POSIX ACL"; + break; + case "sa": + filesystem.properties.value = "System Attribute"; + break; + case "sha256": + filesystem.properties.value = "SHA-256"; + break; + case "sha256,verify": + filesystem.properties.value = "SHA-256 + Verify"; + break; + case "sha512": + filesystem.properties.value = "SHA-512"; + break; + case "sha512,verify": + filesystem.properties.value = "SHA-512 + Verify"; + break; + case "skein,verify": + filesystem.properties.value = "Skein + Verify"; + break; + case "zle": + filesystem.properties.value = "ZLE"; + break; + default: + filesystem.properties.value = ($.isNumeric(filesystem.properties.value) ? FnFormatBytes({ base2: true, decimals: 0, value: filesystem.properties.value }) : filesystem.properties.value.charAt(0).toUpperCase() + filesystem.properties.value.slice(1)); + } + + $("#dropdown-" + modal.name + "-" + filesystem.property + "-" + modal.id + " li[value='InheritedReset'] a").text("Inherited" + (filesystem.properties.value ? " (" + filesystem.properties.value + ")" : "")); + + FnConsole.log[2]("File Systems, Configuration, Property, Inherited, Get: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + }) + .fail(function (message, data) { + $("#dropdown-" + modal.name + "-" + filesystem.property + "-" + modal.id + " li[value='InheritedReset'] a").text("Inherited"); + + FnConsole.warn("File Systems, Configuration, Property, Inherited, Get: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + " , Message: " + (data ? data : message)); + }); +} + +function FnFileSystemConfigure(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, aclinherit, acltype, atime, canmount, checksum, compression, context, dedup, dnodesize, defcontext, fscontext, mountpoint, quota, readonly, recordsize, refreservation, rootcontext, sharenfs, sharesmb, special_small_blocks, type, xattr }, samba = { restart: false }, modal = { id }) { + filesystem.properties = { + inherit: [], + new: [] + }; + + if (filesystem.aclinherit) { + if (/^Default|^Inherited/g.test(filesystem.aclinherit)) { + filesystem.properties.inherit.push("aclinherit"); + } else { + filesystem.properties.new.push("aclinherit=" + filesystem.aclinherit); + } + } + if (filesystem.acltype) { + if (/^Default|^Inherited/g.test(filesystem.acltype)) { + filesystem.properties.inherit.push("acltype"); + } else { + filesystem.properties.new.push("acltype=" + filesystem.acltype); + } + } + if (filesystem.atime) { + if (/^Default|^Inherited/g.test(filesystem.atime)) { + filesystem.properties.inherit.push("atime"); + } else { + filesystem.properties.new.push("atime=" + filesystem.atime); + } + } + if (filesystem.canmount) { + filesystem.properties.new.push("canmount=" + filesystem.canmount); + } + if (filesystem.checksum) { + if (/^Default|^Inherited/g.test(filesystem.checksum)) { + filesystem.properties.inherit.push("checksum"); + } else { + filesystem.properties.new.push("checksum=" + filesystem.checksum); + } + } + if (filesystem.compression) { + if (/^Default|^Inherited/g.test(filesystem.compression)) { + filesystem.properties.inherit.push("compression"); + } else { + filesystem.properties.new.push("compression=" + filesystem.compression); + } + } + if (filesystem.context) { + filesystem.properties.new.push("context=" + filesystem.context); + } + if (filesystem.dedup) { + if (/^Default|^Inherited/g.test(filesystem.dedup)) { + filesystem.properties.inherit.push("dedup"); + } else { + filesystem.properties.new.push("dedup=" + filesystem.dedup); + } + } + if (filesystem.dnodesize) { + if (/^Default|^Inherited/g.test(filesystem.dnodesize)) { + filesystem.properties.inherit.push("dnodesize"); + } else { + filesystem.properties.new.push("dnodesize=" + filesystem.dnodesize); + } + } + if (filesystem.defcontext) { + filesystem.properties.new.push("defcontext=" + filesystem.defcontext); + } + if (filesystem.fscontext) { + filesystem.properties.new.push("fscontext=" + filesystem.fscontext); + } + if (filesystem.mountpoint) { + filesystem.properties.new.push(`mountpoint="` + filesystem.mountpoint + `"`); + } + if (filesystem.quota) { + filesystem.properties.new.push(`quota="` + filesystem.quota + `"`); + } + if (filesystem.readonly) { + filesystem.properties.new.push("readonly=" + filesystem.readonly); + } + if (filesystem.recordsize) { + if (/^Default|^Inherited/g.test(filesystem.recordsize)) { + filesystem.properties.inherit.push("recordsize"); + } else { + filesystem.properties.new.push("recordsize=" + filesystem.recordsize); + } + } + if (filesystem.refreservation) { + filesystem.properties.new.push("refreservation=" + filesystem.refreservation); + } + if (filesystem.rootcontext) { + filesystem.properties.new.push("rootcontext=" + filesystem.rootcontext); + } + if (filesystem.sharenfs) { + filesystem.properties.new.push(`sharenfs="` + filesystem.sharenfs + `"`); + } + if (filesystem.sharesmb && !zfsmanager.configuration.samba.manage) { + filesystem.properties.new.push("sharesmb=" + filesystem.sharesmb); + } + if (filesystem.special_small_blocks) { + if (/^Default|^Inherited/g.test(filesystem.special_small_blocks)) { + filesystem.properties.inherit.push("special_small_blocks"); + } else { + filesystem.properties.new.push("special_small_blocks=" + filesystem.special_small_blocks); + } + } + if (filesystem.xattr) { + if (/^Default|^Inherited/g.test(filesystem.xattr)) { + filesystem.properties.inherit.push("xattr"); + } else { + filesystem.properties.new.push("xattr=" + filesystem.xattr); + } + } + + if (filesystem.properties.inherit.length > 0 && !pool.readonly) { + FnFileSystemConfigureInheritance({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, properties: { inherit: filesystem.properties.inherit }, type: filesystem.type }) + .finally(function () { + if (filesystem.properties.new.length > 0 && !pool.readonly) { + FnFileSystemConfigureCommand({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: filesystem.name, id: filesystem.id, mountpoint: filesystem.mountpoint, properties: { new: filesystem.properties.new }, type: filesystem.type }, { restart: samba.restart }, { id: modal.id }); + } else { + modal.id.modal("hide"); + } + }); + } else if (filesystem.properties.new.length > 0 && !pool.readonly) { + FnFileSystemConfigureCommand({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: filesystem.name, id: filesystem.id, mountpoint: filesystem.mountpoint, properties: { new: filesystem.properties.new }, type: filesystem.type }, { restart: samba.restart }, { id: modal.id }); + } else { + modal.id.modal("hide"); + } +} + +function FnFileSystemConfigureCommand(pool = { name, id, altroot: false }, filesystem = { name, id, mountpoint, properties: { new: [] }, type }, samba = { restart: false }, modal = { id }) { + let process = { + command: ["/bin/sh", "-c", "/sbin/zfs set " + filesystem.properties.new.join(" ") + " " + `"` + filesystem.name + `"`] + }; + + modal.hide = true; + + FnConsole.log[2]("File Systems, Configure: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-storagepool-filesystem-configure-" + filesystem.id + " span").text("Configuring " + filesystem.type.toLowerCase() + "..."); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "File System successfully configured", description: filesystem.name, breakword: false }, { name: "filesystem-configure", id: filesystem.id, timeout: 4 }); + + FnConsole.log[1]("File Systems, Configure: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + + if (zfsmanager.configuration.samba.manage) { + if (filesystem.mountpoint) { + modal.hide = false; + + $("#spinner-storagepool-filesystem-configure-" + filesystem.id + " span").text("Updating Samba shares..."); + + FnSambaZfsShareConfigurationPathsSet({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: filesystem.name }, { restart: samba.restart }, display = { refresh: false, silent: true }) + .finally(function () { + modal.id.modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + }); + } else if (samba.restart) { + FnSambaRestart(); + } + } else { + if (samba.restart) { + FnSambaRestart(); + } + } + }) + .fail(function (message, data) { + filesystem.configured = false; + + if (/size is greater than available space/gi.test(data)) { + modal.hide = false; + + $("#validationwrapper-storagepool-filesystem-configure-refreservation-" + filesystem.id).addClass("has-error"); + $("#helpblock-storagepool-filesystem-configure-refreservation-" + filesystem.id).addClass("has-error").removeClass("hidden").text("Refreservation can not be greater than available size."); + $("#input-storagepool-filesystem-configure-refreservation-" + filesystem.id).focus(); + } else if (/size is less than current used or reserved space/gi.test(data)) { + modal.hide = false; + + $("#validationwrapper-storagepool-filesystem-configure-quota-" + filesystem.id).addClass("has-error"); + $("#helpblock-storagepool-filesystem-configure-quota-" + filesystem.id).addClass("has-error").removeClass("hidden").text("Quota can not be less than used size."); + $("#input-storagepool-filesystem-configure-quota-" + filesystem.id).focus(); + } else if (/property may be set/gi.test(data)) { + filesystem.configured = true; + + FnDisplayAlert({ status: "warning", title: "File system configured with errors", description: filesystem.name, breakword: false }, { name: "filesystem-configure", id: filesystem.id, timeout: 4 }); + + FnConsole.warn("File Systems, Configure: Warning, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); + } + + if (!filesystem.configured) { + if (modal.hide) { + FnDisplayAlert({ status: "danger", title: "File System could not be configured", description: filesystem.name, breakword: false }, { name: "filesystem-configure", id: filesystem.id, timeout: 4 }); + } + + FnConsole.warn("File Systems, Configure: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); + } + + if (!modal.hide) { + $("#spinner-storagepool-filesystem-configure-" + filesystem.id).addClass("hidden"); + $("#spinner-storagepool-filesystem-configure-" + filesystem.id + " span").text(""); + $("#btn-storagepool-filesystem-configure-apply-" + filesystem.id).prop("disabled", false); + } + }) + .finally(function () { + if (modal.hide) { + modal.id.modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + } + }); +} + +function FnFileSystemConfigureInheritance(pool = { name, id }, filesystem = { name, id, properties: { inherit: [] }, type }) { + let process = { + promise: cockpit.defer() + }; + let promise = Promise.resolve(); + + filesystem.properties.errorcount = 0; + + $("#spinner-storagepool-filesystem-configure-" + filesystem.id + " span").text("Configuring " + filesystem.type.toLowerCase() + " inheritance..."); + + filesystem.properties.inherit.forEach((_value, _index) => { + promise = promise.then(_ => new Promise(resolve => + setTimeout(function () { + process.command = ["/sbin/zfs", "inherit", _value, filesystem.name]; + + FnConsole.log[2]("File Systems, Configure, Inheritance: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnConsole.log[2]("File Systems, Configure, Inheritance: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + + if (_index == (filesystem.properties.inherit.length - 1)) { + if (filesystem.properties.errorcount == 0) { + FnDisplayAlert({ status: "success", title: "File System inheritance successfully configured", description: filesystem.name, breakword: false }, { name: "filesystem-configure-inheritance", id: filesystem.id, timeout: 4 }); + } else { + FnDisplayAlert({ status: "danger", title: "File System inheritance could not be configured", description: filesystem.name, breakword: false }, { name: "filesystem-configure-inheritance", id: filesystem.id, timeout: 4 }); + } + + process.promise.resolve(); + } + }) + .fail(function (message, data) { + filesystem.properties.errorcount++; + + FnConsole.warn("File Systems, Configure, Inheritance: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); + + if (_index == (filesystem.properties.inherit.length - 1)) { + FnDisplayAlert({ status: "danger", title: "File System inheritance could not be configured", description: filesystem.name, breakword: false }, { name: "filesystem-configure-inheritance", id: filesystem.id, timeout: 4 }); + + process.promise.resolve(); + } + }); + + resolve(); + }, 500) + )); + }); + + return process.promise.promise(); +} + +function FnFileSystemCreate(pool = { name, id, altroot: false }, filesystem = { name, id, atime, casesensitivity, cipher, compression, dedup, dnodesize, encryption, passphrase, quota, readonly, recordsize, selinux, sharenfs, sharesmb, special_small_blocks, xattr }) { + let process = { + command: [], + options: `-o normalization=formD -o sharenfs="` + filesystem.sharenfs + `" -o sharesmb=` + filesystem.sharesmb + ` -o utf8only=on` + }; + + if (filesystem.quota) { + process.options += " -o quota=" + filesystem.quota; + } + if (filesystem.readonly) { + process.options += " -o readonly=" + filesystem.readonly; + } + if (filesystem.selinux) { + process.options += " -o context=system_u:object_r:samba_share_t:s0 -o fscontext=system_u:object_r:samba_share_t:s0 -o defcontext=system_u:object_r:samba_share_t:s0 -o rootcontext=system_u:object_r:samba_share_t:s0"; + } + if (/^Inherited/g.test(filesystem.atime) == false) { + process.options += " -o atime=" + filesystem.atime; + } + if (/^Inherited/g.test(filesystem.casesensitivity) == false) { + process.options += " -o casesensitivity=" + filesystem.casesensitivity; + } + if (/^Inherited/g.test(filesystem.dedup) == false) { + process.options += " -o dedup=" + filesystem.dedup; + } + if (/^Inherited/g.test(filesystem.dnodesize) == false) { + process.options += " -o dnodesize=" + filesystem.dnodesize; + } + if (/^Inherited/g.test(filesystem.compression) == false) { + process.options += " -o compression=" + filesystem.compression; + } + if (/^Inherited/g.test(filesystem.recordsize) == false) { + process.options += " -o recordsize=" + filesystem.recordsize; + } + if (/^Inherited/g.test(filesystem.special_small_blocks) == false) { + process.options += " -o special_small_blocks=" + filesystem.special_small_blocks; + } + if (/^Inherited/g.test(filesystem.xattr) == false) { + process.options += " -o xattr=" + filesystem.xattr; + } + if (/^Inherited/g.test(filesystem.cipher) == false && filesystem.encryption) { + process.options += " -o encryption=" + filesystem.cipher; + } + + if (filesystem.encryption && filesystem.passphrase) { + process.options += " -o keyformat=passphrase -o keylocation=prompt"; + + if (filesystem.passphrase.length < 8) { + FnFileSystemCreateFail({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: filesystem.name, id: filesystem.id, sharesmb: filesystem.sharesmb }, { data: "Passphrase requires a minimum of 8 characters.", message: null }); + return; + } + + //Escape percentage and single quote special character for printf + if (/\%/g.test(filesystem.passphrase)) { + filesystem.passphrase = filesystem.passphrase.replace(/\%/g, "\%\%"); + } + if (/\'/g.test(filesystem.passphrase)) { + filesystem.passphrase = filesystem.passphrase.replace(/\'/g, "\'\"\'\"\'"); + } + + process.command = ["/bin/sh", "-c", "printf '" + filesystem.passphrase + "' | /sbin/zfs create " + process.options + ` "` + filesystem.name + `"`]; + } else { + process.command = ["/bin/sh", "-c", "/sbin/zfs create " + process.options + ` "` + filesystem.name + `"`]; + } + + FnConsole.log[1]("File Systems, Create: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-storagepool-filesystems-create-" + pool.id + " span").text("Creating file system..."); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "File System successfully created", description: filesystem.name, breakword: false }, { name: "filesystem-create", id: filesystem.id, timeout: 4 }); + + FnConsole.log[1]("File Systems, Create: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + + if (filesystem.sharesmb == "on" && zfsmanager.configuration.samba.manage) { + $("#spinner-storagepool-filesystems-create-" + pool.id + " span").text("Enabling Samba share..."); + + FnSambaShareEnableMountpointGet({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { name: filesystem.name, id: filesystem.id, sharesmb: true }, { silent: false }); + } + + setTimeout(function () { + $("#modal-storagepool-filesystems-create-" + pool.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + }, (filesystem.sharesmb == "on" && zfsmanager.configuration.samba.manage ? 500 : 0)); + }) + .fail(function (message, data) { + FnFileSystemCreateFail({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: filesystem.name, id: filesystem.id, sharesmb: filesystem.sharesmb }, { data: data, message: message }); + }); +} + +function FnFileSystemCreateFail(pool = { name, id, altroot: false }, filesystem = { name, id, sharesmb }, process = { data, message }) { + let modal = { + hide: true + }; + + filesystem.created = false; + + if (/dataset already exists/gi.test(process.data)) { + modal.hide = false; + + $("#validationwrapper-storagepool-filesystems-create-name-" + pool.id).addClass("has-error"); + $("#helpblock-storagepool-filesystems-create-name-" + pool.id).addClass("has-error").removeClass("hidden").text("Name already exists."); + $("#input-storagepool-filesystems-create-name-" + pool.id).focus(); + } else if (/encryption root's key is not loaded or provided/gi.test(process.data)) { + modal.hide = false; + + $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-" + pool.id).addClass("has-error"); + $("#helpblock-storagepool-filesystems-create-encryption-passphrase-" + pool.id).addClass("has-error").removeClass("hidden").html("Parent file system is locked.
    Unlock parent file system or enter a passphrase to create an independent encryption root."); + $("#input-storagepool-filesystems-create-encryption-passphrase-" + pool.id).focus(); + } else if (/Passphrase requires a minimum of 8 characters./i.test(process.data)) { + modal.hide = false; + + $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-" + pool.id).addClass("has-error"); + $("#helpblock-storagepool-filesystems-create-encryption-passphrase-" + pool.id).addClass("has-error").removeClass("hidden").text("Passphrase requires a minimum of 8 characters."); + $("#input-storagepool-filesystems-create-encryption-passphrase-" + pool.id).focus(); + } else if (/filesystem successfully created/gi.test(process.data)) { + filesystem.created = true; + + FnDisplayAlert({ status: "warning", title: "File system created with errors", description: filesystem.name, breakword: false }, { name: "filesystem-create", id: filesystem.id, timeout: 4 }); + + FnConsole.warn("File Systems, Create: Warning, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (process.data ? process.data : process.message)); + + if (filesystem.sharesmb == "on" && zfsmanager.configuration.samba.manage) { + $("#spinner-storagepool-filesystems-create-" + pool.id + " span").text("Enabling Samba share..."); + + FnSambaShareEnableMountpointGet({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { name: filesystem.name, id: filesystem.id, sharesmb: true }, { silent: false }); + } + } + + if (!modal.hide) { + $("#spinner-storagepool-filesystems-create-" + pool.id).addClass("hidden"); + $("#spinner-storagepool-filesystems-create-" + pool.id + " span").text(""); + $("#btn-storagepool-filesystems-create-apply-" + pool.id).prop("disabled", false); + } + + if (!filesystem.created) { + FnConsole.warn("File Systems, Create: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (process.data ? process.data : process.message)); + } + + if (modal.hide) { + if (!filesystem.created) { + FnDisplayAlert({ status: "danger", title: "File System could not be created", description: filesystem.name, breakword: false }, { name: "filesystem-create", id: filesystem.id, timeout: 4 }); + } + + $("#modal-storagepool-filesystems-create-" + pool.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + } +} + +function FnFileSystemDestroy(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, force: false, recursive: false, recursiveall: false, sharesmb: false, type }, samba = { restart: false }) { + if (samba.restart) { + FnSambaStop() + .finally(function () { + if ((filesystem.recursive || filesystem.recursiveall) && zfsmanager.configuration.samba.manage) { + $("#spinner-storagepool-filesystem-destroy-" + filesystem.id + " span").text("Retrieving Samba shares..."); + + FnSambaSharesGet({ name: pool.name, id: pool.id }, { name: filesystem.name, clones: [] }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Shares, Get:" })); + + let filesystems = { + id: data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) + }; + + $("#spinner-storagepool-filesystem-destroy-" + filesystem.id + " span").text("Destroying " + filesystem.type.toLowerCase() + "s..."); + + if (filesystems.id.length > 0) { + FnFileSystemDestroyCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, force: filesystem.force, recursive: filesystem.recursive, recursiveall: filesystem.recursiveall }, { refresh: false }) + .done(function () { + $("#spinner-storagepool-filesystem-destroy-" + filesystem.id + " span").text("Destroying Samba shares..."); + + FnSambaSharesDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { id: filesystems.id }, { restart: samba.restart }, { silent: true }) + .finally(function () { + $("#modal-storagepool-filesystem-destroy-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + }); + }); + } else { + FnFileSystemDestroyCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, force: filesystem.force, recursive: filesystem.recursive, recursiveall: filesystem.recursiveall }, { refresh: true }) + } + }) + .fail(function (message, data) { + FnFileSystemDestroyFail({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }, { data: data, message: message }, { refresh: true }); + FnSambaStart(); + }); + } else { + $("#spinner-storagepool-filesystem-destroy-" + filesystem.id + " span").text("Destroying " + filesystem.type.toLowerCase() + "..."); + + if (filesystem.sharesmb && zfsmanager.configuration.samba.manage) { + FnFileSystemDestroyCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, force: filesystem.force, recursive: filesystem.recursive, recursiveall: filesystem.recursiveall }, { refresh: false }) + .done(function () { + $("#spinner-storagepool-filesystem-destroy-" + filesystem.id + " span").text("Destroying Samba share..."); + + FnSambaShareDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { name: filesystem.name, id: filesystem.id }, { restart: samba.restart }, { silent: true }) + .finally(function () { + $("#modal-storagepool-filesystem-destroy-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + }); + }); + } else { + FnFileSystemDestroyCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, force: filesystem.force, recursive: filesystem.recursive, recursiveall: filesystem.recursiveall }, { refresh: true }) + .finally(function () { + if (!filesystem.sharesmb || !zfsmanager.configuration.samba.manage) { + FnSambaStart(); + } + }); + } + } + }); + } else { + if ((filesystem.recursive || filesystem.recursiveall) && zfsmanager.configuration.samba.manage) { + $("#spinner-storagepool-filesystem-destroy-" + filesystem.id + " span").text("Retrieving Samba shares..."); + + FnSambaSharesGet({ name: pool.name, id: pool.id }, { name: filesystem.name, clones: [] }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Shares, Get:" })); + + let filesystems = { + id: data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) + }; + + $("#spinner-storagepool-filesystem-destroy-" + filesystem.id + " span").text("Destroying " + filesystem.type.toLowerCase() + "s..."); + + if (filesystems.id.length > 0) { + FnFileSystemDestroyCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, force: filesystem.force, recursive: filesystem.recursive, recursiveall: filesystem.recursiveall }, { refresh: false }) + .done(function () { + $("#spinner-storagepool-filesystem-destroy-" + filesystem.id + " span").text("Destroying Samba shares..."); + + FnSambaSharesDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { id: filesystems.id }, { restart: samba.restart }, { silent: true }) + .finally(function () { + $("#modal-storagepool-filesystem-destroy-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + }); + }); + } else { + FnFileSystemDestroyCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, force: filesystem.force, recursive: filesystem.recursive, recursiveall: filesystem.recursiveall }, { refresh: true }) + } + }) + .fail(function (message, data) { + FnFileSystemDestroyFail({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }, { data: data, message: message }, { refresh: true }); + }); + } else { + $("#spinner-storagepool-filesystem-destroy-" + filesystem.id + " span").text("Destroying " + filesystem.type.toLowerCase() + "..."); + + if (filesystem.sharesmb && zfsmanager.configuration.samba.manage) { + FnFileSystemDestroyCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, force: filesystem.force, recursive: filesystem.recursive, recursiveall: filesystem.recursiveall }, { refresh: false }) + .done(function () { + $("#spinner-storagepool-filesystem-destroy-" + filesystem.id + " span").text("Destroying Samba share..."); + + FnSambaShareDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { name: filesystem.name, id: filesystem.id }, { restart: samba.restart }, { silent: true }) + .finally(function () { + $("#modal-storagepool-filesystem-destroy-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + }); + }); + } else { + FnFileSystemDestroyCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, force: filesystem.force, recursive: filesystem.recursive, recursiveall: filesystem.recursiveall }, { refresh: true }) + } + } + } +} + +function FnFileSystemDestroyCommand(pool = { name, id }, filesystem = { name, id, force: false, recursive: false, recursiveall: false }, display = { refresh: true }) { + let process = { + command: ["/sbin/zfs", "destroy", filesystem.name] + }; + + if (filesystem.force) { + process.command.splice(2, 0, "-f"); + } + if (filesystem.recursive) { + process.command.splice(2, 0, "-r"); + } + if (filesystem.recursiveall) { + process.command.splice(2, 0, "-R"); + } + + FnConsole.log[1]("File Systems, Destroy: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "File System successfully destroyed", description: filesystem.name, breakword: false }, { name: "filesystem-destroy", id: filesystem.id, timeout: 4 }); + + FnConsole.log[1]("File Systems, Destroy: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + }) + .fail(function (message, data) { + FnFileSystemDestroyFail({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }, { data: data, message: message }, { refresh: false }); + + display.refresh = true; + }) + .finally(function () { + if (display.refresh) { + $("#modal-storagepool-filesystem-destroy-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + } + }); +} + +function FnFileSystemDestroyFail(pool = { name, id }, filesystem = { name, id }, process = { data, message }, display = { refresh: true }) { + FnDisplayAlert({ status: "danger", title: "File System could not be destroyed", description: filesystem.name, breakword: false }, { name: "filesystem-destroy", id: filesystem.id, timeout: 4 }); + + FnConsole.warn("File Systems, Destroy: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (process.data ? process.data : process.message)); + + if (display.refresh) { + $("#modal-storagepool-filesystem-destroy-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + } +} + +function FnFileSystemLock(pool = { name, id }, filesystem = { name, id, type }, display = { refresh: true }) { + let process = { + command: ["/sbin/zfs", "unload-key", filesystem.name] + }; + + FnConsole.log[2]("File Systems, Lock: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-storagepool-filesystem-lock-" + filesystem.id + " span").text("Locking " + filesystem.type.toLowerCase() + "..."); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "File System successfully locked", description: filesystem.name, breakword: false }, { name: "filesystem-lock", id: filesystem.id, timeout: 4 }); + + FnConsole.log[1]("File Systems, Lock: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + }) + .fail(function (message, data) { + FnDisplayAlert({ status: "danger", title: "File System could not be locked", description: filesystem.name, breakword: false }, { name: "filesystem-lock", id: filesystem.id, timeout: 4 }); + + FnConsole.warn("File Systems, Lock: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); + }) + .finally(function () { + if (display.refresh) { + $("#modal-storagepool-filesystem-lock-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + } + }); +} + +function FnFileSystemMount(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, overlay: true, type }, samba = { enable: false }, display = { refresh: true }) { + let process = { + command: ["/sbin/zfs", "mount", filesystem.name] + }; + + if (filesystem.overlay) { + process.command.splice(2, 0, "-O"); + } + + FnConsole.log[2]("File Systems, Mount: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-storagepool-filesystem-mount-" + filesystem.id + " span").text("Mounting " + filesystem.type.toLowerCase() + "..."); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "File System successfully mounted", description: filesystem.name, breakword: false }, { name: "filesystem-mount", id: filesystem.id, timeout: 4 }); + + FnConsole.log[1]("File Systems, Mount: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + + if (samba.enable) { + $("#spinner-storagepool-filesystem-mount-" + filesystem.id + " span").text("Enabling Samba share..."); + + if (zfsmanager.configuration.samba.manage) { + FnSambaShareEnableMountpointGet({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, sharesmb: false }, { silent: false }); + } else { + FnFileSystemShareSmbEnable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }); + } + } + }) + .fail(function (message, data) { + if (/filesystem already mounted/gi.test(data)) { + FnDisplayAlert({ status: "warning", title: "File System was already mounted", description: filesystem.name, breakword: false }, { name: "filesystem-mount", id: filesystem.id, timeout: 4 }); + } else { + FnDisplayAlert({ status: "danger", title: "File System could not be mounted", description: filesystem.name, breakword: false }, { name: "filesystem-mount", id: filesystem.id, timeout: 4 }); + } + + FnConsole.warn("File Systems, Mount: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); + }) + .finally(function () { + setTimeout(function () { + $("#modal-storagepool-filesystem-mount-" + filesystem.id).modal("hide"); + + if (display.refresh) { + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: false, status: false }); + }, 200); + } + }, (samba.enable ? 500 : 0)); + }); +} + +function FnFileSystemMountpointGet(pool = { name, id }, filesystem = { name, id }) { + let process = { + command: ["/sbin/zfs", "get", "mountpoint", "-H", "-o", "value", filesystem.name] + }; + + FnConsole.log[2]("File Systems, Mountpoint, Get: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function () { + FnConsole.log[1]("File Systems, Mountpoint, Get: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + }) + .fail(function (message, data) { + FnConsole.warn("File Systems, Mountpoint, Get: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); + }); +} + +function FnFileSystemPromote(pool = { name, id }, filesystem = { name, id, type }) { + let process = { + command: ["/sbin/zfs", "promote", filesystem.name] + }; + + FnConsole.log[2]("File Systems, Promote: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-storagepool-filesystem-promote-" + filesystem.id + " span").text("Promoting " + filesystem.type.toLowerCase() + "..."); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "File System successfully promoted", description: filesystem.name, breakword: false }, { name: "filesystem-promote", id: filesystem.id, timeout: 4 }); + + FnConsole.log[1]("File Systems, Promote: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + }) + .fail(function (message, data) { + FnDisplayAlert({ status: "danger", title: "File System could not be promoted", description: filesystem.name, breakword: false }, { name: "filesystem-promote", id: filesystem.id, timeout: 4 }); + + FnConsole.warn("File Systems, Promote: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); + }) + .finally(function () { + $("#modal-storagepool-filesystem-promote-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + }); +} + +function FnFileSystemRename(pool = { name, id, altroot: false }, filesystem = { name, id, createnonexistparents: false, force: false, namenew, parent, sharesmb: false, type }, samba = { restart: false }) { + if (samba.restart) { + FnSambaStop() + .finally(function () { + if (zfsmanager.configuration.samba.manage) { + $("#spinner-storagepool-filesystem-rename-" + filesystem.id + " span").text("Retrieving Samba shares..."); + + FnSambaSharesGet({ name: pool.name, id: pool.id }, { name: filesystem.name, clones: [] }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Shares, Get:" })); + + let filesystems = { + id: data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) + }; + + $("#spinner-storagepool-filesystem-rename-" + filesystem.id + " span").text("Renaming " + filesystem.type.toLowerCase() + "..."); + + if (filesystems.id.length > 0) { + FnFileSystemRenameCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, createnonexistparents: filesystem.createnonexistparents, force: filesystem.force, namenew: filesystem.namenew, parent: filesystem.parent }, { refresh: false }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Rename:" })); + + if (/dataset already exists/i.test(data) == false) { + $("#spinner-storagepool-filesystem-rename-" + filesystem.id + " span").text("Renaming Samba share" + (filesystems.id.length > 1 ? "s" : "") + "..."); + + FnSambaSharesRename({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, filesystems = { id: filesystems.id, parent: { name: filesystem.name, namenew: filesystem.namenew } }, { restart: samba.restart }, { silent: false }) + .finally(function () { + if (filesystem.createnonexistparents) { + FnFileSystemShareSmbInheritedDisable({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: filesystem.parent }, { disable: true }) + .finally(function () { + $("#modal-storagepool-filesystem-rename-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 500); + }); + } else { + $("#modal-storagepool-filesystem-rename-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 500); + } + }); + + } + }); + } else { + FnFileSystemRenameCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, createnonexistparents: filesystem.createnonexistparents, force: filesystem.force, namenew: filesystem.namenew, parent: filesystem.parent }, { refresh: (filesystem.createnonexistparents ? false : true) }) + .done(function () { + if (filesystem.createnonexistparents) { + $("#spinner-storagepool-filesystem-rename-" + filesystem.id + " span").text("Disabling Samba share inheritance..."); + + FnFileSystemShareSmbInheritedDisable({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: filesystem.parent }, { disable: true }) + .finally(function () { + $("#modal-storagepool-filesystem-rename-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 500); + + FnSambaStart(); + }); + } else { + FnSambaStart(); + } + }) + .fail(function () { + FnSambaStart(); + }); + } + }) + .fail(function (message, data) { + FnFileSystemRenameFail({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, createnonexistparents: filesystem.createnonexistparents, parent: filesystem.parent }, { data: data, message: message }, { refresh: true }); + FnSambaStart(); + }); + } else { + FnFileSystemRenameCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, createnonexistparents: filesystem.createnonexistparents, force: filesystem.force, namenew: filesystem.namenew, parent: filesystem.parent }, { refresh: true }) + .finally(function () { + FnSambaStart(); + }); + } + }); + } else { + if (zfsmanager.configuration.samba.manage) { + $("#spinner-storagepool-filesystem-rename-" + filesystem.id + " span").text("Retrieving Samba shares..."); + + FnSambaSharesGet({ name: pool.name, id: pool.id }, { name: filesystem.name, clones: [] }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Shares, Get:" })); + + let filesystems = { + id: data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) + }; + + $("#spinner-storagepool-filesystem-rename-" + filesystem.id + " span").text("Renaming " + filesystem.type.toLowerCase() + "..."); + + if (filesystems.id.length > 0) { + FnFileSystemRenameCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, createnonexistparents: filesystem.createnonexistparents, force: filesystem.force, namenew: filesystem.namenew, parent: filesystem.parent }, { refresh: false }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Rename:" })); + + if (/dataset already exists/i.test(data) == false) { + $("#spinner-storagepool-filesystem-rename-" + filesystem.id + " span").text("Renaming Samba share" + (filesystems.id.length > 1 ? "s" : "") + "..."); + + FnSambaSharesRename({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, filesystems = { id: filesystems.id, parent: { name: filesystem.name, namenew: filesystem.namenew } }, { restart: samba.restart }, { silent: false }) + .finally(function () { + if (filesystem.createnonexistparents) { + FnFileSystemShareSmbInheritedDisable({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: filesystem.parent }, { disable: true }) + .finally(function () { + $("#modal-storagepool-filesystem-rename-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 500); + }); + } else { + $("#modal-storagepool-filesystem-rename-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 500); + } + }); + } + }); + } else { + FnFileSystemRenameCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, createnonexistparents: filesystem.createnonexistparents, force: filesystem.force, namenew: filesystem.namenew, parent: filesystem.parent }, { refresh: (filesystem.createnonexistparents ? false : true) }) + .done(function () { + if (filesystem.createnonexistparents) { + $("#spinner-storagepool-filesystem-rename-" + filesystem.id + " span").text("Disabling Samba share inheritance..."); + + FnFileSystemShareSmbInheritedDisable({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: filesystem.parent }, { disable: true }) + .finally(function () { + $("#modal-storagepool-filesystem-rename-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 500); + }); + } + }); + } + }) + .fail(function (message, data) { + FnFileSystemRenameFail({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, createnonexistparents: filesystem.createnonexistparents, parent: filesystem.parent }, { data: data, message: message }, { refresh: true }); + }); + } else { + FnFileSystemRenameCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, createnonexistparents: filesystem.createnonexistparents, force: filesystem.force, namenew: filesystem.namenew, parent: filesystem.parent }, { refresh: true }); + } + } +} + +function FnFileSystemRenameCommand(pool = { name, id }, filesystem = { name, id, createnonexistparents: false, force: false, namenew, parent }, display = { refresh: true }) { + let process = { + command: ["/sbin/zfs", "rename", filesystem.name, filesystem.namenew] + }; + + if (filesystem.force) { + process.command.splice(2, 0, "-f"); + } + if (filesystem.createnonexistparents) { + process.command.splice(2, 0, "-p"); + } + + FnConsole.log[1]("File Systems, Rename: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function (data, message) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Rename:" })); + + if (/dataset already exists/i.test(data)) { + FnFileSystemRenameFail({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, createnonexistparents: filesystem.createnonexistparents, parent: filesystem.parent }, { data: data, message: message }, { refresh: true }); + return; + } + + FnDisplayAlert({ status: "success", title: "File System successfully renamed", description: filesystem.name, breakword: false }, { name: "filesystem-rename", id: filesystem.id, timeout: 4 }); + + FnConsole.log[1]("File Systems, Rename: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + + if (display.refresh) { + $("#modal-storagepool-filesystem-rename-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 500); + } + }) + .fail(function (message, data) { + FnFileSystemRenameFail({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, createnonexistparents: filesystem.createnonexistparents, parent: filesystem.parent }, { data: data, message: message }, { refresh: true }); + }); +} + +function FnFileSystemRenameFail(pool = { name, id }, filesystem = { name, id, createnonexistparents: false, parent }, process = { data, message }, display = { refresh: true }) { + let modal = { + hide: true + }; + + if (/dataset already exists/i.test(process.data)) { + modal.hide = false; + + $("#validationwrapper-storagepool-filesystem-rename-name-" + filesystem.id).addClass("has-error"); + $("#helpblock-storagepool-filesystem-rename-name-" + filesystem.id).addClass("has-error").removeClass("hidden").text("Name already exists."); + $("#input-storagepool-filesystem-rename-name-" + filesystem.id).focus(); + } else if (/parent does not exist/i.test(process.data)) { + modal.hide = false; + + $("#validationwrapper-storagepool-filesystem-rename-name-" + filesystem.id).addClass("has-error"); + $("#helpblock-storagepool-filesystem-rename-name-" + filesystem.id).addClass("has-error").removeClass("hidden").text("Parent file system does not exist."); + $("#input-storagepool-filesystem-rename-name-" + filesystem.id).focus(); + } + + if (!modal.hide) { + $("#spinner-storagepool-filesystem-rename-" + filesystem.id).addClass("hidden"); + $("#spinner-storagepool-filesystem-rename-" + filesystem.id + " span").text(""); + $("#btn-storagepool-filesystem-rename-apply-" + filesystem.id).prop("disabled", false); + } + + FnConsole.warn("File Systems, Rename: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (process.data ? process.data : process.message)); + + if (modal.hide) { + FnDisplayAlert({ status: "danger", title: "File System could not be renamed", description: filesystem.name, breakword: false }, { name: "filesystem-rename", id: filesystem.id, timeout: 4 }); + + $("#modal-storagepool-filesystem-rename-" + filesystem.id).modal("hide"); + + if (display.refresh) { + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + } + } +} + +function FnFileSystemSelinuxContextsSambaSet(pool = { name, id }, filesystem = { name }) { + let process = { + command: ["/sbin/zfs", "set", "context=system_u:object_r:samba_share_t:s0", "defcontext=system_u:object_r:samba_share_t:s0", "fscontext=system_u:object_r:samba_share_t:s0", "rootcontext=system_u:object_r:samba_share_t:s0", filesystem.name] + }; + + FnConsole.log[2]("File Systems, SELinux Contexts, Samba, Set: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnConsole.log[1]("File Systems, SELinux Contexts, Samba, Set: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + }) + .fail(function (message, data) { + FnConsole.warn("File Systems, SELinux Contexts, Samba, Set: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); + }) +} + +function FnFileSystemShareSmbDisable(pool = { name, id }, filesystem = { name, id }) { + let process = { + command: ["/sbin/zfs", "set", "sharesmb=off", filesystem.name] + }; + + FnConsole.log[2]("File Systems, Share SMB, Disable: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnConsole.log[1]("File Systems, Share SMB, Disable: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + }) + .fail(function (message, data) { + if (/property may be set/gi.test(data)) { //False error is generated when configuring filesystem + FnConsole.log[1]("File Systems, Share SMB, Disable: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + } else { + FnConsole.warn("File Systems, Share SMB, Disable: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); + } + }); +} + +function FnFileSystemShareSmbEnable(pool = { name, id }, filesystem = { name, id }) { + let process = { + command: ["/sbin/zfs", "set", "sharesmb=on", filesystem.name] + }; + + FnConsole.log[2]("File Systems, Share SMB, Enable: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnConsole.log[1]("File Systems, Share SMB, Enable: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + }) + .fail(function (message, data) { + if (/property may be set/gi.test(data)) { //False error is generated when configuring filesystem + FnConsole.log[1]("File Systems, Share SMB, Enable: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + } else { + FnConsole.warn("File Systems, Share SMB, Enable: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); + } + }); +} + +function FnFileSystemShareSmbInheritedDisable(pool = { name, id, altroot: false }, filesystem = { name }, force = { disable: false }) { + let process = { + command: ["/sbin/zfs", "get", "-H", "name,sharesmb", "-o", "property,value,source", "-r", "-t", "filesystem"], + promise: cockpit.defer() + }; + + if (filesystem.name) { + process.command.push(filesystem.name); + } else if (pool.name) { + process.command.push(pool.name); + } + + FnConsole.log[2]("File Systems, Share SMB, Inherited, Disable: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Share SMB, Inherited, Disable:" })); + + let filesystems = data.replace(/\nsharesmb/g, "\u22C5sharesmb").replace(/\t+/g, "\u22C5").split(/\n/g).filter(v => v && /\u22C5sharesmb\u22C5on\u22C5inherited from|\u22C5sharesmb\u22C5off\u22C5inherited from/gi.test(v)); + let promise = Promise.resolve(); + + if (filesystems.length > 0) { + filesystems.forEach((_value, _index) => { + _value = _value.split("\u22C5"); + + let filesystem = { + name: _value[1], + id: FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: _value[1], attribute: true }), + sharesmb: { + enabled: (_value[4].toLowerCase() == "on" ? true : false), + source: _value[5] + } + }; + let pool = { + name: filesystem.name.replace(/\/.*$/, ""), + id: FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: filesystem.name, attribute: true }) + }; + + promise = promise.then(_ => new Promise(resolve => + setTimeout(function () { + if (filesystem.sharesmb.enabled && !force.disable) { + FnFileSystemShareSmbEnable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }) + .finally(function () { + if (_index == (filesystems.length - 1)) { + FnConsole.log[1]("File Systems, Share SMB, Inherited, Disable: Success"); + + process.promise.resolve(); + } + }); + } else { + if (force.disable) { + FnSambaShareDisable({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { name: filesystem.name, id: filesystem.id }, { restart: false }, { modal: false, silent: true }); + + if (_index == (filesystems.length - 1)) { + setTimeout(function () { + FnConsole.log[1]("File Systems, Share SMB, Inherited, Disable: Success"); + + process.promise.resolve(); + }, 1000); + } + } else { + FnFileSystemShareSmbDisable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }) + .finally(function () { + if (_index == (filesystems.length - 1)) { + FnConsole.log[1]("File Systems, Share SMB, Inherited, Disable: Success"); + + process.promise.resolve(); + } + }); + } + } + + resolve(); + }, (force.disable ? 1000 : 500)) + )); + }); + } else { + FnConsole.log[1]("File Systems, Share SMB, Inherited, Disable: Success" + (pool.name ? ", Pool: " + pool.name : "")); + + process.promise.resolve(); + } + }) + .fail(function (message, data) { + FnConsole.warn("File Systems, Share SMB, Inherited, Disable: Failed" + ", Message: " + (data ? data : message)); + + process.promise.resolve(); + }); + + return process.promise.promise(); +} + +function FnFileSystemUnlock(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, mount: true, overlay: true, passphrase, type }, samba = { enable: false }, modal = { name, id }, display = { refresh: true }) { + let process = { + command: [] + }; + + modal.id = (modal.id ? "-" + modal.id : ""); + + //Escape percentage and single quote special character for printf + if (/\%/g.test(filesystem.passphrase)) { + filesystem.passphrase = filesystem.passphrase.replace(/\%/g, "\%\%"); + } + if (/\'/g.test(filesystem.passphrase)) { + filesystem.passphrase = filesystem.passphrase.replace(/\'/g, "\'\"\'\"\'"); + } + + process.command = ["/bin/sh", "-c", "printf '" + filesystem.passphrase + "' | /sbin/zfs load-key \"" + filesystem.name + "\""]; + + FnConsole.log[2]("File Systems, Unlock: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + if (display.refresh) { + $("#spinner-" + modal.name + modal.id + " span").text("Unlocking " + filesystem.type.toLowerCase() + "..."); + } + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function (data, message) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Unlock:" })); + + if (/error|Incorrect key/i.test(data)) { + FnFileSystemUnlockFail({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, type: filesystem.type }, { name: modal.name, id: modal.id }, { refresh: display.refresh }, { data: data, message: message }); + return; + } + + FnDisplayAlert({ status: "success", title: "File System successfully unlocked", description: filesystem.name, breakword: false }, { name: "filesystem-unlock", id: filesystem.id, timeout: 4 }); + + FnConsole.log[1]("File Systems, Unlock: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + + if (filesystem.mount) { + setTimeout(function () { + FnFileSystemMount({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, overlay: filesystem.overlay, type: filesystem.type }, { enable: samba.enable }, { refresh: display.refresh }) + .finally(function () { + if (display.refresh) { + $("#modal-" + modal.name + modal.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + } + }); + }, 200); + } else if (display.refresh) { + $("#modal-" + modal.name + modal.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + } + }) + .fail(function (message, data) { + if (/Key already loaded/i.test(data)) { + FnFileSystemUnlockWarn({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, mount: filesystem.mount, overlay: filesystem.overlay, type: filesystem.type }, { enable: samba.enable }, { name: modal.name, id: modal.id }, { refresh: display.refresh }, { data: data, message: message }); + } else { + FnFileSystemUnlockFail({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, type: filesystem.type }, { name: modal.name, id: modal.id }, { refresh: display.refresh }, { data: data, message: message }); + } + }); +} + +function FnFileSystemUnlockFail(pool = { name, id }, filesystem = { name, id, type }, modal = { name, id }, display = { refresh: true }, process = { data, message }) { + modal.hide = true; + + if (/Incorrect key provided/gi.test(process.data)) { + modal.hide = false; + + $("#validationwrapper-" + modal.name + "-passphrase" + modal.id).addClass("has-error"); + $("#helpblock-" + modal.name + "-passphrase" + modal.id).addClass("has-error").removeClass("hidden").text("Passphrase is incorrect."); + $("#input-" + modal.name + "-passphrase" + modal.id).focus(); + } + + if (!modal.hide && display.refresh) { + $("#spinner-" + modal.name + modal.id).addClass("hidden"); + $("#spinner-" + modal.name + modal.id + " span").text(""); + $("#btn-" + modal.name + "-apply" + modal.id).prop("disabled", false); + } + + if (modal.hide || !display.refresh) { + FnDisplayAlert({ status: "danger", title: "File System could not be unlocked", description: filesystem.name, breakword: false }, { name: "filesystem-unlock", id: filesystem.id, timeout: 4 }); + } + + if (modal.hide) { + if (display.refresh) { + $("#modal-" + modal.name + modal.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + } + } + + FnConsole.warn("File Systems, Unlock: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (process.data ? process.data : process.message)); +} + +function FnFileSystemUnlockWarn(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, mount: true, overlay: true, type }, samba = { enable: false }, modal = { name, id }, display = { refresh: true }, process = { data, message }) { + FnDisplayAlert({ status: "warning", title: "File System was already unlocked", description: filesystem.name, breakword: false }, { name: "filesystem-unlock", id: filesystem.id, timeout: 4 }); + + FnConsole.warn("File Systems, Unlock: Warning, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (process.data ? process.data : process.message)); + + if (filesystem.mount) { + setTimeout(function () { + FnFileSystemMount({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, overlay: filesystem.overlay, type: filesystem.type }, { enable: samba.enable }, { refresh: display.refresh }) + .finally(function () { + if (display.refresh) { + $("#modal-" + modal.name + modal.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + } + }); + }, 200); + } else if (display.refresh) { + $("#modal-" + modal.name + modal.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + } +} + +function FnFileSystemUnmount(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, force: false, lock: false, type }, samba = { disable: false, restart: false }) { + if (samba.restart) { + FnSambaStop() + .finally(function () { + $("#spinner-storagepool-filesystem-unmount-" + filesystem.id + " span").text("Unmounting " + filesystem.type.toLowerCase() + "..."); + + FnFileSystemUnmountCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, force: filesystem.force, lock: filesystem.lock }, { refresh: ((filesystem.lock || samba.disable) ? false : true) }) + .done(function () { + if (filesystem.lock) { + $("#spinner-storagepool-filesystem-unmount-" + filesystem.id + " span").text("Locking " + filesystem.type.toLowerCase() + "..."); + + FnFileSystemLock({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, type: filesystem.type }, { refresh: false }) + .finally(function () { + if (samba.disable) { + $("#spinner-storagepool-filesystem-unmount-" + filesystem.id + " span").text("Disabling Samba share..."); + + if (zfsmanager.configuration.samba.manage) { + FnSambaShareDisable({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id }, { restart: samba.restart }, { modal: false, silent: false }); + } else { + FnFileSystemShareSmbDisable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }); + } + } + + setTimeout(function () { + $("#modal-storagepool-filesystem-unmount-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + }, (samba.disable ? 1000 : 200)); + }); + } else { + if (samba.disable) { + $("#spinner-storagepool-filesystem-unmount-" + filesystem.id + " span").text("Disabling Samba share..."); + + if (zfsmanager.configuration.samba.manage) { + FnSambaShareDisable({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id }, { restart: samba.restart }, { modal: false, silent: false }); + } else { + FnFileSystemShareSmbDisable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }); + } + } + + setTimeout(function () { + $("#modal-storagepool-filesystem-unmount-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + }, (samba.disable ? 1000 : 200)); + } + }) + .finally(function () { + if (!samba.disable || !zfsmanager.configuration.samba.manage) { + FnSambaStart(); + } + }); + }); + } else { + $("#spinner-storagepool-filesystem-unmount-" + filesystem.id + " span").text("Unmounting " + filesystem.type.toLowerCase() + "..."); + + FnFileSystemUnmountCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, force: filesystem.force, lock: filesystem.lock }, { refresh: ((filesystem.lock || samba.disable) ? false : true) }) + .done(function () { + if (filesystem.lock) { + $("#spinner-storagepool-filesystem-unmount-" + filesystem.id + " span").text("Locking " + filesystem.type.toLowerCase() + "..."); + + FnFileSystemLock({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, type: filesystem.type }, { refresh: false }) + .finally(function () { + if (samba.disable) { + $("#spinner-storagepool-filesystem-unmount-" + filesystem.id + " span").text("Disabling Samba share..."); + + if (zfsmanager.configuration.samba.manage) { + FnSambaShareDisable({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id }, { restart: samba.restart }, { modal: false, silent: false }); + } else { + FnFileSystemShareSmbDisable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }); + } + } + + setTimeout(function () { + $("#modal-storagepool-filesystem-unmount-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + }, (samba.disable ? 1000 : 200)); + }); + } else { + if (samba.disable) { + $("#spinner-storagepool-filesystem-unmount-" + filesystem.id + " span").text("Disabling Samba share..."); + + if (zfsmanager.configuration.samba.manage) { + FnSambaShareDisable({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id }, { restart: samba.restart }, { modal: false, silent: false }); + } else { + FnFileSystemShareSmbDisable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }); + } + } + + setTimeout(function () { + $("#modal-storagepool-filesystem-unmount-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + }, (samba.disable ? 1000 : 200)); + } + }); + } +} + +function FnFileSystemUnmountCommand(pool = { name, id }, filesystem = { name, id, force: false, lock: false }, display = { refresh: true }) { + let process = { + command: ["/sbin/zfs", "unmount", filesystem.name] + }; + + if (filesystem.force) { + process.command.splice(2, 0, "-f"); + } + + FnConsole.log[2]("File Systems, Unmount: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "File System successfully unmounted", description: filesystem.name, breakword: false }, { name: "filesystem-unmount", id: filesystem.id, timeout: 4 }); + + FnConsole.log[1]("File Systems, Unmount: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + + if (display.refresh) { + $("#modal-storagepool-filesystem-unmount-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + } + }) + .fail(function (message, data) { + FnDisplayAlert({ status: "danger", title: "File System could not be unmounted", description: filesystem.name, breakword: false }, { name: "filesystem-unmount", id: filesystem.id, timeout: 4 }); + + FnConsole.warn("File Systems, Unmount: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); + + $("#modal-storagepool-filesystem-unmount-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + }); +} + +//#endregion + +//#region Snapshots + +function FnSnapshotsGet(pool = { name, id }) { + let process = { + command: ["/sbin/zfs", "list", "-H", "-o", "name,creation,used,refer,encryption,encryptionroot,keystatus,clones", "-r", "-p", "-t", "snapshot", pool.name] + }; + let snapshots = { + empty: true + }; + + pool.altroot = (($("#tr-storagepool-" + pool.id).attr("data-pool-altroot") == "true") ? true : false); + pool.readonly = (($("#tr-storagepool-" + pool.id).attr("data-pool-readonly") == "true") ? true : false); + + FnConsole.log[2]("Snapshots, Get: In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data, message) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Snapshots, Get:" })); + + if (data) { + snapshots.empty = false; + + FnSnapshotsGetCommand({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { data: data, message: message }); + } + + FnConsole.log[1]("Snapshots, Get: Success, Pool: " + pool.name); + }) + .fail(function (message, data) { + FnConsole.warn("Snapshots, Get: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); + }) + .finally(function () { + if (snapshots.empty) { + if (zfsmanager.configuration.zfs.snapshot.filesystemlist) { + $("#div-storagepool-snapshots-" + pool.id).empty(); + } + $("#tbody-storagepool-snapshots-" + pool.id).empty(); + $("#" + (zfsmanager.configuration.zfs.snapshot.filesystemlist ? "div" : "tbody") + "-storagepool-snapshots-" + pool.id).append((zfsmanager.configuration.zfs.snapshot.filesystemlist ? `` : ``) + `` + (zfsmanager.configuration.zfs.snapshot.filesystemlist ? `
    No snapshots found.
    ` : ``)); + $("#modals-storagepool-snapshots-" + pool.id).remove(); + $("#modals-storagepool-snapshot-" + pool.id).remove(); + $("#modals").append(`
    `); + + //Register snapshots modals + if (!pool.readonly) { + FnModalSnaphshotsCreate({ name: pool.name, id: pool.id }); + } + + $("#tr-storagepool-" + pool.id).attr("data-pool-refresh-snapshots", "true"); + + $("#spinner-storagepool-snapshots-" + pool.id).addClass("hidden"); + $("#paneltitle-storagepool-snapshots-" + pool.id).removeClass("hidden").text(FnDateTime()); + $("#btn-storagepool-snapshots-create-" + pool.id).prop("disabled", false); + $("#btn-storagepool-snapshots-refresh-" + pool.id).prop("disabled", false); + } + + FnStoragePoolSpinnerHide({ name: pool.name, id: pool.id }); + FnCockpitElementsUpdate(); + }); +} + +function FnSnapshotsGetCommand(pool = { name, id, altroot: false, readonly: false }, process = { data, message }) { + let snapshots = { + data: process.data.split(/\n/g).filter(v => v), + filesystemlist: { + count: 0, + name: "" + } + }; + + if (zfsmanager.configuration.zfs.snapshot.filesystemlist) { + $("#div-storagepool-snapshots-" + pool.id).empty(); + } + $("#tbody-storagepool-snapshots-" + pool.id).empty(); + $("#modals-storagepool-snapshots-" + pool.id).remove(); + $("#modals-storagepool-snapshot-" + pool.id).remove(); + $("#modals").append(`
    `); + $("#modals").append(`
    `); + + snapshots.data.forEach((_value, _index) => { + let snapshot = { + properties: _value.split(/\t/g).filter(v => v), + clones: [], + creation: "", + encryption: false, + encryptionroot: "", + id: "", + keystatus: "", + name: "", + actionsmenu: { + register: {} + } + }; + + if (!snapshot.properties[7]) { //Append clones property if not included after split + snapshot.properties[7] = ""; + } + + snapshot.filesystem = { + id: FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: snapshot.properties[0].replace(/^(.*)\@.*$/, "$1"), attribute: true }) + }; + + snapshot.output = ""; + + if (zfsmanager.configuration.zfs.snapshot.filesystemlist) { + if (_index == 0 || (snapshots.filesystemlist.name != "" && snapshots.filesystemlist.name != snapshot.properties[0].replace(/^(.*)\@.*$/, "$1"))) { + snapshot.output += ` + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#table-storagepool-snapshots-listing-` + snapshot.filesystem.id + ` > tbody > tr.listing-ct-item").on("click", function () { + if (!$(this).parent().hasClass("open")) { + $(this).parent().addClass("open"); + } else { + $(this).parent().removeClass("open"); + } + }); + \x3C/script> + + + + + + + + + +
    Name:` + snapshot.properties[0].replace(/^(.*)\@.*$/, "$1") + (zfsmanager.configuration.zfs.storagepool.count ? ` ` : ``) + `
    + + +
    +
    + `; + + $("#div-storagepool-snapshots-" + pool.id).append(snapshot.output); + + snapshot.output = ""; + snapshots.filesystemlist.count = 0; + } + + snapshots.filesystemlist.count++; + $("#span-storagepool-snapshots-listing-" + snapshot.filesystem.id + "-count").html(snapshots.filesystemlist.count); + } + + snapshot.output += ``; + + snapshot.properties.forEach((__value, __index) => { + //0=name, 1=creation, 2=used, 3=refer, 4=encryption, 5=encryptionroot, 6=keystatus, 7=clones + + switch (__index) { + case 0: //0=name + snapshot.name = __value; + snapshot.id = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: snapshot.name, attribute: true }); + + snapshot.output += `Name:` + __value + ``; + break; + case 1: //1=creation + snapshot.creation = __value; + + snapshot.output += `Created:` + FnDateTimeEpoch({ date: __value }) + ``; + break; + case 2: //2=used + snapshot.output += `Used:` + FnFormatBytes({ base2: true, decimals: 2, value: __value }) + ``; + break; + case 3: //3=refer + snapshot.output += `Referenced:` + FnFormatBytes({ base2: true, decimals: 2, value: __value }) + ``; + break; + case 4: //4=encryption + if (__value.toLowerCase() != "off") { + snapshot.encryption = true; + } else { + snapshot.encryption = false; + } + break; + case 5: //5=encryptionroot + snapshot.encryptionroot = __value; + break; + case 6: //6=keystatus + snapshot.keystatus = __value; + break; + case 7: //7=clones + snapshot.clones = __value.split(",").filter(v => v).sort(); + + snapshot.output += `Clones:` + (snapshot.clones.length > 0 ? snapshot.clones.join(", ") : `None`) + ``; + break; + } + + //Add action menu at end of array + if (__index >= (snapshot.properties.length - 1)) { + snapshot.icons = { + keystatus: { + locked: ``, + unlocked: `` + } + }; + + snapshot.output += `Encrypted:` + (/available|unavailable/.test(snapshot.keystatus) ? `Yes` : `No`) + ``; + + if (snapshot.keystatus == "unavailable") { + snapshot.output += snapshot.icons.keystatus.locked; + } else if (snapshot.keystatus == "available") { + snapshot.output += snapshot.icons.keystatus.unlocked; + } + + snapshot.output += ``; + + //Actions menu + snapshot.actionsmenu.items = { + item: [], + itemdivider: function () { + if (this.item.length > 0 && this.itemdestroy.length > 0) { + this.item.push(this.divider); + } + }, + itemdestroy: [], + divider: `` + }; + snapshot.actionsmenu.display = function () { + if ((this.items.item.length + this.items.itemdestroy.length) > 0 || pool.readonly) { + this.items.itemdivider(); + + return this.header + this.items.item.join("\n") + this.items.itemdestroy.join("\n") + this.footer; + } else { + return ""; + } + }; + snapshot.actionsmenu.header = ` + + `; + + //Clone Snapshot + if (!pool.readonly) { + snapshot.actionsmenu.items.item.push(`
  • Clone Snapshot
  • `); + + snapshot.actionsmenu.register.clone = true; + } + + //Rename Snapshot + if (!pool.readonly && snapshot.name != pool.name) { + snapshot.actionsmenu.items.item.push(`
  • Rename Snapshot
  • `); + + snapshot.actionsmenu.register.rename = true; + } + + //Roll Back Snapshot + if (!pool.readonly) { + snapshot.actionsmenu.items.item.push(`
  • Roll Back Snapshot
  • `); + + snapshot.actionsmenu.register.rollback = true; + } + + //Destroy Snapshot + if (!pool.readonly) { + snapshot.actionsmenu.items.itemdestroy.push(`
  • Destroy Snapshot
  • `); + + snapshot.actionsmenu.register.destroy = true; + } + + snapshot.output += `` + snapshot.actionsmenu.display() + ``; + } + }); + + snapshot.output += ``; + + if (zfsmanager.configuration.zfs.snapshot.filesystemlist) { + $("#tbody-storagepool-snapshots-list-" + snapshot.filesystem.id).append(snapshot.output); + + snapshots.filesystemlist.name = snapshot.properties[0].replace(/^(.*)\@.*$/, "$1"); + } else { + $("#tbody-storagepool-snapshots-" + pool.id).append(snapshot.output); + } + + + //Register snapshot modals + if (snapshot.actionsmenu.register.clone) { + FnModalSnapshotClone({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: snapshot.name, id: snapshot.id, encryption: snapshot.encryption, encryptionroot: snapshot.encryptionroot }); + } + if (snapshot.actionsmenu.register.destroy) { + FnModalSnapshotDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: snapshot.name, id: snapshot.id, clones: snapshot.clones }); + } + if (snapshot.actionsmenu.register.rename) { + FnModalSnapshotRename({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, creation: snapshot.creation }); + } + if (snapshot.actionsmenu.register.rollback) { + FnModalSnapshotRollBack({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: snapshot.name, id: snapshot.id, creation: snapshot.creation }); + } + }); + + //Register snapshots modals + if (!pool.readonly) { + FnModalSnaphshotsCreate({ name: pool.name, id: pool.id }); + } + + $("#tr-storagepool-" + pool.id).attr("data-pool-refresh-snapshots", "true"); + + $("#spinner-storagepool-snapshots-" + pool.id).addClass("hidden"); + $("#paneltitle-storagepool-snapshots-" + pool.id).removeClass("hidden").html(FnDateTime() + (zfsmanager.configuration.zfs.storagepool.count ? ` ` + snapshots.data.length + `` : ``)); + $("#btn-storagepool-snapshots-create-" + pool.id).prop("disabled", false); + $("#btn-storagepool-snapshots-refresh-" + pool.id).prop("disabled", false); + + FnStoragePoolSpinnerHide({ name: pool.name, id: pool.id }); + FnCockpitElementsUpdate(); +} + +//#endregion + +//#region Snapshot + +function FnSnapshotChildFileSystemsGet(pool = { name, id }, snapshot = { name, id }, filesystems = { id: [] }, modal = { name, id }) { + let process = { + command: ["/sbin/zfs", "list", "-H", "-o", "name", "-r", "-t", "filesystem"] + }; + + filesystems.id.forEach(_value => _value && process.command.push(_value)); + + FnConsole.log[2]("Snapshots, Child, File Systems, Get: In Progress, Pool: " + pool.name + ", Snapshot: " + snapshot.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Snapshots, Child, File Systems, Get:" })); + + let filesystems = { + id: data.split(/\n/g).filter(v => v), + count: { + filesystems: 0 + } + }; + + if (filesystems.id.length > 0) { + filesystems.id.forEach((_value, _index) => { + if (_value != snapshot.name.replace(/^(.*)\@.*$/, "$1")) { + filesystems.count.filesystems++; + + $("#ul-" + modal.name + "-child-filesystems-" + modal.id).append("
  • " + _value + "
  • \n"); + } + }); + + $("#panelgroup-" + modal.name + "-" + modal.id).attr("data-snapshot-child-filesystems", filesystems.count.filesystems); + } + + FnConsole.log[1]("Snapshots, Child, File Systems, Get: Success, Pool: " + pool.name + ", Snapshot: " + snapshot.name); + }) + .fail(function (message, data) { + FnConsole.warn("Snapshots, Child, File Systems, Get: Failed, Pool: " + pool.name + ", Snapshot: " + snapshot.name + ", Message: " + (data ? data : message)); + }); +} + +function FnSnapshotChildSnapshotsGet(pool = { name, id }, snapshot = { name, id, exclude: false }, filesystems = { id: [] }, modal = { name, id }) { + let process = { + command: ["/sbin/zfs", "list", "-H", "-o", "name", "-r", "-t", "snapshot"] + }; + + if (!snapshot.exclude) { + process.command.push(snapshot.name.replace(/^(.*)\@.*$/, "$1")); + } + + filesystems.id.forEach(_value => _value && process.command.push(_value)); + + FnConsole.log[2]("Snapshots, Child, Snapshots, Get: In Progress, Pool: " + pool.name + ", Snapshot: " + snapshot.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Snapshots, Child, Snapshots, Get:" })); + + let snapshots = { + id: data.split(/\n/g).filter(v => v), + count: { + snapshots: 0, + snapshotswithclones: (snapshot.exclude ? $("#panelgroup-" + modal.name + "-" + modal.id).attr("data-snapshot-child-snapshotswithclones") : 0) //Exclude for Roll Back and append + } + }; + + if (snapshots.id.length > 0) { + snapshots.id.forEach((_value, _index) => { + if (_value != snapshot.name) { + //Recursive all will delete child file system snapshots with same name only. If clones are also found, all clone snapshots will be deleted + if (new RegExp("^" + snapshot.name.replace(/^(.*)\@.*$/, "$1") + "/.*@" + snapshot.name.replace(/^.*\@(.*)$/, "$1") + "$").test(_value)) { //Child file system snapshots with same name + if (!snapshot.exclude) { + snapshots.count.snapshots++; + + $("#ul-" + modal.name + "-child-snapshots-" + modal.id).append("
  • " + _value + "
  • \n"); + } + + snapshots.count.snapshotswithclones++; + + $("#ul-" + modal.name + "-child-snapshotswithclones-" + modal.id).append("
  • " + _value + "
  • \n"); + } else { + filesystems.id.forEach((__value, __index) => { + if (new RegExp("^" + __value.replace(/^(.*)\@.*$/, "$1") + "@").test(_value) || new RegExp("^" + __value.replace(/^(.*)\@.*$/, "$1") + "/.*@").test(_value)) { //Snapshots of clone file system + snapshots.count.snapshotswithclones++; + + $("#ul-" + modal.name + "-child-snapshotswithclones-" + modal.id).append("
  • " + _value + "
  • \n"); + } + }); + } + } + }); + + if (!snapshot.exclude) { + $("#panelgroup-" + modal.name + "-" + modal.id).attr("data-snapshot-child-snapshots", snapshots.count.snapshots); + } + $("#panelgroup-" + modal.name + "-" + modal.id).attr("data-snapshot-child-snapshotswithclones", snapshots.count.snapshotswithclones); + } + + FnConsole.log[1]("Snapshots, Child, Snapshots, Get: Success, Pool: " + pool.name + ", Snapshot: " + snapshot.name); + }) + .fail(function (message, data) { + FnConsole.warn("Snapshots, Child, Snapshots, Get: Failed, Pool: " + pool.name + ", Snapshot: " + snapshot.name + ", Message: " + (data ? data : message)); + }); +} + +function FnSnapshotClone(pool = { name, id, altroot: false }, snapshot = { name, id, clone: { name, createnonexistparents: false, parent } }) { + let process = { + command: ["/sbin/zfs", "clone", "-o", "sharenfs=off", "-o", "sharesmb=off", snapshot.name, snapshot.clone.name] + }; + + if (snapshot.clone.createnonexistparents) { + process.command.splice(2, 0, "-p"); + } + + FnConsole.log[2]("Snapshots, Clone: In Progress, Pool: " + pool.name + ", Snapshot: " + snapshot.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-storagepool-snapshot-clone-" + snapshot.id + " span").text("Cloning snapshot..."); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function (data, message) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Snapshots, Clone:" })); + + if (/dataset already exists/i.test(data)) { + FnSnapshotCloneFail({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id }, { data: data, message: message }); + return; + } + + FnDisplayAlert({ status: "success", title: "Snapshot successfully cloned", description: snapshot.name, breakword: false }, { name: "snapshot-clone", id: snapshot.id, timeout: 4 }); + + FnConsole.log[1]("Snapshots, Clone: Success, Pool: " + pool.name + ", Snapshot: " + snapshot.name); + + if (snapshot.clone.createnonexistparents && zfsmanager.configuration.samba.manage) { + $("#spinner-storagepool-snapshot-clone-" + snapshot.id + " span").text("Disabling Samba share inheritance..."); + + FnFileSystemShareSmbInheritedDisable({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: snapshot.clone.parent }, { disable: true }) + .finally(function () { + $("#modal-storagepool-snapshot-clone-" + snapshot.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + }); + } else { + $("#modal-storagepool-snapshot-clone-" + snapshot.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + } + }) + .fail(function (message, data) { + FnSnapshotCloneFail({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id }, { data: data, message: message }); + }); +} + +function FnSnapshotCloneFail(pool = { name, id }, snapshot = { name, id }, process = { data, message }) { + let modal = { + hide: true + }; + + if (/filesystem successfully created/gi.test(process.data)) { + FnDisplayAlert({ status: "warning", title: "Snapshot cloned with errors", description: snapshot.name, breakword: false }, { name: "snapshot-clone", id: snapshot.id, timeout: 4 }); + + FnConsole.warn("Snapshots, Clone: Warning, Pool: " + pool.name + ", Snapshot: " + snapshot.name + ", Message: " + (process.data ? process.data : process.message)); + } else { + if (/dataset already exists/i.test(process.data)) { + modal.hide = false; + + $("#validationwrapper-storagepool-snapshot-clone-name-" + snapshot.id).addClass("has-error"); + $("#helpblock-storagepool-snapshot-clone-name-" + snapshot.id).addClass("has-error").removeClass("hidden").text("Name already exists."); + $("#input-storagepool-snapshot-clone-name-" + snapshot.id).focus(); + } else if (/parent does not exist/i.test(process.data)) { + modal.hide = false; + + $("#validationwrapper-storagepool-snapshot-clone-name-" + snapshot.id).addClass("has-error"); + $("#helpblock-storagepool-snapshot-clone-name-" + snapshot.id).addClass("has-error").removeClass("hidden").text("Parent file system does not exist."); + $("#input-storagepool-snapshot-clone-name-" + snapshot.id).focus(); + } + + if (modal.hide) { + FnDisplayAlert({ status: "danger", title: "Snapshot could not be cloned", description: snapshot.name, breakword: false }, { name: "snapshot-clone", id: snapshot.id, timeout: 4 }); + } + + FnConsole.warn("Snapshots, Clone: Failed, Pool: " + pool.name + ", Snapshot: " + snapshot.name + ", Message: " + (process.data ? process.data : process.message)); + } + + if (!modal.hide) { + $("#spinner-storagepool-snapshot-clone-" + snapshot.id).addClass("hidden"); + $("#spinner-storagepool-snapshot-clone-" + snapshot.id + " span").text(""); + $("#btn-storagepool-snapshot-clone-apply-" + snapshot.id).prop("disabled", false); + } + + if (modal.hide) { + $("#modal-storagepool-snapshot-clone-" + snapshot.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + } +} + +function FnSnapshotCreate(pool = { name, id }, snapshot = { name, id, recursive: false }, modal = { name, id }) { + let process = { + command: ["/sbin/zfs", "snapshot", snapshot.name] + }; + + modal.hide = true; + + if (snapshot.recursive) { + process.command.splice(2, 0, "-r"); + } + + FnConsole.log[2]("Snapshots, Create: In Progress, Pool: " + pool.name + ", Snapshot: " + snapshot.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-" + modal.name + "-" + modal.id + " span").text("Creating snapshot" + (snapshot.recursive ? "s" : "") + "..."); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "Snapshot successfully created", description: snapshot.name, breakword: false }, { name: "snapshot-create", id: snapshot.id, timeout: 4 }); + + FnConsole.log[1]("Snapshots, Create: Success, Pool: " + pool.name + ", Snapshot: " + snapshot.name); + }) + .fail(function (message, data) { + if (/dataset already exists/gi.test(data)) { + modal.hide = false; + + $("#validationwrapper-" + modal.name + "-name-" + modal.id).addClass("has-error"); + $("#helpblock-" + modal.name + "-name-" + modal.id).addClass("has-error").removeClass("hidden").text("Name already exists."); + $("#input-" + modal.name + "-name-" + modal.id).focus(); + } + + if (!modal.hide) { + $("#spinner-" + modal.name + "-" + modal.id).addClass("hidden"); + $("#spinner-" + modal.name + "-" + modal.id + " span").text(""); + $("#btn-" + modal.name + "-apply-" + modal.id).prop("disabled", false); + } + + if (modal.hide) { + FnDisplayAlert({ status: "danger", title: "Snapshot could not be created", description: snapshot.name, breakword: false }, { name: "snapshot-create", id: snapshot.id, timeout: 4 }); + } + + FnConsole.warn("Snapshots, Create: Failed, Pool: " + pool.name + ", Snapshot: " + snapshot.name + ", Message: " + (data ? data : message)); + }) + .finally(function () { + if (modal.hide) { + setTimeout(function () { + $("#modal-" + modal.name + "-" + modal.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + }, 700); + } + }); +} + +function FnSnapshotCreateDateGet(pool = { name, id }, snapshot = { name, id, recursive: false }, modal = { name, id }) { + let process = { + command: ["/bin/date", "\+\%Y.\%m.\%d-\%H.\%M.\%S"] + }; + + snapshot.date = ""; + + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-" + modal.name + "-" + modal.id + " span").text("Creating snapshot" + (snapshot.recursive ? "s" : "") + "..."); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Snapshots, Create, Date, Get:" })); + + snapshot.date = data.replace(/[ \t\n]+/g, ""); + }) + .fail(function () { + snapshot.date = FnDateTimeSnapshot({ date: null }); + }) + .finally(function () { + snapshot.name = snapshot.name.replace(/^(.*)\@.*$/, "$1") + "@" + snapshot.date; + snapshot.id = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: snapshot.name, attribute: true }); + + $("#input-" + modal.name + "-name-" + modal.id).val(snapshot.date); + + FnSnapshotCreate({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, recursive: snapshot.recursive }, { name: modal.name, id: modal.id }); + }); +} + +function FnSnapshotDestroy(pool = { name, id, altroot: false, readonly: false }, snapshot = { name, id, clones: [], recursive: false, recursiveall: false }, samba = { restart: false }) { + if (samba.restart) { + FnSambaStop() + .finally(function () { + if (snapshot.recursiveall && snapshot.clones.length > 0 && zfsmanager.configuration.samba.manage) { + $("#spinner-storagepool-snapshot-destroy-" + snapshot.id + " span").text("Retrieving Samba shares..."); + + FnSambaSharesGet({ name: pool.name, id: pool.id }, { name: null, clones: snapshot.clones }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Shares, Get:" })); + + let filesystems = { + id: data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) + }; + + $("#spinner-storagepool-snapshot-destroy-" + snapshot.id + " span").text("Destroying snapshot..."); + + if (filesystems.id.length > 0) { + FnSnapshotDestroyCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: false }) + .done(function () { + $("#spinner-storagepool-snapshot-destroy-" + snapshot.id + " span").text("Destroying Samba shares..."); + + FnSambaSharesDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { id: filesystems.id }, { restart: samba.restart }, { silent: false }) + .finally(function () { + $("#modal-storagepool-snapshot-destroy-" + snapshot.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + }); + }); + } else { + $("#spinner-storagepool-snapshot-destroy-" + snapshot.id + " span").text("Destroying snapshot..."); + + FnSnapshotDestroyCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: true }) + .finally(function () { + FnSambaStart(); + }); + } + }) + .fail(function (message, data) { + FnSnapshotDestroyFail({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id }, { data: data, message: message }, { refresh: true }); + FnSambaStart(); + }); + } else { + $("#spinner-storagepool-snapshot-destroy-" + snapshot.id + " span").text("Destroying snapshot..."); + + FnSnapshotDestroyCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: true }) + .finally(function () { + FnSambaStart(); + }); + } + }); + } else { + if (snapshot.recursiveall && snapshot.clones.length > 0 && zfsmanager.configuration.samba.manage) { + $("#spinner-storagepool-snapshot-destroy-" + snapshot.id + " span").text("Retrieving Samba shares..."); + + FnSambaSharesGet({ name: pool.name, id: pool.id }, { name: null, clones: snapshot.clones }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Shares, Get:" })); + + let filesystems = { + id: data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) + }; + + $("#spinner-storagepool-snapshot-destroy-" + snapshot.id + " span").text("Destroying snapshot..."); + + if (filesystems.id.length > 0) { + FnSnapshotDestroyCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: false }) + .done(function () { + $("#spinner-storagepool-snapshot-destroy-" + snapshot.id + " span").text("Destroying Samba shares..."); + + FnSambaSharesDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { id: filesystems.id }, { restart: samba.restart }, { silent: false }) + .finally(function () { + $("#modal-storagepool-snapshot-destroy-" + snapshot.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + }); + }); + } else { + $("#spinner-storagepool-snapshot-destroy-" + snapshot.id + " span").text("Destroying snapshot..."); + + FnSnapshotDestroyCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: true }); + } + }) + .fail(function (message, data) { + FnSnapshotDestroyFail({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id }, { data: data, message: message }, { refresh: true }); + }); + } else { + $("#spinner-storagepool-snapshot-destroy-" + snapshot.id + " span").text("Destroying snapshot..."); + + FnSnapshotDestroyCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: true }); + } + } +} + +function FnSnapshotDestroyCommand(pool = { name, id }, snapshot = { name, id, recursive: false, recursiveall: false }, display = { refresh: true }) { + let process = { + command: ["/sbin/zfs", "destroy", snapshot.name] + }; + + if (snapshot.recursive) { + process.command.splice(2, 0, "-r"); + } + if (snapshot.recursiveall) { + process.command.splice(2, 0, "-R"); + } + + FnConsole.log[1]("Snapshots, Destroy: In Progress, Pool: " + pool.name + ", Snapshot: " + snapshot.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "Snapshot successfully destroyed", description: snapshot.name, breakword: false }, { name: "snapshot-destroy", id: snapshot.id, timeout: 4 }); + + FnConsole.log[1]("Snapshots, Destroy: Success, Pool: " + pool.name + ", Snapshot: " + snapshot.name); + }) + .fail(function (message, data) { + FnSnapshotDestroyFail({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id }, { data: data, message: message }, { refresh: false }); + + display.refresh = true; + }) + .finally(function () { + if (display.refresh) { + $("#modal-storagepool-snapshot-destroy-" + snapshot.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + } + }); +} + +function FnSnapshotDestroyFail(pool = { name, id }, snapshot = { name, id }, process = { data, message }, display = { refresh: true }) { + FnDisplayAlert({ status: "danger", title: "Snapshot could not be destroyed", description: snapshot.name, breakword: false }, { name: "snapshot-destroy", id: snapshot.id, timeout: 4 }); + + FnConsole.warn("Snapshots, Destroy: Failed, Pool: " + pool.name + ", Snapshot: " + snapshot.name + ", Message: " + (process.data ? process.data : process.message)); + + if (display.refresh) { + $("#modal-storagepool-snapshot-destroy-" + snapshot.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + } +} + +function FnSnapshotRename(pool = { name, id }, snapshot = { name, id, namenew, recursive: false }) { + let process = { + command: ["/sbin/zfs", "rename", snapshot.name, snapshot.namenew] + }; + let modal = { + hide: true + }; + + if (snapshot.recursive) { + process.command.splice(2, 0, "-r"); + } + + FnConsole.log[1]("Snapshots, Rename: In Progress, Pool: " + pool.name + ", Snapshot: " + snapshot.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-storagepool-snapshot-rename-" + snapshot.id + " span").text("Renaming snapshot..."); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "Snapshot successfully renamed", description: snapshot.name, breakword: false }, { name: "snapshot-rename", id: snapshot.id, timeout: 4 }); + + FnConsole.log[1]("Snapshots, Rename: Success, Pool: " + pool.name + ", Snapshot: " + snapshot.name); + }) + .fail(function (message, data) { + if (/dataset already exists|child dataset already has a snapshot with the new name/gi.test(data)) { + modal.hide = false; + + $("#validationwrapper-storagepool-snapshot-rename-name-" + snapshot.id).addClass("has-error"); + $("#helpblock-storagepool-snapshot-rename-name-" + snapshot.id).addClass("has-error").removeClass("hidden").text("Name already exists."); + $("#input-storagepool-snapshot-rename-name-" + snapshot.id).focus(); + } + + if (!modal.hide) { + $("#spinner-storagepool-snapshot-rename-" + snapshot.id).addClass("hidden"); + $("#spinner-storagepool-snapshot-rename-" + snapshot.id + " span").text(""); + $("#btn-storagepool-snapshot-rename-apply-" + snapshot.id).prop("disabled", false); + } + + FnConsole.warn("Snapshots, Rename: Failed, Pool: " + pool.name + ", Snapshot: " + snapshot.name + ", Message: " + (data ? data : message)); + + if (modal.hide) { + FnDisplayAlert({ status: "danger", title: "Snapshot could not be renamed", description: snapshot.name, breakword: false }, { name: "snapshot-rename", id: snapshot.id, timeout: 4 }); + } + }) + .finally(function () { + if (modal.hide) { + $("#modal-storagepool-snapshot-rename-" + snapshot.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + } + }); +} + +function FnSnapshotRollBack(pool = { name, id, altroot: false, readonly: false }, snapshot = { name, id, creation, force: false, recursive: false, recursiveall: false }, samba = { restart: false }) { + if (samba.restart) { + FnSambaStop() + .finally(function () { + if (snapshot.recursiveall && zfsmanager.configuration.samba.manage) { + FnSnapshotRollBackSnapshotsGet({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, creation: snapshot.creation }, { name: null, id: null }) + .done(function (data) { + let snapshots = { + id: data.split(/\n/g).filter(v => v), + clones: [] + }; + + if (snapshots.id.length > 0) { + snapshots.id.forEach((_value, _index) => { + _value = _value.split(/\t/g).filter(v => v); + + snapshots.properties = { + clones: (_value[2] ? _value[2].split(",").filter(v => v) : []), + creation: _value[1], + name: _value[0] + }; + + if (snapshots.properties.name != snapshot.name && snapshots.properties.creation > snapshot.creation && snapshots.properties.clones.length > 0) { + snapshots.properties.clones.forEach((_value, _index) => { + snapshots.clones.push(_value); + }); + } + }); + } + + if (snapshots.clones.length > 0) { + $("#spinner-storagepool-snapshot-rollback-" + snapshot.id + " span").text("Retrieving Samba shares..."); + + FnSambaSharesGet({ name: pool.name, id: pool.id }, { name: null, clones: snapshots.clones }) + .done(function (_data) { + FnConsole.log[4](FnConsoleVerbose({ data: _data, message: "Samba, Shares, Get:" })); + + let filesystems = { + id: _data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) + }; + + $("#spinner-storagepool-snapshot-rollback-" + snapshot.id + " span").text("Rolling back snapshot..."); + + if (filesystems.id.length > 0) { + FnSnapshotRollBackCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, force: snapshot.force, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: false }) + .done(function () { + $("#spinner-storagepool-snapshot-rollback-" + snapshot.id + " span").text("Destroying Samba shares..."); + + FnSambaSharesDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { id: filesystems.id }, { restart: samba.restart }, { silent: false }) + .finally(function () { + $("#modal-storagepool-snapshot-rollback-" + snapshot.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + }); + }); + } else { + $("#spinner-storagepool-snapshot-rollback-" + snapshot.id + " span").text("Rolling back snapshot..."); + + FnSnapshotRollBackCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, force: snapshot.force, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: true }) + .finally(function () { + FnSambaStart(); + }); + } + }) + .fail(function (_message, _data) { + FnSnapshotRollBackCommandFail({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id }, { data: _data, message: _message }, { refresh: true }); + FnSambaStart(); + }); + } else { + $("#spinner-storagepool-snapshot-rollback-" + snapshot.id + " span").text("Rolling back snapshot..."); + + FnSnapshotRollBackCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, force: snapshot.force, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: true }) + .finally(function () { + FnSambaStart(); + }); + } + }); + } else { + $("#spinner-storagepool-snapshot-rollback-" + snapshot.id + " span").text("Rolling back snapshot..."); + + FnSnapshotRollBackCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, force: snapshot.force, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: true }) + .finally(function () { + FnSambaStart(); + }); + } + }); + } else { + if (snapshot.recursiveall && zfsmanager.configuration.samba.manage) { + FnSnapshotRollBackSnapshotsGet({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, creation: snapshot.creation }, { name: null, id: null }) + .done(function (data) { + let snapshots = { + id: data.split(/\n/g).filter(v => v), + clones: [] + }; + + if (snapshots.id.length > 0) { + snapshots.id.forEach((_value, _index) => { + _value = _value.split(/\t/g).filter(v => v); + + snapshots.properties = { + clones: (_value[2] ? _value[2].split(",").filter(v => v) : []), + creation: _value[1], + name: _value[0] + }; + + if (snapshots.properties.name != snapshot.name && snapshots.properties.creation > snapshot.creation && snapshots.properties.clones.length > 0) { + snapshots.properties.clones.forEach((_value, _index) => { + snapshots.clones.push(_value); + }); + } + }); + } + + if (snapshots.clones.length > 0) { + $("#spinner-storagepool-snapshot-rollback-" + snapshot.id + " span").text("Retrieving Samba shares..."); + + FnSambaSharesGet({ name: pool.name, id: pool.id }, { name: null, clones: snapshots.clones }) + .done(function (_data) { + FnConsole.log[4](FnConsoleVerbose({ data: _data, message: "Samba, Shares, Get:" })); + + let filesystems = { + id: _data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) + }; + + $("#spinner-storagepool-snapshot-rollback-" + snapshot.id + " span").text("Rolling back snapshot..."); + + if (filesystems.id.length > 0) { + FnSnapshotRollBackCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, force: snapshot.force, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: false }) + .done(function () { + $("#spinner-storagepool-snapshot-rollback-" + snapshot.id + " span").text("Destroying Samba shares..."); + + FnSambaSharesDestroy({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: false }, { id: filesystems.id }, { restart: samba.restart }, { silent: false }) + .finally(function () { + $("#modal-storagepool-snapshot-rollback-" + snapshot.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + }); + }); + } else { + $("#spinner-storagepool-snapshot-rollback-" + snapshot.id + " span").text("Rolling back snapshot..."); + + FnSnapshotRollBackCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, force: snapshot.force, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: true }); + } + }) + .fail(function (_message, _data) { + FnSnapshotRollBackCommandFail({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id }, { data: _data, message: _message }, { refresh: true }); + }); + } else { + $("#spinner-storagepool-snapshot-rollback-" + snapshot.id + " span").text("Rolling back snapshot..."); + + FnSnapshotRollBackCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, force: snapshot.force, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: true }); + } + }); + } else { + $("#spinner-storagepool-snapshot-rollback-" + snapshot.id + " span").text("Rolling back snapshot..."); + + FnSnapshotRollBackCommand({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, force: snapshot.force, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { refresh: true }); + } + } +} + +function FnSnapshotRollBackCommand(pool = { name, id }, snapshot = { name, id, force: false, recursive: false, recursiveall: false }, display = { refresh: true }) { + let process = { + command: ["/sbin/zfs", "rollback", snapshot.name] + }; + + if (snapshot.force) { + process.command.splice(2, 0, "-f"); + } + if (snapshot.recursive) { + process.command.splice(2, 0, "-r"); + } + if (snapshot.recursiveall) { + process.command.splice(2, 0, "-R"); + } + + FnConsole.log[1]("Snapshots, Roll Back: In Progress, Pool: " + pool.name + ", Snapshot: " + snapshot.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "Snapshot successfully rolled back", description: snapshot.name, breakword: false }, { name: "snapshot-rollback", id: snapshot.id, timeout: 4 }); + + FnConsole.log[1]("Snapshots, Roll Back: Success, Pool: " + pool.name + ", Snapshot: " + snapshot.name); + }) + .fail(function (message, data) { + FnSnapshotRollBackCommandFail({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id }, { data: data, message: message }, { refresh: false }); + + display.refresh = true; + }) + .finally(function () { + if (display.refresh) { + $("#modal-storagepool-snapshot-rollback-" + snapshot.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + } + }); +} + +function FnSnapshotRollBackCommandFail(pool = { name, id }, snapshot = { name, id }, process = { data, message }, display = { refresh: true }) { + FnDisplayAlert({ status: "danger", title: "Snapshot could not be rolled back", description: snapshot.name, breakword: false }, { name: "snapshot-rollback", id: snapshot.id, timeout: 4 }); + + FnConsole.warn("Snapshots, Roll Back: Failed, Pool: " + pool.name + ", Snapshot: " + snapshot.name + ", Message: " + (process.data ? process.data : process.message)); + + if (display.refresh) { + $("#modal-storagepool-snapshot-rollback-" + snapshot.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 200); + } +} + +function FnSnapshotRollBackSnapshotsGet(pool = { name, id }, snapshot = { name, id, creation }, modal = { name, id }) { + let process = { + command: ["/sbin/zfs", "list", "-H", "-o", "name,creation,clones", "-p", "-t", "snapshot"] + }; + + process.command.push(snapshot.name.replace(/^(.*)\@.*$/, "$1")); + + FnConsole.log[2]("Snapshots, Roll Back, Snapshots, Get: In Progress, Pool: " + pool.name + ", Snapshot: " + snapshot.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Snapshots, Roll Back, Snapshots, Get:" })); + + if (modal.name && modal.id) { + let snapshots = { + id: data.split(/\n/g).filter(v => v), + clones: [], + count: { + snapshots: 0, + snapshotswithclones: 0 + } + }; + + if (snapshots.id.length > 0) { + snapshots.id.forEach((_value, _index) => { + _value = _value.split(/\t/g).filter(v => v); + + snapshots.properties = { + clones: (_value[2] ? _value[2].split(",").filter(v => v) : []), + creation: _value[1], + name: _value[0] + }; + + if (snapshots.properties.name != snapshot.name && snapshots.properties.creation > snapshot.creation) { + snapshots.count.snapshots++; + snapshots.count.snapshotswithclones++; + + if (snapshots.properties.clones.length > 0) { + snapshots.properties.clones.forEach((_value, _index) => { + snapshots.clones.push(_value); + }); + } + + $("#ul-" + modal.name + "-snapshots-" + modal.id).append("
  • " + snapshots.properties.name + "
  • \n"); + $("#ul-" + modal.name + "-child-snapshotswithclones-" + modal.id).append("
  • " + snapshots.properties.name + "
  • \n"); + } + }); + + $("#panelgroup-" + modal.name + "-" + modal.id).attr("data-snapshot-snapshots", snapshots.count.snapshots); + $("#panelgroup-" + modal.name + "-" + modal.id).attr("data-snapshot-child-snapshotswithclones", snapshots.count.snapshotswithclones); + } + + if (snapshots.clones.length > 0) { + FnSnapshotChildFileSystemsGet({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id }, filesystems = { id: snapshots.clones }, { name: modal.name, id: modal.id }); + FnSnapshotChildSnapshotsGet({ name: pool.name, id: pool.id }, { name: snapshot.name, id: snapshot.id, exclude: true }, { id: snapshots.clones }, { name: modal.name, id: modal.id }); + } + } + + FnConsole.log[1]("Snapshots, Roll Back, Snapshots, Get: Success, Pool: " + pool.name + ", Snapshot: " + snapshot.name); + }) + .fail(function (message, data) { + FnConsole.warn("Snapshots, Roll Back, Snapshots, Get: Failed, Pool: " + pool.name + ", Snapshot: " + snapshot.name + ", Message: " + (data ? data : message)); + }); +} + +//#endregion + +//#region Status + +function FnStatusErrorColors(status = { count }) { + if (!$.isNumeric(status.count)) { + return status.count; + } + + if (status.count >= 5 && status.count <= 20) { + return (`` + status.count + ``); + } else if (status.count >= 21) { + return (`` + status.count + ``); + } else { + return status.count; + } +} + +function FnStatusGet(pool = { name, id }) { + let process = { + command: ["/bin/sh", "-c", ((zfsmanager.user.name == "root" || !zfsmanager.user.name) ? "ZPOOL_SCRIPTS_AS_ROOT=1 " : "") + `/sbin/zpool status -p -t -c upath "` + pool.name + `"`] + }; + + pool.autotrim = ($("#tr-storagepool-" + pool.id).attr("data-pool-autotrim") == "true" ? true : false); + pool.boot = ($("#tr-storagepool-" + pool.id).attr("data-pool-boot") == "true" ? true : false); + pool.feature = { + allocation_classes: ($("#tr-storagepool-" + pool.id).attr("data-pool-feature-allocation_classes") == "true" ? true : false), + device_removal: ($("#tr-storagepool-" + pool.id).attr("data-pool-feature-device_removal") == "true" ? true : false), + resilver_defer: ($("#tr-storagepool-" + pool.id).attr("data-pool-feature-resilver_defer") == "true" ? true : false) + }; + pool.guid = $("#tr-storagepool-" + pool.id).attr("data-pool-guid"); + pool.readonly = ($("#tr-storagepool-" + pool.id).attr("data-pool-readonly") == "true" ? true : false); + pool.root = ($("#tr-storagepool-" + pool.id).attr("data-pool-root") == "true" ? true : false); + pool.status = { + empty: true + }; + pool.upgrade = ($("#tr-storagepool-" + pool.id).attr("data-pool-upgrade") == "true" ? true : false); + pool.version = $("#tr-storagepool-" + pool.id).attr("data-pool-version"); + + FnConsole.log[2]("Status, Get: In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data, message) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Status, Get:" })); + + FnDisksLsblkGet({ sizeraw: true }) + .done(function (_data) { + FnConsole.log[4](FnConsoleVerbose({ data: _data, message: "Disks, Lsblk, Get:" })); + + if (data) { + pool.status.empty = false; + + let disks = { + lsblkjson: JSON.parse(_data) + }; + + FnStatusGetCommand({ name: pool.name, id: pool.id, autotrim: pool.autotrim, boot: pool.boot, feature: { allocation_classes: pool.feature.allocation_classes, device_removal: pool.feature.device_removal, resilver_defer: pool.feature.resilver_defer }, guid: pool.guid, readonly: pool.readonly, root: pool.root, upgrade: pool.upgrade, version: pool.version }, { lsblk: disks.lsblkjson }, { data: data, message: message }); + } + + FnConsole.log[1]("Status, Get: Success, Pool: " + pool.name); + + if (pool.status.empty) { + $("#tbody-storagepool-status-messages-" + pool.id).empty(); + $("#tbody-storagepool-status-config-" + pool.id).empty(); + $("#tbody-storagepool-status-messages-" + pool.id).append(`Status not available`); + $("#modals-storagepool-status-" + pool.id).remove(); + $("#dynamics-storagepool-status-" + pool.id).remove(); + + $("#tr-storagepool-" + pool.id).attr("data-pool-refresh-status", "true"); + + $("#spinner-storagepool-status-" + pool.id).addClass("hidden"); + $("#paneltitle-storagepool-status-" + pool.id).removeClass("hidden").text(FnDateTime()); + $("#btn-storagepool-status-refresh-" + pool.id).prop("disabled", false); + $("#btn-storagepool-status-refresh-auto-" + pool.id).prop("disabled", false); + } + + FnStoragePoolSpinnerHide({ name: pool.name, id: pool.id }); + FnCockpitElementsUpdate(); + }) + .fail(function (_message, _data) { + FnConsole.warn("Status, Get: Failed, Pool: " + pool.name + ", Message: " + (_data ? _data : _message)); + + FnStatusGetFail({ name: pool.name, id: pool.id, status: { empty: pool.status.empty } }); + }); + }) + .fail(function (message, data) { + FnConsole.warn("Status, Get: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); + + FnStatusGetFail({ name: pool.name, id: pool.id, status: { empty: pool.status.empty } }); + }); +} + +function FnStatusGetCommand(pool = { name, id, autotrim: false, boot: false, feature: { allocation_classes: true, device_removal: true, resilver_defer: true }, guid, readonly: false, root: false, upgrade: false, version }, disks = { lsblk: {} }, process = { data, message }) { + process.data = process.data.replace(/\n\t+/g, "[TAB1]").split(/\n/g).filter(v => v); //Replace new line with [TAB1] for multi line messages and config + + pool.status = { + state: "", + status: "", + action: "", + see: "", + scan: "", + remove: "", + memory: "", + errors: "", + upgrade: false, + resilver: { + started: false + }, + scrub: { + started: false, + paused: false + }, + trim: { + started: false, + suspended: false + }, + disks: { + count: 0, + ssd: false, + trim: { + unsupportedcount: 0 + } + }, + config: { + items: [], + regexp: {}, + replacement: {}, + tier: { + count: 0, + nametier0: "", + nametier1: "", + nametier2: "", + nametier3: "" + }, + virtualdevice: { + count: 0 + } + } + }; + + $("#modals-storagepool-status-" + pool.id).remove(); + $("#modals").append(`
    `); + $("#dynamics-storagepool-status-" + pool.id).remove(); + $("#dynamics").append(`
    `); + + pool.status.output = `Pool: ` + pool.name + ``; + + process.data.forEach((_value, _index) => { + if (/^(?: )+pool:/g.test(_value)) { + _value = ""; + } + if (/^(?: )+state:/g.test(_value)) { + pool.status.state = _value.replace(/\[TAB1\]/g, " ").replace(/^(?: )+state:/g, "").trim(); + _value = ""; + + pool.status.output += `State: ` + (pool.status.state ? ` ` + pool.status.state : ``) + ``; + } + if (/^status:/g.test(_value)) { + pool.status.status = _value.replace(/\[TAB1\]/g, " ").replace(/^status:/g, "").trim(); + _value = ""; + + if (/currently being resilvered/gi.test(pool.status.status)) { + pool.status.resilver.started = true; + } + + pool.status.output += `Status: ` + pool.status.status + ``; + } + if (/^action:/g.test(_value)) { + pool.status.action = _value.replace(/\[TAB1\]/g, " ").replace(/^action:/g, "").trim(); + pool.status.upgrade = ((pool.upgrade || /Upgrade the pool|zpool upgrade/gi.test(pool.status.action)) && !pool.boot ? true : false); + _value = ""; + + if (/Upgrade the pool|zpool upgrade/gi.test(pool.status.action) && !pool.boot) { //Hide upgrade message for boot pool. Upgrading version may cause an unbootable system + pool.status.output += `Action: ` + pool.status.action + ``; + } + } + if (/^(?: )+see:/g.test(_value)) { + pool.status.see = _value.replace(/\[TAB1\]/g, " ").replace(/^(?: )+see:(?: )+/g, "").trim(); + _value = ""; + + if (/http/g.test(pool.status.see)) { + pool.status.see = `` + pool.status.see + ``; + } + + pool.status.output += `See: ` + pool.status.see + ``; + } + if (/^(?: )+scan:/g.test(_value)) { + pool.status.scan = _value.replace(/\[TAB1\]/g, " ").replace(/^(?: )+scan:/g, "").trim(); + _value = ""; + + if (/scrub in progress/gi.test(pool.status.scan)) { + pool.status.scrub.started = true; + } else if (/scrub paused/gi.test(pool.status.scan)) { + pool.status.scrub.paused = true; + } + + if (/resilver in progress/gi.test(pool.status.scan)) { + pool.status.resilver.started = true; + } + + pool.status.output += `Scan: ` + pool.status.scan + ``; + } + if (/^remove:/g.test(_value)) { + pool.status.remove = _value.replace(/\[TAB1\]/g, " ").replace(/^remove:/g, "").trim(); + _value = ""; + + pool.status.output += `Remove: ` + pool.status.remove + ``; + } + if (/memory used for/g.test(_value)) { + pool.status.memory = ". " + _value.replace(/\[TAB1\]/g, " ").trim(); + _value = ""; + } + if (/^config:/g.test(_value)) { + _value = ""; + } + if (/^errors:/g.test(_value)) { + pool.status.errors = _value.replace(/\[TAB1\]/g, " ").replace(/^errors:/g, "").trim(); + _value = ""; + + pool.status.output += `Errors: ` + pool.status.errors + ``; + } + if (/\[TAB1\]NAME/g.test(_value)) { //Config header row + _value = _value.split("upath").slice(1).join("."); //Remove config header row (and any previous text if exists) + + pool.status.config.regexp.tabspace = new RegExp("^\\[TAB1\\]" + pool.name); + + if (pool.status.config.regexp.tabspace.test(_value)) { //Confirm config rows + pool.status.config.items = _value.split("[TAB1]").filter(v => v); + } + + if (/trimmed, started|trimmed started/i.test(pool.status.config.items.join(" "))) { //Storage pool contains a disk with TRIM started + pool.status.trim.started = true; + } else if (/trimmed, suspended|trimmed suspended/i.test(pool.status.config.items.join(" "))) { //Storage pool contains a disk with TRIM suspended + pool.status.trim.suspended = true; + } + } + }); + + pool.status.output += ``; + pool.status.output += ``; + + $("#tbody-storagepool-status-messages-" + pool.id).html(pool.status.output); + $("#td-storagepool-status-messages-remove-" + pool.id).append(pool.status.memory); + + pool.status.config.output = ` + + Name + State + Read + Write + Checksum + Message + Product + + + + `; + + $("#tbody-storagepool-status-config-" + pool.id).html(pool.status.config.output); + + pool.status.config.items.forEach((_value, _index) => { + pool.status.config.disk = false; + pool.status.config.tier.level = (_value.match(/^\s*/g)[0].length / 2); + pool.status.config.tier.cache = false; + pool.status.config.tier.dedup = false; + pool.status.config.tier.logs = false; + pool.status.config.tier.pool = false; + pool.status.config.tier.spares = false; + pool.status.config.tier.special = false; + pool.status.config.tier.replacing = false; + pool.status.config.output = ""; + + pool.status.disks.disk = { + ssd: false, + trim: { + started: false, + suspended: false, + unsupported: false + }, + replacing: false, + messages: [], + upath: "" + } + + if (_index == 0 && /[ ]/g.test(pool.name)) { //Fix for storage pool name if it contains whitespace + pool.status.config.regexp.poolname = new RegExp("^" + pool.name, "g"); + _value = _value.replace(pool.status.config.regexp.poolname, "[POOLNAME]"); + } + + _value = _value.replace(/ +/g, "\u22C5").replace(/^\u22C5/, "").split("\u22C5").filter(v => v); + + if (_index == 0 && _value[0] == "[POOLNAME]") { + _value[0] = pool.name; + } + + switch (pool.status.config.tier.level) { + case 0: //Pool / Cache / Dedup / Log / Spares / Special tier + pool.status.config.tier.nametier0 = _value[0].trim(); + break; + case 1: //Virtual device tier + pool.status.config.tier.nametier1 = _value[0]; + + if (pool.status.config.tier.nametier0 == pool.name) { + pool.status.config.virtualdevice.count++; + } + break; + case 2: //Drive tier + pool.status.config.tier.nametier2 = _value[0]; + break; + case 3: //Action tier + pool.status.config.tier.nametier3 = _value[0]; + break; + case 4: //Action Drive tier + break; + } + + if (pool.status.config.tier.level == 0) { //1= Pool, 2+= / Cache / Dedup / Log / Spares / Special + pool.status.config.tier.count++; + } + + if (pool.status.config.tier.level > 0) { + if (pool.status.config.tier.nametier0 == pool.name && pool.status.config.tier.count == 1) { //Virtual Device / Disk is member of pool + pool.status.config.tier.pool = true; + } + if (/^cache/g.test(pool.status.config.tier.nametier0) && pool.status.config.tier.count > 1) { //Virtual Device / Disk is member of cache + pool.status.config.tier.cache = true; + } + if (/^dedup/g.test(pool.status.config.tier.nametier0) && pool.status.config.tier.count > 1) { //Virtual Device / Disk is member of dedup + pool.status.config.tier.dedup = true; + } + if (/^logs/g.test(pool.status.config.tier.nametier0) && pool.status.config.tier.count > 1) { //Virtual Device / Disk is member of logs + pool.status.config.tier.logs = true; + } + if (/^spares/g.test(pool.status.config.tier.nametier0) && pool.status.config.tier.count > 1) { //Virtual Device / Disk is member of spares + pool.status.config.tier.spares = true; + } + if (/^special/g.test(pool.status.config.tier.nametier0) && pool.status.config.tier.count > 1) { //Virtual Device / Disk is member of special + pool.status.config.tier.special = true; + } + } + + pool.status.config.tier.virtualdevice = ((pool.status.config.tier.level == 0 && /^cache|^dedup|^logs|^spares|^special/g.test(pool.status.config.tier.nametier0) && pool.status.config.tier.count > 1) ? true : false); + + if (pool.status.config.tier.level == 0 && /^special/g.test(pool.status.config.tier.nametier0) && pool.status.config.tier.count > 1) { + $("#tr-storagepool-" + pool.id).attr("data-pool-special", true); + } + + if (/^\/dev\/nvme|^\/dev\/sd/gi.test(_value[5])) { //upath + pool.status.disks.disk.upath = _value[5]; + _value[5] = ""; + } else if ($.isNumeric(_value[0]) && _value[5] == "was") { //upath appears after was device path message + pool.status.disks.disk.upath = _value[7]; + _value[7] = ""; + } else if (!$.isNumeric(_value[0]) && _value[5] != "was") { //upath appears after error messages and before trim messages + for (let i = 5; i < _value.length; i++) { //Collect messages + if (/^\/dev\/nvme|^\/dev\/sd/gi.test(_value[i])) { + pool.status.disks.disk.upath = _value[i]; + _value[i] = ""; + } + } + } + + if ((/^\/dev\/nvme|^\/dev\/sd/gi.test(pool.status.disks.disk.upath) || /^nvme-nvme/gi.test(_value[0]) || /^wwn-/gi.test(_value[0]) || $.isNumeric(_value[0])) && pool.status.config.tier.level > 0) { + pool.status.config.disk = true; + pool.status.disks.count++; + } + + if (pool.status.config.disk && (pool.status.config.tier.level == 2 && /^replacing-/g.test(pool.status.config.tier.nametier1) || pool.status.config.tier.level == 3 && /^replacing-/g.test(pool.status.config.tier.nametier2) || pool.status.config.tier.level == 4 && /^replacing-/g.test(pool.status.config.tier.nametier3))) { + pool.status.disks.disk.replacing = true; + } + + if (pool.status.config.tier.level > 0 && /^replacing-/g.test(_value[0])) { + pool.status.config.tier.replacing = true; + } + + pool.status.config.output += ``; + pool.status.config.output += `` + (pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name ? `Pool` : (pool.status.config.disk ? `Disk` : `Virtual Device`)) + `:` + _value[0] + ``; //Pool / Virtual Device / Disk + pool.status.config.output += `State:` + (_value[1] ? ` ` + _value[1] : ``) + ``; //State + + if (_value[2] && /^spares/g.test(pool.status.config.tier.nametier0)) { //Read + pool.status.disks.disk.messages.push(_value[2]); + + pool.status.config.output += ``; + } else { + pool.status.config.output += `` + (_value[2] ? `Read:` + (zfsmanager.configuration.zfs.status.errorcolors ? FnStatusErrorColors({ count: _value[2] }) : _value[2]) : ``) + ``; + } + + if (_value[3] && /^spares/g.test(pool.status.config.tier.nametier0)) { //Write + pool.status.disks.disk.messages.push(_value[3]); + + pool.status.config.output += ``; + } else { + pool.status.config.output += `` + (_value[3] ? `Write:` + (zfsmanager.configuration.zfs.status.errorcolors ? FnStatusErrorColors({ count: _value[3] }) : _value[3]) : ``) + ``; + } + + if (/^spares/g.test(pool.status.config.tier.nametier0)) { //Checksum + if (_value[4]) { + pool.status.disks.disk.messages.push(_value[4]); + } + + pool.status.config.output += ``; + } else { + pool.status.config.output += `` + (_value[4] ? `Checksum:` + (zfsmanager.configuration.zfs.status.errorcolors ? FnStatusErrorColors({ count: _value[4] }) : _value[4]) : ``) + ``; + } + + for (let i = 5; i < _value.length; i++) { //Collect messages + if (_value[i]) { + pool.status.disks.disk.messages.push(_value[i]); + } + } + + pool.status.disks.disk.messages = pool.status.disks.disk.messages.join(" "); //Join Messages for output + + if (pool.status.config.disk && /\(trim unsupported\)/gi.test(pool.status.disks.disk.messages)) { + pool.status.disks.disk.trim.unsupported = true; + pool.status.disks.trim.unsupportedcount++; + } + + if (!zfsmanager.configuration.zfs.status.trimunsupported) { + pool.status.disks.disk.messages = pool.status.disks.disk.messages.replace(/\(trim unsupported\)/gi, ""); + } + if (pool.status.config.tier.cache || pool.status.config.tier.spares) { //Cache and spare disks can not be trimmed + pool.status.disks.disk.messages = pool.status.disks.disk.messages.replace(/\(untrimmed\)/gi, ""); + } + + pool.status.config.replacement.messages = [ + { pattern: /^\(/g, replacement: "" }, + { pattern: /\)$/g, replacement: "" }, + { pattern: / \(/g, replacement: ", " }, + { pattern: /\),/g, replacement: "," }, + { pattern: /\) /g, replacement: " " } + ]; + + pool.status.config.output += `Message:` + pool.status.config.replacement.messages.reduce((m, r) => m.replace(r.pattern, r.replacement), pool.status.disks.disk.messages) + ``; //Message + + if (pool.status.config.disk) { + if (/trimmed, started|trimmed started/i.test(pool.status.disks.disk.messages)) { + pool.status.disks.disk.trim.started = true; + + if (!pool.status.trim.started) { //Storage pool contains a disk with TRIM started + pool.status.trim.started = true; + } + } else if (/trimmed, suspended|trimmed suspended/i.test(pool.status.disks.disk.messages)) { + pool.status.disks.disk.trim.suspended = true; + + if (!pool.status.trim.suspended) { //Storage pool contains a disk with TRIM suspended + pool.status.trim.suspended = true; + } + } + } + + pool.status.config.output += `Product:`; //Product + + if (pool.status.config.disk) { + disks.lsblk.blockdevices.forEach((__value, __index) => { + if (__value.type == "disk") { + if (pool.status.disks.disk.upath.replace(/^\/dev\//gi, "") == __value.name || "nvme-" + __value.wwn == _value[0] || "wwn-" + __value.wwn == _value[0]) { + if (__value.rota == 0 || __value.rota === "false") { + pool.status.disks.disk.ssd = true; + + if (!pool.status.ssd) { //Storage pool contains an SSD + pool.status.disks.ssd = true; + } + } + + pool.status.config.output += FnFormatBytes({ base2: zfsmanager.configuration.disks.base2, decimals: 2, value: __value.size }) + " " + __value.model + (__value.serial ? " (" + __value.serial + ")" : ""); + } + } + }); + } + + pool.status.config.output += ``; + + //Actions Menu + pool.status.config.actionsmenu = { + items: { + storagepool: [], + storagepooldivider: function () { + if (this.storagepool.length > 0 && (this.virtualdevice.length > 0 || this.disk.length > 0)) { + this.storagepool.push(this.divider); + } + }, + virtualdevice: [], + virtualdevicedivider: function () { + if (this.virtualdevice.length > 0 && this.disk.length > 0) { + this.virtualdevice.push(this.divider); + } + }, + disk: [], + divider: `` + }, + display: function () { + if ((this.items.virtualdevice.length + this.items.virtualdevice.length + this.items.disk.length) > 0 || pool.readonly) { + this.items.storagepooldivider(); + this.items.virtualdevicedivider(); + return this.header + this.items.storagepool.join("\n") + this.items.virtualdevice.join("\n") + this.items.disk.join("\n") + this.footer; + } else { + return ""; + } + } + } + pool.status.config.actionsmenu.header = ` + + `; + pool.status.config.actionsmenu.register = { + storagepool: { + scrub: {}, + trim: {} + }, + virtualdevice: {}, + disk: { + trim: {} + } + }; + + //Clear storage pool errors + if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name) { + pool.status.config.actionsmenu.items.storagepool.push(`
  • Clear Storage Pool Errors
  • `); + + pool.status.config.actionsmenu.register.storagepool.clear = true; + } + + //Resilver Storage Pool + if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name && pool.feature.resilver_defer) { + pool.status.config.actionsmenu.items.storagepool.push(`
  • Resilver Storage Pool
  • `); + + pool.status.config.actionsmenu.register.storagepool.resilver = true; + } + + //Start Storage Pool Scrub + if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name && !pool.status.scrub.started && !pool.status.scrub.paused) { + pool.status.config.actionsmenu.items.storagepool.push(`
  • Scrub Storage Pool
  • `); + + pool.status.config.actionsmenu.register.storagepool.scrub.start = true; + } + + //Resume Storage Pool Scrub + if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name && pool.status.scrub.paused) { + pool.status.config.actionsmenu.items.storagepool.push(`
  • Resume Storage Pool Scrub
  • `); + + pool.status.config.actionsmenu.register.storagepool.scrub.resume = true; + } + + //Pause Storage Pool Scrub + if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name && pool.status.scrub.started) { + pool.status.config.actionsmenu.items.storagepool.push(`
  • Pause Storage Pool Scrub
  • `); + + pool.status.config.actionsmenu.register.storagepool.scrub.pause = true; + } + + //Stop Storage Pool Scrub + if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name && (pool.status.scrub.started || pool.status.scrub.paused)) { + pool.status.config.actionsmenu.items.storagepool.push(`
  • Stop Storage Pool Scrub
  • `); + + pool.status.config.actionsmenu.register.storagepool.scrub.stop = true; + } + + //TRIM Storage Pool + if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name && !pool.status.trim.started && !pool.status.trim.suspended) { + pool.status.config.actionsmenu.items.storagepool.push(`
  • TRIM Storage Pool
  • `); + + pool.status.config.actionsmenu.register.storagepool.trim.start = true; + } + + //Resume Storage Pool TRIM + if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name && pool.status.trim.suspended) { + pool.status.config.actionsmenu.items.storagepool.push(`
  • Resume Storage Pool TRIM
  • `); + + pool.status.config.actionsmenu.register.storagepool.trim.resume = true; + } + + //Suspend Storage Pool TRIM + if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name && pool.status.trim.started) { + pool.status.config.actionsmenu.items.storagepool.push(`
  • Suspend Storage Pool TRIM
  • `); + + pool.status.config.actionsmenu.register.storagepool.trim.suspend = true; + } + + //Cancel Storage Pool TRIM + if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name && (pool.status.trim.started || pool.status.trim.suspended)) { + pool.status.config.actionsmenu.items.storagepool.push(`
  • Cancel Storage Pool TRIM
  • `); + + pool.status.config.actionsmenu.register.storagepool.trim.cancel = true; + } + + //Upgrade Storage Pool + if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name && pool.status.upgrade) { + pool.status.config.actionsmenu.items.storagepool.push(`
  • Upgrade Storage Pool
  • `); + + pool.status.config.actionsmenu.register.storagepool.upgrade = true; + } + + //Regenerate Storage Pool GUID + if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name) { + pool.status.config.actionsmenu.items.storagepool.push(`
  • Regenerate Storage Pool GUID
  • `); + + pool.status.config.actionsmenu.register.storagepool.regenerateguid = true; + } + + //Clear Virtual Device Errors + if (!pool.readonly && pool.status.config.tier.level > 0 && !pool.status.config.disk) { + pool.status.config.actionsmenu.items.virtualdevice.push(`
  • Clear Virtual Device Errors
  • `); + + pool.status.config.actionsmenu.register.virtualdevice.clear = true; + } + + //Add Virtual Device + if (!pool.readonly && pool.status.config.tier.level == 0 && pool.status.config.tier.count == 1 && _value[0] == pool.name) { + pool.status.config.actionsmenu.items.virtualdevice.push(`
  • Add Virtual Device
  • `); + + pool.status.config.actionsmenu.register.virtualdevice.add = true; + } + + //Remove Virtual Device + if (!pool.readonly && pool.status.config.tier.level == 1 && !pool.status.config.tier.replacing && (pool.feature.device_removal || pool.status.config.tier.spares)) { + pool.status.config.actionsmenu.items.virtualdevice.push(`
  • Remove Virtual Device
  • `); + + pool.status.config.actionsmenu.register.virtualdevice.remove = true; + } + + //Clear Disk Errors + if (!pool.readonly && pool.status.config.tier.level > 0 && !pool.status.config.tier.spares && pool.status.config.disk) { + pool.status.config.actionsmenu.items.disk.push(`
  • Clear Disk Errors
  • `); + + pool.status.config.actionsmenu.register.disk.clear = true; + } + + //Attach Disk: Disk and Mirror virtual devices only + if (!pool.readonly && pool.status.config.tier.level == 1 && !pool.status.config.tier.cache && !pool.status.config.tier.spares && (/^mirror-/g.test(_value[0]) || pool.status.config.disk)) { + pool.status.config.actionsmenu.items.disk.push(`
  • Attach Disk
  • `); + + pool.status.config.actionsmenu.register.disk.attach = true; + } + + //Detach Disk: Disk and Mirror virtual devices only + if (!pool.readonly && (pool.status.config.tier.level == 2 && /^spare-/g.test(_value[0]) == false || pool.status.config.tier.level == 3) && /^mirror-/g.test(pool.status.config.tier.nametier1) && pool.status.config.disk) { + pool.status.config.actionsmenu.items.disk.push(`
  • Detach Disk
  • `); + + pool.status.config.actionsmenu.register.disk.detach = true; + } + + if (!pool.readonly && pool.status.config.tier.level > 0 && pool.status.config.disk) { + //Online Disk / Offline Disk + if (_value[1] == "OFFLINE" || _value[1] == "UNAVAIL" || _value[1] == "FAULTED") { + pool.status.config.actionsmenu.items.disk.push(`
  • Online Disk
  • `); + + pool.status.config.actionsmenu.register.disk.online = true; + } else if ((_value[1] == "ONLINE" || _value[1] == "DEGRADED") && (pool.status.config.tier.level > 1 || pool.status.config.tier.level == 1 && (pool.status.config.tier.cache || pool.status.config.tier.logs))) { //Do not show offline disk if virtual device is Disk in Pool and Dedup + pool.status.config.actionsmenu.items.disk.push(`
  • Offline Disk
  • `); + + pool.status.config.actionsmenu.register.disk.offline = true; + } + + //Replace Disk + if (!pool.status.config.tier.spares) { + pool.status.config.actionsmenu.items.disk.push(`
  • Replace Disk
  • `); + + pool.status.config.actionsmenu.register.disk.replace = true; + } + + if (pool.status.disks.disk.ssd && !pool.status.disks.disk.trim.unsupported && !pool.status.config.tier.cache && !pool.status.config.tier.spares) { + //TRIM Disk + if (!pool.status.disks.disk.trim.started && !pool.status.disks.disk.trim.suspended) { + pool.status.config.actionsmenu.items.disk.push(`
  • TRIM Disk
  • `); + + pool.status.config.actionsmenu.register.disk.trim.start = true; + } + + //Resume Disk TRIM + if (pool.status.disks.disk.trim.suspended) { + pool.status.config.actionsmenu.items.disk.push(`
  • Resume Disk TRIM
  • `); + + pool.status.config.actionsmenu.register.disk.trim.resume = true; + } + + //Suspend Disk TRIM + if (pool.status.disks.disk.trim.started) { + pool.status.config.actionsmenu.items.disk.push(`
  • Suspend Disk TRIM
  • `); + + pool.status.config.actionsmenu.register.disk.trim.suspend = true; + } + + //Cancel Disk TRIM + if (pool.status.disks.disk.trim.started || pool.status.disks.disk.trim.suspended) { + pool.status.config.actionsmenu.items.disk.push(`
  • Cancel Disk TRIM
  • `); + + pool.status.config.actionsmenu.register.disk.trim.cancel = true; + } + } + } + + pool.status.config.output += ``; + pool.status.config.output += `` + pool.status.config.actionsmenu.display() + ``; + pool.status.config.output += ``; + + $("#tbody-storagepool-status-config-" + pool.id).append(pool.status.config.output); + + //Register status modals + if (pool.status.config.actionsmenu.register.disk.attach) { + FnModalStatusDiskAttach({ name: pool.name, id: pool.id, status: { config: { items: { index: _index }, tier: { name: pool.status.config.tier.nametier0, dedup: pool.status.config.tier.dedup, logs: pool.status.config.tier.logs, special: pool.status.config.tier.special } } } }, { id: _value[0], disk: pool.status.config.disk }); + } + if (pool.status.config.actionsmenu.register.disk.clear) { + FnModalStatusDiskClear({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }, { id: _value[0] }); + } + if (pool.status.config.actionsmenu.register.disk.detach) { + FnModalStatusDiskDetach({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }, { id: _value[0] }); + } + if (pool.status.config.actionsmenu.register.disk.offline) { + FnModalStatusDiskOffline({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }, { id: _value[0] }); + } + if (pool.status.config.actionsmenu.register.disk.online) { + FnModalStatusDiskOnline({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }, { id: _value[0] }); + } + if (pool.status.config.actionsmenu.register.disk.replace) { + FnModalStatusDiskReplace({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }, { id: _value[0] }); + } + if (pool.status.config.actionsmenu.register.storagepool.clear) { + FnModalStatusStoragePoolClear({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }); + } + if (pool.status.config.actionsmenu.register.storagepool.regenerateguid) { + FnModalStatusStoragePoolRegenerateGuid({ name: pool.name, id: pool.id, guid: pool.guid, status: { config: { items: { index: _index } } } }); + } + if (pool.status.config.actionsmenu.register.storagepool.resilver) { + FnModalStatusStoragePoolResilver({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } }, resilver: { started: pool.status.resilver.started } } }); + } + if (pool.status.config.actionsmenu.register.storagepool.trim.start) { + FnModalStatusStoragePoolTrimStart({ name: pool.name, id: pool.id, autotrim: pool.autotrim, status: { config: { items: { index: _index } } } }); + } + if (pool.status.config.actionsmenu.register.storagepool.upgrade) { + FnModalStatusStoragePoolUpgrade({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } }, version: pool.version }); + } + if (pool.status.config.actionsmenu.register.virtualdevice.add) { + FnModalStatusVirtualDeviceAdd({ name: pool.name, id: pool.id, feature: { allocation_classes: pool.feature.allocation_classes }, status: { config: { items: { index: _index } } } }); + } + if (pool.status.config.actionsmenu.register.virtualdevice.clear) { + FnModalStatusVirtualDeviceClear({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }, { id: _value[0] }); + } + if (pool.status.config.actionsmenu.register.virtualdevice.remove) { + FnModalStatusVirtualDeviceRemove({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }, { id: _value[0], disk: pool.status.config.disk }); + } + + //Register status dynamics + if (pool.status.config.actionsmenu.register.disk.trim.cancel) { + FnDynamicStatusDiskTrimCancel({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }, { id: _value[0] }); + } + if (pool.status.config.actionsmenu.register.disk.trim.resume) { + FnDynamicStatusDiskTrimResume({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }, { id: _value[0] }); + } + if (pool.status.config.actionsmenu.register.disk.trim.start) { + FnModalStatusDiskTrimStart({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }, { id: _value[0] }); + } + if (pool.status.config.actionsmenu.register.disk.trim.suspend) { + FnDynamicStatusDiskTrimSuspend({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }, { id: _value[0] }); + } + if (pool.status.config.actionsmenu.register.storagepool.scrub.pause) { + FnDynamicStatusStoragePoolScrubPause({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }); + } + if (pool.status.config.actionsmenu.register.storagepool.scrub.resume) { + FnDynamicStatusStoragePoolScrubResume({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }); + } + if (pool.status.config.actionsmenu.register.storagepool.scrub.start) { + FnDynamicStatusStoragePoolScrubStart({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }); + } + if (pool.status.config.actionsmenu.register.storagepool.scrub.stop) { + FnDynamicStatusStoragePoolScrubStop({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }); + } + if (pool.status.config.actionsmenu.register.storagepool.trim.cancel) { + FnDynamicStatusStoragePoolTrimCancel({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }); + } + if (pool.status.config.actionsmenu.register.storagepool.trim.resume) { + FnDynamicStatusStoragePoolTrimResume({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }); + } + if (pool.status.config.actionsmenu.register.storagepool.trim.suspend) { + FnDynamicStatusStoragePoolTrimSuspend({ name: pool.name, id: pool.id, status: { config: { items: { index: _index } } } }); + } + }); + + //Hide Storage Pool TRIM actions menu items if there is no SSD in the storage pool or all disks are TRIM unsupported + if (!pool.status.disks.ssd || pool.status.disks.trim.unsupportedcount == pool.status.disks.count) { + $("#btn-storagepool-status-trim-start-0-" + pool.id).addClass("hidden"); + $("#btn-storagepool-status-trim-resume-0-" + pool.id).addClass("hidden"); + $("#btn-storagepool-status-trim-suspend-0-" + pool.id).addClass("hidden"); + $("#btn-storagepool-status-trim-cancel-0-" + pool.id).addClass("hidden"); + } + + //Hide Remove Virtual Device actions menu item is there is only one in the storage pool + if (pool.status.config.virtualdevice.count < 2) { + $("[id^=btn-storagepool-status-virtualdevice-remove-][id$='" + pool.id + "'].pool-virtualdevice").addClass("hidden"); + $("[id^=divider-storagepool-status-][id$=" + pool.id + "].pool-virtualdevice").addClass("hidden"); + } + + $("#tr-storagepool-" + pool.id).attr("data-pool-refresh-status", "true"); + + $("#spinner-storagepool-status-" + pool.id).addClass("hidden"); + $("#paneltitle-storagepool-status-" + pool.id).removeClass("hidden").text(FnDateTime()); + $("#btn-storagepool-status-refresh-" + pool.id).prop("disabled", false); + $("#btn-storagepool-status-refresh-auto-" + pool.id).prop("disabled", false); + + FnStoragePoolSpinnerHide({ name: pool.name, id: pool.id }); + FnCockpitElementsUpdate(); +} + +function FnStatusGetFail(pool = { name, id, status: { empty: true } }) { + if (pool.status.empty) { + $("#tbody-storagepool-status-messages-" + pool.id).empty(); + $("#tbody-storagepool-status-config-" + pool.id).empty(); + $("#tbody-storagepool-status-messages-" + pool.id).append(`Status not available`); + $("#modals-storagepool-status-" + pool.id).remove(); + $("#dynamics-storagepool-status-" + pool.id).remove(); + + $("#tr-storagepool-" + pool.id).attr("data-pool-refresh-status", "true"); + + $("#spinner-storagepool-status-" + pool.id).addClass("hidden"); + $("#paneltitle-storagepool-status-" + pool.id).removeClass("hidden").text(FnDateTime()); + $("#btn-storagepool-status-refresh-" + pool.id).prop("disabled", false); + $("#btn-storagepool-status-refresh-auto-" + pool.id).prop("disabled", false); + } + + FnStoragePoolSpinnerHide({ name: pool.name, id: pool.id }); + FnCockpitElementsUpdate(); +} + +//#endregion + +//#region System + +function FnSystemHostIdGet(modal = { name, id }) { + let process = { + command: ["/bin/sh", "-c", "/bin/cat /etc/hostid 2> /dev/null && echo response true || echo response false"] + }; + + FnConsole.log[2]("System, Host ID, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "System, Host ID, Get:" })); + + data = data.replace(/\n+/g, "").replace(/^.+response /, "").replace("response ", ""); + + if (data == "false") { + if (modal.name) { + if ($("#switch-" + modal.name + "-multihost-" + modal.id + " input").prop("checked")) { + $("#btnspan-" + modal.name + "-hostid-" + modal.id).text("Use Lib C Generated Host ID").attr("data-field-value", "libc"); + $("#dropdown-" + modal.name + "-hostid-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-hostid-" + modal.id + " li[value='libc']").addClass("active"); + + $("#controllabel-" + modal.name + "-hostid-" + modal.id).removeClass("hidden"); + $("#validationwrapper-" + modal.name + "-hostid-" + modal.id).removeClass("hidden"); + } else { + $("#btnspan-" + modal.name + "-hostid-" + modal.id).text("Use Lib C Generated Host ID").attr("data-field-value", "missing"); + $("#dropdown-" + modal.name + "-hostid-" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-" + modal.name + "-hostid-" + modal.id + " li[value='libc']").addClass("active"); + } + } + + FnConsole.warn("System, Host ID, Get: Warning, Message: Host ID does not exist"); + } else { + FnConsole.log[1]("System, Host ID, Get: Success"); + } + }) + .fail(function (message, data) { + FnConsole.warn("System, Host ID, Get: Failed, Message: " + (data ? data : message)); + }); +} + +function FnSystemHostIdSet(system = { hostid }) { + let process = { + command: ["/bin/sh", "-c", "[ -x /usr/" + (/Debian/.test(zfsmanager.system.operatingsystem) ? "s" : "") + "bin/zgenhostid ] && /usr/" + (/Debian/.test(zfsmanager.system.operatingsystem) ? "s" : "") + "bin/zgenhostid" + (system.hostid ? " " + system.hostid : "") + " || zgenhostid " + (system.hostid ? " " + system.hostid : "")] + }; + + FnConsole.log[2]("System, Host ID, Set: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "System Host ID successfully configured", description: null, breakword: false }, { name: "system-hostid-set", id: null, timeout: 4 }); + + FnConsole.log[1]("System, Host ID, Set: Success"); + }) + .fail(function (message, data) { + FnConsole.warn("System, Host ID, Set: Failed, Message: " + (data ? data : message)); + }); +} + +function FnSystemNfsVersionGet(modal = { alert: { id } }) { + let process = { + command: ["/usr/sbin/nfsstat", "--version"] + }; + + FnConsole.log[2]("System, NFS, Version, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "System, NFS, Version, Get:" })); + + modal.alert.id.addClass("hidden"); + + FnConsole.log[1]("System, NFS, Version, Get: Success"); + }) + .fail(function () { + modal.alert.id.removeClass("hidden"); + + FnConsole.warn("System, NFS, Version, Get: Failed, Message: NFS is not installed."); + }); +} + +function FnSystemOperatingSystemGet() { + let process = { + command: ["/bin/sh", "-c", "/usr/bin/hostnamectl status | /bin/grep 'Operating System'"] + }; + + FnConsole.log[2]("System, Operating System, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "System, Operating System, Get:" })); + + data = data.replace(/\n+/g, "").replace(/^(?: +)Operating System: /, ""); + + if (data) { + zfsmanager.system.operatingsystem = data; + } + + FnConsole.log[2]("System, Operating System, Get: Success"); + }) + .fail(function (message, data) { + FnConsole.warn("System, Operating System, Get: Failed, Message: " + (data ? data : message)); + }); +} + +//#endregion + +//#region Disks + +function FnDisksAvailableGet(modal = { name, id, default: true }) { + disks = { + attached: [], + id: { + device: [], + path: [], + vdev: [] + }, + importable: [], + importableconfig: [], + importableconfigok: false, + storagepools: [], + storagepoolsconfig: [] + + }; + modal.id = (modal.id ? "-" + modal.id : ""); + + $("#listgroup-" + modal.name + modal.id).empty(); + $("#listgroup-" + modal.name + modal.id).append(`
  • `); + + FnDisksStoragePoolsAttachedGet({ name: null, id: null }, { id: { blockdevice: true } }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Disks, Storage Pools, Attached, Get:" })); + + disks.storagepools = data.replace(/\n\t+/g, "[TAB1]").split(/\n/g).filter(v => v); + + disks.storagepools.forEach((_value, _index) => { + if (/\[TAB1\]NAME/g.test(_value)) { //Config header row + _value = _value.split("upath").slice(1).join("."); //Remove config header row (and any previous text if exists) + + if (new RegExp("^\\[TAB1\\]").test(_value)) { //Confirm config rows + _value.split("[TAB1]").filter(v => v && disks.storagepoolsconfig.push(v)); + } + } + }); + + disks.storagepoolsconfig.forEach((_value, _index) => { + let config = { + disk: { + upath: "" + }, + tier: { + level: (_value.match(/^\s*/g)[0].length / 2) + } + }; + + _value = _value.replace(/ +/g, "\u22C5").replace(/^\u22C5/, "").split("\u22C5").filter(v => v); + + if (/^\/dev\/nvme|^\/dev\/sd/gi.test(_value[5])) { //upath + config.disk.upath = _value[5]; + } else if (!$.isNumeric(_value[0]) && _value[5] != "was") { //upath appears after error messages and before trim messages + for (let i = 5; i < _value.length; i++) { + if (/^\/dev\/nvme|^\/dev\/sd/gi.test(_value[i])) { + config.disk.upath = _value[i]; + } + } + } + + if (config.tier.level > 0) { + if (/^\/dev\/nvme|^\/dev\/sd/gi.test(config.disk.upath)) { //Block Device via upath + disks.attached.push(config.disk.upath.replace(/^\/dev\//gi, "")); + } else if (/^\/dev\/nvme|^\/dev\/sd/gi.test(_value[0])) { //Block Device + if (/^\/dev\/nvme\d+n\d+p\d+$/gi.test(_value[0])) { + disks.attached.push(_value[0].replace(/^\/dev\//gi, "").replace(/p\d+$/, "")); + } else if (/^\/dev\/sd.*\d+$/gi.test(_value[0])) { + disks.attached.push(_value[0].replace(/^\/dev\//gi, "").replace(/\d+$/, "")); + } else { + disks.attached.push(_value[0]); + } + } else if (/^nvme-nvme/gi.test(_value[0]) || /^wwn-/gi.test(_value[0])) { //WWN + if (/^nvme-nvme.*-part\d+$/gi.test(_value[0])) { + disks.attached.push(_value[0].replace(/-part\d+$/, "")); + } else if (/^wwn-.*-part\d+$/gi.test(_value[0])) { + disks.attached.push(_value[0].replace(/-part\d+$/, "")); + } else { + disks.attached.push(_value[0]); + } + } + } + }); + + disks.attached.sort(); + + FnDisksStoragePoolsImportableAttachedGet() + .done(function (_data) { + FnConsole.log[4](FnConsoleVerbose({ data: _data, message: "Disks, Storage Pools, Importable, Attached, Get:" })); + + disks.importable = _data.replace(/\n\t+/g, "[TAB1]").split(/\n/g).filter(v => v); + + disks.importable.forEach((_value, _index) => { + if (/config:/g.test(_value)) { //Config header row + disks.importableconfigok = true; + } + + if (new RegExp("^\\[TAB1\\]").test(_value) && disks.importableconfigok) { //Confirm config rows + _value.split("[TAB1]").filter(v => v && disks.importableconfig.push(v)); + } + }); + + disks.importableconfig.forEach((_value, _index) => { + let config = { + tier: { + level: (_value.match(/^\s*/g)[0].length / 2) + } + }; + + _value = _value.replace(/ +/g, "\u22C5").replace(/^\u22C5/, "").split("\u22C5").filter(v => v); + + if (config.tier.level > 0) { + if (/^nvme|^sd/gi.test(_value[0])) { //Block Device + if (/^nvme\d+n\d+p\d+$/gi.test(_value[0])) { + disks.attached.push(_value[0].replace(/p\d+$/, "")); + } else if (/^sd.*\d+$/gi.test(_value[0])) { + disks.attached.push(_value[0].replace(/\d+$/, "")); + } else { + disks.attached.push(_value[0]); + } + } else if (/^\/dev\/nvme|^\/dev\/sd/gi.test(_value[0])) { //Block Device + if (/^\/dev\/nvme\d+n\d+p\d+$/gi.test(_value[0])) { + disks.attached.push(_value[0].replace(/^\/dev\//gi, "").replace(/p\d+$/, "")); + } else if (/^\/dev\/sd.*\d+$/gi.test(_value[0])) { + disks.attached.push(_value[0].replace(/^\/dev\//gi, "").replace(/\d+$/, "")); + } else { + disks.attached.push(_value[0]); + } + } else if (/^nvme-nvme/gi.test(_value[0]) || /^wwn-/gi.test(_value[0])) { //WWN + if (/^nvme-nvme.*-part\d+$/gi.test(_value[0])) { + disks.attached.push(_value[0].replace(/-part\d+$/, "")); + } else if (/^wwn-.*-part\d+$/gi.test(_value[0])) { + disks.attached.push(_value[0].replace(/-part\d+$/, "")); + } else { + disks.attached.push(_value[0]); + } + } + } + }); + + disks.attached.sort(); + + FnDisksLsblkGet({ sizeraw: true }) + .done(function (__data) { + FnConsole.log[4](FnConsoleVerbose({ data: __data, message: "Disks, Lsblk, Get:" })); + + disks.lsblkjson = __data; + + FnDisksBlkidGet() + .done(function (___data) { + FnConsole.log[4](FnConsoleVerbose({ data: ___data, message: "Disks, Blkid, Get:" })); + + let replacement = { + regexp: [ + { pattern: /"/g, replacement: "" }, + { pattern: /: LABEL=/g, replacement: ",LABEL=" }, + { pattern: / UUID=/g, replacement: ",UUID=" }, + { pattern: / UUID_SUB=/g, replacement: ",UUID_SUB=" }, + { pattern: / TYPE=/g, replacement: ",TYPE=" }, + { pattern: / PARTLABEL=/g, replacement: ",PARTLABEL=" }, + { pattern: / PARTUUID=/g, replacement: ",PARTUUID=" } + ] + }; + + disks.blkid = replacement.regexp.reduce((d, r) => d.replace(r.pattern, r.replacement), ___data).split(/\n/g).filter(v => v); + + FnDisksIdentifierDiskGet() + .done(function (____data) { + FnConsole.log[4](FnConsoleVerbose({ data: ____data, message: "Disks, Identifier, Disk / WWN, Get:" })); + + disks.id.device = ____data.replace(/\t+/g, "\u22C5").replace(/..\/..\//g, "").split(/\n/g).filter(v => v && v != "\u22C5"); + + FnDisksIdentifierHardwarePathGet() + .done(function (_____data) { + FnConsole.log[4](FnConsoleVerbose({ data: _____data, message: "Disks, Identifier, Hardware Path, Get:" })); + + disks.id.path = _____data.replace(/\t+/g, "\u22C5").replace(/..\/..\//g, "").split(/\n/g).filter(v => v && v != "\u22C5"); + + FnDisksIdentifierVirtualDeviceMappingGet() + .done(function (______data) { + FnConsole.log[4](FnConsoleVerbose({ data: ______data, message: "Disks, Identifier, Virtual Device Mapping, Get:" })); + + disks.id.vdev = ______data.replace(/\t+/g, "\u22C5").replace(/..\/..\//g, "").split(/\n/g).filter(v => v && v != "\u22C5"); + + FnDisksAvailableGetCommand({ attached: disks.attached, blkid: disks.blkid, id: { device: disks.id.device, path: disks.id.path, vdev: disks.id.vdev }, lsblkjson: disks.lsblkjson }, { name: modal.name, id: modal.id, default: modal.default }); + }) + .fail(function (______message, ______data) { + FnConsole.warn("Disks, Available, Get: Failed, Message: " + (______data ? ______data : ______message)); + + FnDisksAvailableGetFail({ name: modal.name, id: modal.id }, { data: ______data, message: ______message }); + }); + }) + .fail(function (_____message, _____data) { + FnConsole.warn("Disks, Available, Get: Failed, Message: " + (_____data ? _____data : _____message)); + + FnDisksAvailableGetFail({ name: modal.name, id: modal.id }, { data: _____data, message: _____message }); + }); + }) + .fail(function (____message, ____data) { + FnConsole.warn("Disks, Available, Get: Failed, Message: " + (____data ? ____data : ____message)); + + FnDisksAvailableGetFail({ name: modal.name, id: modal.id }, { data: ____data, message: ____message }); + }); + }) + .fail(function (___message, ___data) { + FnConsole.warn("Disks, Available, Get: Failed, Message: " + (___data ? ___data : ___message)); + + FnDisksAvailableGetFail({ name: modal.name, id: modal.id }, { data: ___data, message: ___message }); + }); + }) + .fail(function (__message, __data) { + FnConsole.warn("Disks, Available, Get: Failed, Message: " + (__data ? __data : __message)); + + FnDisksAvailableGetFail({ name: modal.name, id: modal.id }, { data: __data, message: __message }); + }); + }) + .fail(function (_message, _data) { + FnConsole.warn("Disks, Available, Get: Failed, Message: " + (_data ? _data : _message)); + + FnDisksAvailableGetFail({ name: modal.name, id: modal.id }, { data: _data, message: _message }); + }); + }) + .fail(function (message, data) { + FnConsole.warn("Disks, Available, Get: Failed, Message: " + (data ? data : message)); + + FnDisksAvailableGetFail({ name: modal.name, id: modal.id }, { data: data, message: message }); + }); +} + +function FnDisksAvailableGetCommand(disks = { attached: [], blkid: [], id: { device: [], path: [], vdev: [] }, lsblkjson }, modal = { name, id, default: true }) { + disks.lsblk = JSON.parse(disks.lsblkjson); + disks.regexp = {}; + + disks.lsblk.blockdevices.forEach((_value, _index) => { + if (_value.type == "disk") { + let disk = { + id: { + blockdevice: "", + disk: "", + path: "", + vdev: "", + wwn: "" + }, + allow: true, + zfsmember: false, + warning: "", + warningicon: "", + }; + + disks.attached.forEach((__value, __index) => { + if (_value.name == __value || _value.wwn == __value || "nvme-" + _value.wwn == __value || "wwn-" + _value.wwn == __value) { //Do not allow if block device or WWN identifier match + disk.allow = false; + return; + } + }); + + if (_value.children && disk.allow) { + _value.children.forEach((__value, __index) => { + if (__value.mountpoint) { //Do not allow if partition of disk is mounted + disk.allow = false; + return; + } + }); + } + + if (disk.allow) { + disks.blkid.forEach((__value, __index) => { + disks.regexp.name = new RegExp("^\/dev\/" + _value.name, "gi"); + + if (disks.regexp.name.test(__value)) { + if (/,TYPE=zfs_member/gi.test(__value)) { + disk.zfsmember = true; + return; + } + } + }); + + if (disk.zfsmember) { + disk.warningicon = ` `; + + $("#helpblock-" + modal.name + "-zfsmemberwarning" + modal.id).html("One or more disks used to be a member of a Storage Pool." + disk.warningicon); + } + + disk.id.blockdevice = _value.name; + + if (!_value.wwn) { + disk.id.wwn = ""; + disk.warning = "One or more disks is missing a WWN identifier."; + + $("#helpblock-" + modal.name + "-identifierwarning" + modal.id).removeClass("hidden").text(disk.warning); + } else { + if (/^nvme/gi.test(_value.wwn)) { + disk.id.wwn = "nvme-" + _value.wwn; + } else { + disk.id.wwn = "wwn-" + _value.wwn; + } + } + + disks.id.device.forEach((_value, _index) => { + _value = _value.split("\u22C5"); + + if (_value[1] == disk.id.blockdevice) { + if (/^nvme-nvme|^wwn-/gi.test(_value[0])) { + return; + } else { + disk.id.disk = _value[0]; + return; + } + } + }); + + disks.id.path.forEach((_value, _index) => { + _value = _value.split("\u22C5"); + + if (_value[1] == disk.id.blockdevice) { + disk.id.path = _value[0]; + + return; + } + }); + + disks.id.vdev.forEach((_value, _index) => { + _value = _value.split("\u22C5"); + + if (_value[1] == disk.id.blockdevice) { + disk.id.vdev = _value[0]; + + return; + } + }); + + disks.output = ` + + `; + + $("#listgroup-" + modal.name + modal.id).append(disks.output); + } + } + }); + + setTimeout(function () { + $("#spinner-" + modal.name + modal.id).remove(); + $("#listgroup-" + modal.name + modal.id + " > li").removeClass("hidden"); + + if ($("#helpblock-" + modal.name + "-identifierwarning" + modal.id).text) { + $("#helpblock-" + modal.name + "-identifierwarning" + modal.id).removeClass("hidden"); + } + if ($("#helpblock-" + modal.name + "-zfsmemberwarning" + modal.id).text()) { + $("#helpblock-" + modal.name + "-zfsmemberwarning" + modal.id).removeClass("hidden"); + } + + if ($("#listgroup-" + modal.name + modal.id + " > li").length == 1 && modal.default) { //Change Virtual Device dropdown to Disk if there is only 1 disk available + if (modal.name == "storagepools-create-disks") { + $("#btnspan-storagepools-create-virtualdevice").text("Disk").attr("data-field-value", "disk"); + $("#dropdown-storagepools-create-virtualdevice li").siblings().removeClass("active"); + $("#dropdown-storagepools-create-virtualdevice li[value='disk']").addClass("active"); + } else if (modal.name == "storagepool-status-virtualdevice-add-disks") { + $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice" + modal.id).text("Disk").attr("data-field-value", "disk"); + $("#dropdown-storagepool-status-virtualdevice-add-virtualdevice" + modal.id + " li").siblings().removeClass("active"); + $("#dropdown-storagepool-status-virtualdevice-add-virtualdevice" + modal.id + " li[value='disk']").addClass("active"); + } + } + + if ($("#listgroup-" + modal.name + modal.id + " > li").length == 0) { + disks.output = ` +
  • + +
  • + `; + + $("#listgroup-" + modal.name + modal.id).append(disks.output); + } + }, 200); + + FnConsole.log[1]("Disks, Available, Get: Success"); +} + +function FnDisksAvailableGetFail(modal = { name, id }, process = { data, message }) { + setTimeout(function () { + $("#spinner-" + modal.name + modal.id).remove(); + $("#listgroup-" + modal.name + modal.id + " > li").removeClass("hidden"); + + if ($("#listgroup-" + modal.name + modal.id + " > li").length == 0) { + let disks = { + output: "" + }; + + disks.output = ` +
  • + +
  • + `; + + $("#listgroup-" + modal.name + modal.id).append(disks.output); + } + }, 200); +} + +function FnDisksBlkidGet() { + let process = { + command: ["/bin/sh", "-c", "/sbin/blkid -o full | /bin/grep -E '/dev/nvme\|/dev/sd'"] + }; + + FnConsole.log[2]("Disks, Blkid, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnConsole.log[2]("Disks, Blkid, Get: Success"); + }) + .fail(function (message, data) { + FnConsole.warn("Disks, Blkid, Get: Failed, Message: " + (data ? data : message)); + }); +} + +function FnDisksIdentifierDiskGet() { + let process = { + command: ["/bin/sh", "-c", `ls -lF /dev/disk/by-id | awk '{ print $9"\t"$11 }'`] + }; + + FnConsole.log[2]("Disks, Identifier, Disk / WWN, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnConsole.log[2]("Disks, Identifier, Disk / WWN, Get: Success"); + }) + .fail(function (message, data) { + FnConsole.warn("Disks, Identifier, Disk / WWN, Get: Failed, Message: " + (data ? data : message)); + }); +} + +function FnDisksIdentifierHardwarePathGet() { + let process = { + command: ["/bin/sh", "-c", `ls -lF /dev/disk/by-path | awk '{ print $9"\t"$11 }'`] + }; + + FnConsole.log[2]("Disks, Identifier, Hardware Path, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnConsole.log[2]("Disks, Identifier, Hardware Path, Get: Success"); + }) + .fail(function (message, data) { + FnConsole.warn("Disks, Identifier, Hardware Path, Get: Failed, Message: " + (data ? data : message)); + }); +} + +function FnDisksIdentifierVirtualDeviceMappingGet() { + let process = { + command: ["/bin/sh", "-c", `[ -d /dev/disk/by-vdev ] && ls -lF /dev/disk/by-vdev | awk '{ print $9"\t"$11 }' || printf ""`] + }; + + FnConsole.log[2]("Disks, Identifier, Virtual Device Mapping, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnConsole.log[2]("Disks, Identifier, Virtual Device Mapping, Get: Success"); + }) + .fail(function (message, data) { + FnConsole.warn("Disks, Identifier, Virtual Device Mapping, Get: Failed, Message: " + (data ? data : message)); + }); +} + +function FnDisksLsblkGet(disks = { sizeraw: true }) { + let process = { + command: ["/bin/sh", "-c", "/bin/lsblk -o label,model,mountpoint,name,partuuid,phy-sec,rota,serial,size,type,uuid,vendor,wwn -J" + (disks.sizeraw ? " -b" : "")] + }; + + FnConsole.log[2]("Disks, Lsblk, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function () { + FnConsole.log[2]("Disks, Lsblk, Get: Success"); + }) + .fail(function (message, data) { + FnConsole.warn("Disks, Lsblk, Get: Failed, Message: " + (data ? data : message)); + }); +} + +function FnDisksStoragePoolsAttachedGet(pool = { name, id }, disks = { id: { blockdevice: true } }) { + let process = { + command: ["/bin/sh", "-c", ((zfsmanager.user.name == "root" || !zfsmanager.user.name) ? "ZPOOL_SCRIPTS_AS_ROOT=1 " : "") + "/sbin/zpool status -P " + (disks.id.blockdevice ? "-L " : "") + "-c upath" + (pool.name ? ` "` + pool.name + `"` : "")] + }; + + FnConsole.log[2]("Disks, Storage Pools, Attached, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function () { + FnConsole.log[2]("Disks, Storage Pools, Attached, Get: Success"); + }) + .fail(function (message, data) { + FnConsole.warn("Disks, Storage Pools, Attached, Get: Failed, Message: " + (data ? data : message)); + }); +} + +function FnDisksStoragePoolsImportableAttachedGet() { + let process = { + command: ["/sbin/zpool", "import", "-d", "/dev"] + }; + + FnConsole.log[2]("Disks, Storage Pools, Importable, Attached, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnConsole.log[2]("Disks, Storage Pools, Importable, Attached, Get: Success"); + }) + .fail(function (message, data) { + FnConsole.warn("Disks, Storage Pools, Importable, Attached, Get: Failed, Message: " + (data ? data : message)); + }); +} + +function FnDisksStoragePoolsImportableGet() { + let process = { + command: ["/bin/sh", "-c", "/sbin/zpool import | /bin/grep -E 'pool:\| id:' | tr '\\\n' ','"] + }; + + FnConsole.log[2]("Disks, Importable Storage Pools, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnConsole.log[2]("Disks, Importable Storage Pools, Get: Success"); + }) + .fail(function (message, data) { + if (/no pools available to import/gi.test(data) == false) { + FnConsole.warn("Disks, Importable Storage Pools, Get: Failed, Message: " + (data ? data : message)); + } + }); +} + +//#endregion + +//#region Samba + +function FnSambaConfigurationReload() { + let process = { + command: ["/usr/bin/smbcontrol", "all", "reload-config"] + }; + + FnConsole.log[2]("Samba, Configuration, Reload: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnConsole.log[1]("Samba, Configuration, Reload: Success"); + }) + .fail(function (message, data) { + FnConsole.warn("Samba, Configuration, Reload: Failed, Message: " + (data ? data : message)); + }); +} + +function FnSambaConfigurationZfsSharesEnable() { + let process = { + command: ["/bin/sh", "-c", `[ -s /etc/samba/smb.conf ] && /usr/bin/awk -v k='\n\t# COCKPIT ZFS MANAGER\n\t# WARNING: DO NOT EDIT, AUTO-GENERATED CONFIGURATION\n\tinclude = /etc/cockpit/zfs/shares.conf\n\tinclude = /run/cockpit/zfs/shares.conf\n' '($1=="[global]"||x&&/^\\[/)&&!(x=!x){print k} END{if(x)print k}1' /etc/samba/smb.conf > /etc/samba/smb.tmp && /bin/mv -f /etc/samba/smb.tmp /etc/samba/smb.conf \|\| { echo '/etc/samba/smb.conf file does not exist or is empty.' ; exit 1; }`] + }; + + FnConsole.log[2]("Samba, Configuration, ZFS Shares, Enable: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnConsole.log[1]("Samba, Configuration, ZFS Shares, Enable: Success"); + + FnSambaConfigurationReload(); + }) + .fail(function (message, data) { + FnConsole.warn("Samba, Configuration, ZFS Shares, Enable: Failed, Message: " + (data ? data : message)); + }); +} + +function FnSambaConfigurationZfsSharesGet() { + let process = { + command: ["/bin/sh", "-c", "/bin/grep -Pzoq '(?s)include = /etc/cockpit/zfs/shares.conf.*/run/cockpit/zfs/shares.conf' /etc/samba/smb.conf && echo true || echo false"] + }; + + FnConsole.log[2]("Samba, Configuration, ZFS Shares, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data, message) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Configuration, ZFS Shares, Get:" })); + + data = data.replace(/\n+/g, ""); + + if (data == "false") { + FnSambaConfigurationZfsSharesEnable(); + } else if (data == "true") { + FnConsole.log[2]("Samba, Configuration, ZFS Shares, Get: Success"); + } else { + FnConsole.warn("Samba, Configuration, ZFS Shares, Get: Failed, Message: " + (data ? data : message)); + } + }) + .fail(function (message, data) { + FnConsole.warn("Samba, Configuration, ZFS Shares, Get: Failed, Message: " + (data ? data : message)); + }); +} + +function FnSambaManage() { + if (zfsmanager.user.admin) { + FnSambaConfigurationZfsSharesGet(); + } +} + +function FnSambaRestart() { + let process = { + command: ["/bin/systemctl", "restart"] + }; + + if (/Debian|Ubuntu/i.test(zfsmanager.system.operatingsystem)) { + process.command.splice(2, 0, "smbd"); + } else { + process.command.splice(2, 0, "smb"); + } + + FnConsole.log[2]("Samba, Restart: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnConsole.log[1]("Samba, Restart: Success"); + }) + .fail(function (message, data) { + FnConsole.warn("Samba, Restart: Failed, Message: " + (data ? data : message)); + }); +} + +function FnSambaShareDestroy(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id }, samba = { restart: false }, display = { silent: false }) { + let process = { + promise: cockpit.defer() + }; + + FnSambaZfsShareDisable({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id }) + .done(function () { + FnSambaZfsSharesConfigurationReload() + .done(function () { + setTimeout(function () { + if (samba.restart) { + FnSambaRestart() + .finally(function () { + if (!display.silent) { + FnDisplayAlert({ status: "success", title: "Samba share successfully destroyed", description: filesystem.name, breakword: false }, { name: "samba-destroy", id: filesystem.id, timeout: 4 }); + } + + FnConsole.log[1]("Samba, Share, Destroy: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + + process.promise.resolve(); + }); + } else { + FnSambaConfigurationReload() + .finally(function () { + if (!display.silent) { + FnDisplayAlert({ status: "success", title: "Samba share successfully destroyed", description: filesystem.name, breakword: false }, { name: "samba-destroy", id: filesystem.id, timeout: 4 }); + } + + FnConsole.log[1]("Samba, Share, Destroy: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + + process.promise.resolve(); + }); + } + }, 500); + }) + }) + .fail(function () { + process.promise.resolve(); + }); + + return process.promise.promise(); +} + +function FnSambaShareDisable(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id }, samba = { restart: false }, display = { modal: true, silent: false }) { + if (display.modal) { + $("#spinner-storagepool-filesystem-samba-disable-" + filesystem.id + " span").text("Disabling Samba share..."); + } + + if (!pool.readonly) { + FnFileSystemShareSmbDisable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }) + .done(function () { + FnSambaShareDisableCommand({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id }, { restart: samba.restart }, { modal: display.modal, silent: display.silent }); + }) + .fail(function (message, data) { + if (/property may be set/gi.test(data)) { //False error is generated when configuring filesystem + FnSambaShareDisableCommand({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id }, { restart: samba.restart }, { modal: display.modal, silent: display.silent }); + } else { + if (!display.silent) { + FnDisplayAlert({ status: "danger", title: "Samba share could not be disabled", description: filesystem.name, breakword: false }, { name: "samba-disable", id: filesystem.id, timeout: 4 }); + } + + if (display.modal) { + $("#modal-storagepool-filesystem-samba-disable-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: false, status: false }); + }, 200); + } + } + }); + } else { + FnSambaShareDisableCommand({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id }, { restart: samba.restart }, { modal: display.modal, silent: display.silent }); + } +} + +function FnSambaShareDisableCommand(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id }, samba = { restart: false }, display = { modal: true, silent: false }) { + FnSambaZfsShareDisable({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id }) + .done(function () { + FnSambaZfsSharesConfigurationReload() + .done(function () { + setTimeout(function () { + if (samba.restart) { + FnSambaRestart() + .finally(function () { + if (!display.silent) { + FnDisplayAlert({ status: "success", title: "Samba share successfully disabled", description: filesystem.name, breakword: false }, { name: "samba-disable", id: filesystem.id, timeout: 4 }); + } + + if (display.modal) { + $("#modal-storagepool-filesystem-samba-disable-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: false, status: false }); + }, 200); + } + }); + } else { + FnSambaConfigurationReload() + .finally(function () { + if (!display.silent) { + FnDisplayAlert({ status: "success", title: "Samba share successfully disabled", description: filesystem.name, breakword: false }, { name: "samba-diable", id: filesystem.id, timeout: 4 }); + } + + if (display.modal) { + $("#modal-storagepool-filesystem-samba-disable-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: false, status: false }); + }, 200); + } + }); + } + }, 500); + }) + .fail(function () { + FnFileSystemShareSmbEnable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }); + }); + }) + .fail(function () { + FnFileSystemShareSmbEnable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }); + }); +} + +function FnSambaShareEnable(pool = { name, id, readonly: false }, filesystem = { name, id, mounted: false, mountpoint }, samba = { share: { additional: [], administrative: false, browseable: true, guestok: false, name, comment, readonly: false, temporary: false } }, display = { silent: false }) { + let modal = { + hide: true + }; + + $("#spinner-storagepool-filesystem-samba-enable-" + filesystem.id + " span").text("Enabling Samba share..."); + + FnSambaShareNamesGet({ zfsonly: false }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Share, Names, Get:" })); + + samba.share.nameunique = true; + samba.share.errormessage = "Share name is already in use."; + + if (data.replace(/\n/g, "") != "$empty") { //$empty response is received if share names list is empty + samba.shares = data.split(/\n/g).filter(v => v); + + samba.shares.forEach((_value, _index) => { + if (_value.replace(/^\[/, "").replace(/\]$/, "").toLowerCase() == samba.share.name.toLowerCase() + (samba.share.administrative ? "$" : "")) { + samba.share.nameunique = false; + + return; + } + }); + } + + if (/^global$|^homes$|^printers$/gi.test(samba.share.name)) { + samba.share.nameunique = false; + samba.share.errormessage = "Share name can not be a restricted name."; + } + + if (!samba.share.nameunique) { + modal.hide = false; + + $("#validationwrapper-storagepool-filesystem-samba-enable-name-" + filesystem.id).addClass("has-error"); + $("#helpblock-storagepool-filesystem-samba-enable-name-" + filesystem.id).addClass("has-error").removeClass("hidden").text(samba.share.errormessage); + $("#input-storagepool-filesystem-samba-enable-name-" + filesystem.id).focus(); + + if (!modal.hide) { + $("#spinner-storagepool-filesystem-samba-enable-" + filesystem.id).addClass("hidden"); + $("#spinner-storagepool-filesystem-samba-enable-" + filesystem.id + " span").text(""); + $("#btn-storagepool-filesystem-samba-enable-apply-" + filesystem.id).prop("disabled", false); + + FnConsole.warn("Samba, Share, Enable: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + samba.share.errormessage); + } + } else { + FnSambaShareEnableCommand({ name: pool.name, id: pool.id, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, force: false, mounted: filesystem.mounted, mountpoint: filesystem.mountpoint, sharesmb: false }, { reload: true, share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary } }, { refresh: true, silent: display.silent }); + + $("#modal-storagepool-filesystem-samba-enable-" + filesystem.id).modal("hide"); + } + }); +} + +function FnSambaShareEnableAutoGenerateName(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, force: false, mounted: false, mountpoint, sharesmb: false }, samba = { reload: true }, display = { refresh: true, silent: false }) { + FnSambaShareNamesGet({ zfsonly: false }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Share, Names, Get:" })); + + samba.share = { + name: "", + nameunique: true, + temporary: (pool.altroot || pool.readonly ? true : false) + };; + + if (data.replace(/\n/g, "") != "$empty") { //$empty response is received if share names list is empty + samba.shares = data.split(/\n/g).filter(v => v); + + samba.shares.forEach((_value, _index) => { + if (_value.replace(/^\[/, "").replace(/\]$/, "").toLowerCase() == filesystem.name.replace(/^.*\/(.*)$/, "$1").toLowerCase()) { + samba.share.nameunique = false; + + return; + } + }); + } + + if (/^global$|^homes$|^printers$/gi.test(samba.share.name)) { + samba.share.nameunique = false; + } + + if (!samba.share.nameunique) { + samba.share.name = FnGenerateShareName({ at: false, colon: false, period: false, whitespace: false }, { name: filesystem.name }); + + if (filesystem.name == pool.name) { + samba.share.name = "StoragePool-" + samba.share.name; + } + + FnSambaShareEnableCommand({ name: pool.name, id: pool.id, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, force: false, mounted: filesystem.mounted, mountpoint: filesystem.mountpoint, sharesmb: filesystem.sharesmb }, { reload: samba.reload, share: { additional: [], administrative: false, browseable: true, guestok: false, name: samba.share.name, comment: null, readonly: null, temporary: samba.share.temporary } }, { refresh: display.refresh, silent: display.silent }); + } else { + FnSambaShareEnableCommand({ name: pool.name, id: pool.id, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, force: false, mounted: filesystem.mounted, mountpoint: filesystem.mountpoint, sharesmb: filesystem.sharesmb }, { reload: samba.reload, share: { additional: [], administrative: false, browseable: true, guestok: false, name: null, comment: null, readonly: null, temporary: samba.share.temporary } }, { refresh: display.refresh, silent: display.silent }); + } + }); +} + +function FnSambaShareEnableCommand(pool = { name, id, readonly: false }, filesystem = { name, force: false, id, mounted: false, mountpoint, sharesmb: false }, samba = { reload: true, share: { additional: [], administrative: false, browseable: true, guestok: false, name, comment, readonly: false, temporary: false } }, display = { refresh: true, silent: false }) { + if (!pool.readonly && (!filesystem.sharesmb || filesystem.sharesmb && filesystem.force)) { //Force to disable inheritance + FnFileSystemShareSmbEnable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }) + .done(function () { + FnSambaShareEnableCommandFinally({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, mounted: filesystem.mounted, mountpoint: filesystem.mountpoint }, { reload: samba.reload, share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary } }, { refresh: display.refresh, silent: display.silent }); + }) + .fail(function (message, data) { + if (/property may be set/gi.test(data)) { //False error is generated when configuring filesystem + FnSambaShareEnableCommandFinally({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, mounted: filesystem.mounted, mountpoint: filesystem.mountpoint }, { share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary } }, { refresh: display.refresh, silent: display.silent }); + } else { + if (!display.silent) { + FnDisplayAlert({ status: "danger", title: "Samba share could not be enabled", description: filesystem.name, breakword: false }, { name: "samba-enable", id: filesystem.id, timeout: 4 }); + } + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: false, status: false }); + }, 200); + } + }); + } else { + FnSambaShareEnableCommandFinally({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, mounted: filesystem.mounted, mountpoint: filesystem.mountpoint }, { reload: samba.reload, share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary } }, { refresh: display.refresh, silent: display.silent }); + } +} + +function FnSambaShareEnableCommandFinally(pool = { name, id }, filesystem = { name, id, mounted: false, mountpoint }, samba = { reload: true, share: { additional: [], administrative: false, browseable: true, guestok: false, name, comment, readonly: false, temporary: false } }, display = { refresh: true, silent: false }) { + FnSambaZfsShareEnable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, mountpoint: filesystem.mountpoint }, { share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary } }) + .done(function () { + if (!display.silent) { + FnDisplayAlert({ status: "success", title: "Samba share successfully enabled", description: filesystem.name, breakword: false }, { name: "samba-enable", id: filesystem.id, timeout: 4 }); + } + + if (samba.reload) { + FnSambaZfsSharesConfigurationReload() + .done(function () { + setTimeout(function () { + FnSambaConfigurationReload() + .finally(function () { + if (display.refresh) { + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: false, status: false }); + }, 200); + } + }); + }, 500); + }) + .fail(function () { + FnFileSystemShareSmbDisable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }); + }); + } else { + if (display.refresh) { + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: false, status: false }); + }, 200); + } + } + }) + .fail(function () { + FnFileSystemShareSmbDisable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }); + }); +} + +function FnSambaShareEnableMountpointGet(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, sharesmb: false }, display = { silent: false }) { + let process = { + command: ["/sbin/zfs", "list", "-H", "-o", "mounted,mountpoint", "-t", "filesystem", filesystem.name] + }; + + FnConsole.log[2]("File Systems, Mountpoint, Get: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data, message) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "File Systems, Mountpoint, Get:" })); + + data = data.replace(/\n/g, "").replace(/\t/g, "\u22C5").split("\u22C5"); + + filesystem.mounted = data[0]; + filesystem.mountpoint = data[1]; + + if (/^\//.test(filesystem.mountpoint)) { + FnConsole.log[1]("File Systems, Mountpoint, Get: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + + FnSambaShareEnableAutoGenerateName({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, force: false, mounted: filesystem.mounted, mountpoint: filesystem.mountpoint, sharesmb: filesystem.sharesmb }, { reload: true }, { refresh: true, silent: display.silent }); + } else { + FnConsole.warn("File Systems, Mountpoint, Get: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); + } + }) + .fail(function (message, data) { + FnConsole.warn("File Systems, Mountpoint, Get: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); + + FnFileSystemShareSmbDisable({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id }); + }); +} + +function FnSambaShareNamesGet(samba = { zfsonly: false }) { + let process = { + command: ["/bin/sh", "-c", `/bin/cat /etc/cockpit/zfs/shares/*.conf /run/cockpit/zfs/shares/*.conf ` + (!samba.zfsonly ? `/etc/samba/smb.conf ` : ``) + `2> /dev/null | /bin/grep "^\\\[.*\\\]$" || echo \\\$empty`] + }; + + FnConsole.log[2]("Samba, Share, Names, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function () { + FnConsole.log[1]("Samba, Share, Names, Get: Success"); + }) + .fail(function (message, data) { + FnConsole.warn("Samba, Share, Names, Get: Failed, Message: " + (data ? data : message)); + }); +} + +function FnSambaSharesDestroy(pool = { name, id, altroot: false, readonly: false }, filesystems = { id: [] }, samba = { restart: false }, display = { silent: true }) { + let process = { + promise: cockpit.defer() + }; + let promise = Promise.resolve(); + + FnConsole.log[1]("Samba, Shares, Destroy: In Progress, Pool: " + pool.name); + + if (filesystems.id.length > 0) { + filesystems.id.forEach((_value, _index) => { + let filesystem = { + properties: _value.split(/\t/g).filter(v => v) + }; + + filesystem.name = filesystem.properties[0]; + filesystem.id = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: filesystem.properties[0], attribute: true }); + filesystem.mounted = filesystem.properties[1]; + filesystem.mountpoint = filesystem.properties[2]; + filesystem.sharesmb = filesystem.properties[3]; + + promise = promise.then(_ => new Promise(resolve => + setTimeout(function () { + if (_index <= (filesystems.id.length - 1)) { + if (filesystem.sharesmb == "on") { + FnSambaZfsShareDisable({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id }); + } + } + + if (_index == (filesystems.id.length - 1)) { + setTimeout(function () { + if (!display.silent) { + FnDisplayAlert({ status: "success", title: "Samba shares successfully destroyed", description: pool.name, breakword: false }, { name: "samba-destroy", id: pool.id, timeout: 4 }); + } + + FnConsole.log[1]("Samba, Shares, Destroy: Success, Pool: " + pool.name); + + FnSambaZfsSharesConfigurationReload() + .done(function () { + setTimeout(function () { + if (samba.restart) { + FnSambaRestart() + .finally(function () { + process.promise.resolve(); + }); + } else { + FnSambaConfigurationReload() + .finally(function () { + process.promise.resolve(); + }); + } + }, 300); + }); + }, 500); + } + + resolve(); + }, 500) + )); + }); + } else { + if (!display.silent) { + FnDisplayAlert({ status: "success", title: "Samba shares successfully destroyed", description: pool.name, breakword: false }, { name: "samba-destroy", id: pool.id, timeout: 4 }); + } + + FnConsole.log[1]("Samba, Shares, Destroy: Success, Pool: " + pool.name); + + process.promise.resolve(); + } + + return process.promise.promise(); +} + +function FnSambaSharesDestroyAll(samba = { restart: false }, display = { silent: false }, modal = { name }) { + let process = { + command: ["/bin/sh", "-c", "echo '# COCKPIT ZFS MANAGER\n# WARNING: DO NOT EDIT, AUTO-GENERATED CONFIGURATION' > /etc/cockpit/zfs/shares.conf && echo '# COCKPIT ZFS MANAGER\n# WARNING: DO NOT EDIT, AUTO-GENERATED CONFIGURATION' > /run/cockpit/zfs/shares.conf && /bin/rm -rf /etc/cockpit/zfs/shares/*.conf && /bin/rm -rf /run/cockpit/zfs/shares/*.conf"], + promise: cockpit.defer() + }; + + FnConsole.log[1]("Samba, Shares, Destroy All: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + $("#spinner-" + modal.name + " span").text("Destroying Samba shares..."); + + cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + if (!display.silent) { + FnDisplayAlert({ status: "success", title: "Samba shares successfully destroyed", description: null, breakword: false }, { name: "samba-destroy-all", id: null, timeout: 4 }); + } + + FnConsole.log[1]("Samba, Shares, Destroy All: Success"); + + if (samba.restart) { + FnSambaRestart() + .finally(function () { + process.promise.resolve(); + }); + } else { + FnSambaConfigurationReload() + .finally(function () { + process.promise.resolve(); + }); + } + }) + .fail(function (message, data) { + if (!display.silent) { + FnDisplayAlert({ status: "danger", title: "Samba shares could not be destroyed", description: null, breakword: false }, { name: "samba-destroy-all", id: null, timeout: 4 }); + } + + FnConsole.warn("Samba, Shares, Destroy All: Failed, Message: " + (data ? data : message)); + + process.promise.resolve(); + }); + + return process.promise.promise(); +} + +function FnSambaSharesEnable(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, force: false }, samba = { restart: false }, display = { refresh: false, silent: true }) { + let process = { + command: ["/sbin/zfs", "list", "-H", "-o", "name,mounted,mountpoint,sharesmb", "-r", "-t", "filesystem"], + promise: cockpit.defer() + }; + + if (filesystem.name) { + process.command.push(filesystem.name); + } else { + process.command.push(pool.name); + } + + FnConsole.log[1]("Samba, Shares, Enable: In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Shares, Enable:" })); + + let filesystems = { + id: data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) + }; + let promise = Promise.resolve(); + + if (filesystems.id.length > 0) { + filesystems.id.forEach((_value, _index) => { + let filesystem = { + properties: _value.split(/\t/g).filter(v => v) + }; + + filesystem.name = filesystem.properties[0]; + filesystem.id = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: filesystem.properties[0], attribute: true }); + filesystem.mounted = filesystem.properties[1]; + filesystem.mountpoint = filesystem.properties[2]; + filesystem.sharesmb = filesystem.properties[3]; + + promise = promise.then(_ => new Promise(resolve => + setTimeout(function () { + if (_index <= (filesystems.id.length - 1)) { + if (filesystem.sharesmb == "on") { + FnSambaShareEnableAutoGenerateName({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, force: filesystem.force, mounted: filesystem.mounted, mountpoint: filesystem.mountpoint, sharesmb: true }, { reload: false }, { refresh: false, silent: true }); + } + } + + if (_index == (filesystems.id.length - 1)) { + setTimeout(function () { + if (!display.silent) { + FnDisplayAlert({ status: "success", title: "Samba shares successfully enabled", description: pool.name, breakword: false }, { name: "samba-enable", id: pool.id, timeout: 4 }); + } + + FnConsole.log[1]("Samba, Shares, Enable: Success, Pool: " + pool.name); + + FnSambaZfsSharesConfigurationReload() + .done(function () { + setTimeout(function () { + if (samba.restart) { + FnSambaRestart() + .finally(function () { + if (display.refresh) { + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 500); + } + + process.promise.resolve(); + }); + } else { + FnSambaConfigurationReload() + .finally(function () { + if (display.refresh) { + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 500); + } + + process.promise.resolve(); + }); + } + }, 300); + }); + }, 500); + } + + resolve(); + }, 500) + )); + }); + } else { + if (!display.silent) { + FnDisplayAlert({ status: "success", title: "Samba shares successfully enabled", description: pool.name, breakword: false }, { name: "samba-enable", id: pool.id, timeout: 4 }); + } + + FnConsole.log[1]("Samba, Shares, Enable: Success, Pool: " + pool.name); + + process.promise.resolve(); + } + }) + .fail(function (message, data) { + if (!display.silent) { + FnDisplayAlert({ status: "danger", title: "Samba shares could not enabled", description: pool.name, breakword: false }, { name: "samba-enable", id: pool.id, timeout: 4 }); + } + + FnConsole.warn("Samba, Shares, Enable: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); + + if (display.refresh) { + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 500); + } + + process.promise.resolve(); + }); + + return process.promise.promise(); +} + +function FnSambaSharesEnableAll(samba = { restart: false }, display = { silent: false }, modal = { name }) { + let process = { + command: ["/sbin/zfs", "list", "-H", "-o", "name,mounted,mountpoint,sharesmb", "-r", "-t", "filesystem"], + promise: cockpit.defer() + }; + + FnConsole.log[1]("Samba, Shares, Enable All: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + FnStoragePoolsTemporaryGet() + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Storage Pools, Temporary, Get:" })); + + $("#spinner-" + modal.name + " span").text("Disabling Samba share inheritance..."); + + FnFileSystemShareSmbInheritedDisable({ name: null, id: null, altroot: null }, { name: null }, { disable: false }) + .finally(function () { + $("#spinner-" + modal.name + " span").text("Creating Samba shares..."); + + cockpit.spawn(process.command, { err: "out" }) + .done(function (_data) { + FnConsole.log[4](FnConsoleVerbose({ data: _data, message: "Samba, Shares, Enable All:" })); + + let filesystems = { + id: _data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) + }; + let promise = Promise.resolve(); + + if (filesystems.id.length > 0) { + filesystems.id.forEach((_value, _index) => { + let filesystem = { + properties: _value.split(/\t/g).filter(v => v) + }; + let pool = { + name: filesystem.properties[0].replace(/\/.*$/, ""), + id: FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: filesystem.properties[0].replace(/\/.*$/, ""), attribute: true }) + }; + + filesystem.name = filesystem.properties[0]; + filesystem.id = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: filesystem.properties[0], attribute: true }); + filesystem.mounted = filesystem.properties[1]; + filesystem.mountpoint = filesystem.properties[2]; + filesystem.sharesmb = filesystem.properties[3]; + + promise = promise.then(_ => new Promise(resolve => + setTimeout(function () { + if (_index <= (filesystems.id.length - 1)) { + if (filesystem.sharesmb == "on") { + + pool.properties = data.split(/\n/g).filter(v => v && new RegExp("^" + pool.name + "\t").test(v))[0].split(/\t/g).filter(v => v); + + if (pool.properties[0] == pool.name) { + pool.altroot = (pool.properties[2] && pool.properties[2] != "-" ? true : false); + pool.readonly = (pool.properties[1].toLowerCase() == "on" ? true : false); + + FnSambaShareEnableAutoGenerateName({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id, force: false, mounted: filesystem.mounted, mountpoint: filesystem.mountpoint, sharesmb: true }, { reload: false }, { refresh: false, silent: true }); + } + } + } + + if (_index == (filesystems.id.length - 1)) { + setTimeout(function () { + if (!display.silent) { + FnDisplayAlert({ status: "success", title: "Samba shares successfully enabled", description: null, breakword: false }, { name: "samba-enable-all", id: null, timeout: 4 }); + } + + FnConsole.log[1]("Samba, Shares, Enable All: Success"); + + FnSambaZfsSharesConfigurationReload() + .done(function () { + setTimeout(function () { + if (samba.restart) { + FnSambaRestart() + .finally(function () { + process.promise.resolve(); + }); + } else { + FnSambaConfigurationReload() + .finally(function () { + process.promise.resolve(); + }); + } + }, 300); + }); + }, 500); + } + + resolve(); + }, 500) + )); + }); + } else { + if (!display.silent) { + FnDisplayAlert({ status: "success", title: "Samba shares successfully enabled", description: null, breakword: false }, { name: "samba-enable-all", id: null, timeout: 4 }); + } + + FnConsole.log[1]("Samba, Shares, Enable All: Success"); + + process.promise.resolve(); + } + }) + .fail(function (message, data) { + if (!display.silent) { + FnDisplayAlert({ status: "danger", title: "Samba shares could not be enabled", description: null, breakword: false }, { name: "samba-enable-all", id: null, timeout: 4 }); + } + + FnConsole.warn("Samba, Shares, Enable All: Failed, Message: " + (data ? data : message)); + + process.promise.resolve(); + }); + }); + }) + .fail(function (message, data) { + if (!display.silent) { + FnDisplayAlert({ status: "danger", title: "Samba shares could not be enabled", description: null, breakword: false }, { name: "samba-enable-all", id: null, timeout: 4 }); + } + + FnConsole.warn("Samba, Shares, Enable All: Failed, Message: " + (data ? data : message)); + + process.promise.resolve(); + }); + + return process.promise.promise(); +} + +function FnSambaSharesGet(pool = { name, id }, filesystem = { name, clones: [] }) { + let process = { + command: ["/sbin/zfs", "list", "-H", "-o", "name,mounted,mountpoint,sharesmb", "-r", "-t", "filesystem"] + }; + + if (filesystem.name) { + process.command.push(filesystem.name); + } else if (filesystem.clones.length > 0) { + filesystem.clones.forEach(_value => _value && process.command.push(_value)); + } else { + process.command.push(pool.name); + } + + FnConsole.log[2]("Samba, Shares, Get: In Progress, Pool: " + pool.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function () { + FnConsole.log[1]("Samba, Shares, Get: Success, Pool: " + pool.name); + }) + .fail(function (message, data) { + FnConsole.warn("Samba, Shares, Get: Failed, Pool: " + pool.name + ", Message: " + (data ? data : message)); + }); +} + +function FnSambaSharesRename(pool = { name, id, altroot: false, readonly: false }, filesystems = { id: [], parent: { name, namenew } }, samba = { restart: false }, display = { silent: true }) { + let process = { + promise: cockpit.defer() + }; + let promise = Promise.resolve(); + + FnConsole.log[1]("Samba, Shares, Rename: In Progress, Pool: " + pool.name); + + if (filesystems.id.length > 0) { + filesystems.id.forEach((_value, _index) => { + let filesystem = { + properties: _value.split(/\t/g).filter(v => v) + }; + + filesystem.name = filesystem.properties[0]; + filesystem.id = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: filesystem.properties[0], attribute: true }); + filesystem.mounted = filesystem.properties[1]; + filesystem.mountpoint = filesystem.properties[2]; + filesystem.sharesmb = filesystem.properties[3]; + + filesystem.namenew = filesystem.name.replace(new RegExp("^" + filesystems.parent.name), filesystems.parent.namenew); + filesystem.idnew = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: filesystem.namenew, attribute: true }); + + promise = promise.then(_ => new Promise(resolve => + setTimeout(function () { + if (_index <= (filesystems.id.length - 1)) { + if (filesystem.sharesmb == "on") { + FnFileSystemMountpointGet({ name: pool.name, id: pool.id }, { name: filesystem.namenew, id: filesystem.idnew }) + .done(function (data) { + filesystem.mountpoint = data.replace(/\n$/, ""); + + FnSambaZfsShareConfigurationPathSet({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: filesystem.name, namenew: filesystem.namenew, id: filesystem.id, mountpoint: filesystem.mountpoint }) + .finally(function () { + FnSambaZfsShareDisable({ name: pool.name, id: pool.id, altroot: pool.altroot, readonly: pool.readonly }, { name: filesystem.name, id: filesystem.id }); + }); + }); + } + } + + if (_index == (filesystems.id.length - 1)) { + setTimeout(function () { + if (!display.silent) { + FnDisplayAlert({ status: "success", title: "Samba shares successfully renamed", description: pool.name, breakword: false }, { name: "samba-rename", id: pool.id, timeout: 4 }); + } + + FnConsole.log[1]("Samba, Shares, Rename: Success, Pool: " + pool.name); + + FnSambaZfsSharesConfigurationReload() + .done(function () { + setTimeout(function () { + if (samba.restart) { + FnSambaRestart() + .finally(function () { + process.promise.resolve(); + }); + } else { + FnSambaConfigurationReload() + .finally(function () { + process.promise.resolve(); + }); + } + }, 300); + }); + }, 800); + } + + resolve(); + }, 800) + )); + }); + } else { + if (!display.silent) { + FnDisplayAlert({ status: "success", title: "Samba shares successfully renamed", description: pool.name, breakword: false }, { name: "samba-rename", id: pool.id, timeout: 4 }); + } + + FnConsole.log[1]("Samba, Shares, Rename: Success, Pool: " + pool.name); + + process.promise.resolve(); + } + + return process.promise.promise(); +} + +function FnSambaStart() { + let process = { + command: ["/bin/systemctl", "start"] + }; + + if (/Debian|Ubuntu/i.test(zfsmanager.system.operatingsystem)) { + process.command.splice(2, 0, "smbd"); + } else { + process.command.splice(2, 0, "smb"); + } + + FnConsole.log[2]("Samba, Start: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnConsole.log[1]("Samba, Start: Success"); + }) + .fail(function (message, data) { + FnConsole.warn("Samba, Start: Failed, Message: " + (data ? data : message)); + }); +} + +function FnSambaStop() { + let process = { + command: ["/bin/systemctl", "stop"] + }; + + if (/Debian|Ubuntu/i.test(zfsmanager.system.operatingsystem)) { + process.command.splice(2, 0, "smbd"); + } else { + process.command.splice(2, 0, "smb"); + } + + FnConsole.log[2]("Samba, Stop: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnConsole.log[1]("Samba, Stop: Success"); + }) + .fail(function (message, data) { + FnConsole.warn("Samba, Stop: Failed, Message: " + (data ? data : message)); + }); +} + +function FnSambaUsersharesDirectoryCreate() { + let process = { + command: ["/bin/sh", "-c", `[ ! -d /var/lib/samba/usershares ] && /bin/mkdir -p /var/lib/samba/usershares || printf "Skipped"`] + }; + + FnConsole.log[2]("Samba, Usershares Directory, Create: In Progress") + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Usershares Directory, Create:" })); + + if (data == "Skipped") { + FnConsole.log[2]("Samba, Usershares Directory, Create: Skipped"); + } else { + FnConsole.log[1]("Samba, Usershares Directory, Create: Success"); + } + }) + .fail(function (message, data) { + FnConsole.warn("Samba, Usershares Directory, Create: Failed, Message: " + (data ? data : message)); + }); +} + +function FnSambaVersionGet() { + let process = { + command: ["/usr/sbin/smbd", "-V"] + }; + let samba = { + message: "" + }; + + FnConsole.log[2]("Samba, Version, Get: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data, message) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Version, Get:" })); + + FnConsole.log[1]("Samba, Version, Get: Success, Version: " + (data ? data.replace(/^Version /i, "") : message.replace(/^Version /i, ""))); + + $("#alerts-requirements").empty().addClass("hidden"); + $("#container").removeClass("hidden"); + }) + .fail(function (message, data) { + FnConsole.error("Samba, Version, Get: Failed, Message: " + (data ? data : message)); + + samba.message = ` +
    + +
    +

    This package requires Samba

    +

    Install Samba software via your package manager

    +
    + +
    + `; + + $("#alerts-requirements").removeClass("hidden").html(samba.message); + $("#container").addClass("hidden"); + }); +} + +function FnSambaZfsShareConfigurationGenerate(filesystem = { name, id, mountpoint }, samba = { enable: false, share: { additional: [], administrative: false, browseable: true, guestok: false, name, comment, readonly: false, temporary: false } }) { + samba.share.conf = { + content: "", + path: "/" + (samba.share.temporary ? "run" : "etc") + "/cockpit/zfs/shares/" + FnGenerateShareFileName({ name: filesystem.name }) + ".conf" + } + + if (!samba.share.name) { + samba.share.name = FnGenerateShareName({ at: false, colon: false, period: false, whitespace: false }, { name: filesystem.name.replace(/^.*\/(.*)$/, "$1") }); + } + if (samba.share.administrative) { + samba.share.name = samba.share.name + "$"; + } + if (!samba.share.comment && samba.enable) { + samba.share.comment = "ZFS: " + filesystem.name; + } + + samba.share.additional = samba.share.additional.reduce((a, v) => { + let allow = true; + + if (/[\[\]]/g.test(v)) { //Do not allow section names + allow = false; + } + if (/^[#]/.test(v) == false && /[=]/.test(v)) { //Do not allow modal configurable properties + if (/(path|comment|browseable|read only|guest ok).*=/gi.test(v)) { + allow = false; + } + } + + if (allow) { + v = v.replace(/\\/g, "\\\\\\"); + + a.push((/^[#]/.test(v) == false && /[=]/.test(v) ? "\\t" + v : v)); + } + + return a; + }, []); + + samba.share.conf.content = "\"# COCKPIT ZFS MANAGER\n# WARNING: DO NOT EDIT, AUTO-GENERATED CONFIGURATION\\n\[" + samba.share.name + "\]\\n\\tpath \= " + filesystem.mountpoint + "\\n\\tcomment \= " + samba.share.comment + "\\n\\tbrowseable = " + (samba.share.browseable ? "yes" : "no") + "\\n\\tread only = " + (samba.share.readonly ? "yes" : "no") + "\\n\\tguest ok = " + (samba.share.guestok ? "yes" : "no") + "\\n\\n# ADD ADDITIONAL CONFIGURATION HERE\\n" + samba.share.additional.join("\\n") + "\\n\" > \"" + samba.share.conf.path + "\""; + + return samba.share.conf.content; +} + +function FnSambaZfsShareConfigurationGet(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id }, modal = { name, id }) { + let process = { + command: ["/bin/cat", "/" + (pool.altroot || pool.readonly ? "run" : "etc") + "/cockpit/zfs/shares/" + FnGenerateShareFileName({ name: filesystem.name }) + ".conf"] + }; + let samba = { + share: { + name: "", + path: "", + comment: "", + administrative: false, + browseable: true, + guestok: false, + readonly: false, + additional: [] + } + }; + + FnConsole.log[2]("Samba, ZFS Share Configuration, Get: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, ZFS Share Configuration, Get:" })); + + samba.share.conf = data.split(/\n/g).filter(v => v); + + samba.share.conf.forEach((_value, _index) => { + _value = _value.replace(/\t/g, ""); + + //2=name, 3=path, 4=comment, 5=browseable, 6=read only, 7=guest ok + + switch (_index) { + case 2: //2=name + if (/^\[.*\]$/g.test(_value)) { + samba.share.name = _value.replace(/\[/g, "").replace(/\]/g, ""); + + if (/[$]$/.test(samba.share.name)) { + samba.share.administrative = true; + samba.share.name = samba.share.name.replace(/[$]$/, ""); + } + } + + break; + case 3: //3=path + if (/path \=/gi.test(_value)) { + samba.share.path = _value.replace("path = ", "").replace(/["]/g, ""); + } + + break; + case 4: //4=comment + if (/comment \=/gi.test(_value)) { + samba.share.comment = _value.replace("comment = ", "").replace(/["]/g, ""); + } + + break; + case 5: //5=browseable + if (/browseable \=/gi.test(_value)) { + samba.share.browseable = (_value.replace("browseable = ", "").replace(/["]/g, "") == "yes" ? true : false); + } + + break; + case 6: //6=read only + if (/read only \=/gi.test(_value)) { + samba.share.readonly = (_value.replace("read only = ", "").replace(/["]/g, "") == "yes" ? true : false); + } + + break; + case 7: //7=guest ok + if (/guest ok \=/gi.test(_value)) { + samba.share.guestok = (_value.replace("guest ok = ", "").replace(/["]/g, "") == "yes" ? true : false); + } + + break; + } + }); + + samba.share.additional = samba.share.conf.filter((v, i) => i > 8).map(v => v.replace(/^\s+/, "")); + + FnConsole.log[1]("Samba, ZFS Share Configuration, Get: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + }) + .fail(function (message, data) { + FnConsole.warn("Samba, ZFS Share Configuration, Get: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); + }) + .finally(function () { + $("#input-" + modal.name + "-name-" + modal.id).val(samba.share.name).attr("data-field-value", samba.share.name); + $("#input-" + modal.name + "-comment-" + modal.id).val(samba.share.comment); + $("#textarea-" + modal.name + "-additional-" + modal.id).val(samba.share.additional.join("\n")); + + if (samba.share.administrative && !$("#switch-" + modal.name + "-administrative-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-administrative-" + modal.id + " input").click(); + } + if (!samba.share.browseable && $("#switch-" + modal.name + "-browseable-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-browseable-" + modal.id + " input").click(); + } + if (samba.share.guestok && !$("#switch-" + modal.name + "-guestok-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-guestok-" + modal.id + " input").click(); + } + if (samba.share.readonly && !$("#switch-" + modal.name + "-readonly-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-readonly-" + modal.id + " input").click(); + } + + if (!samba.share.name) { + $("#alert-" + modal.name + "-configurationmissing-" + modal.id).removeClass("hidden"); + + $("#input-" + modal.name + "-name-" + modal.id).val(FnGenerateShareName({ at: false, colon: false, period: false, whitespace: false }, { name: filesystem.name.replace(/^.*\/(.*)$/, "$1") })).focus(); + if (!samba.share.comment) { + $("#input-" + modal.name + "-comment-" + modal.id).val("ZFS: " + filesystem.name); + } + } + if (samba.share.additional.length > 0 && !$("#switch-" + modal.name + "-additional-" + modal.id + " input").prop("checked")) { + $("#switch-" + modal.name + "-additional-" + modal.id + " input").click(); + } + }); +} + +function FnSambaZfsShareConfigurationPathSet(pool = { name, id, altroot: false }, filesystem = { name, namenew, id, mountpoint }, display = { silent: true }) { + let process = { + command: ["/bin/cat", "/" + (pool.altroot ? "run" : "etc") + "/cockpit/zfs/shares/" + FnGenerateShareFileName({ name: filesystem.name }) + ".conf"], + promise: cockpit.defer() + }; + let samba = { + share: { + name: "", + path: "", + comment: "", + administrative: false, + browseable: true, + guestok: false, + readonly: false, + temporary: (pool.altroot ? true : false), + additional: [] + } + }; + + FnConsole.log[2]("Samba, ZFS Share Configuration, Get: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, ZFS Share Configuration, Get:" })); + + samba.share.conf = data.split(/\n/g).filter(v => v); + + samba.share.conf.forEach((_value, _index) => { + _value = _value.replace(/\t/g, ""); + + //2=name, 3=path, 4=comment, 5=browseable, 6=read only, 7=guest ok + + switch (_index) { + case 2: //2=name + if (/^\[.*\]$/g.test(_value)) { + samba.share.name = _value.replace(/\[/g, "").replace(/\]/g, ""); + + if (/[$]$/.test(samba.share.name)) { + samba.share.administrative = true; + samba.share.name = samba.share.name.replace(/[$]$/, ""); + } + } + + break; + case 3: //3=path + if (/path \=/gi.test(_value)) { + samba.share.path = _value.replace("path = ", "").replace(/["]/g, ""); + } + + break; + case 4: //4=comment + if (/comment \=/gi.test(_value)) { + samba.share.comment = _value.replace("comment = ", "").replace(/["]/g, ""); + } + + break; + case 5: //5=browseable + if (/browseable \=/gi.test(_value)) { + samba.share.browseable = (_value.replace("browseable = ", "").replace(/["]/g, "") == "yes" ? true : false); + } + + break; + case 6: //6=read only + if (/read only \=/gi.test(_value)) { + samba.share.readonly = (_value.replace("read only = ", "").replace(/["]/g, "") == "yes" ? true : false); + } + + break; + case 7: //7=guest ok + if (/guest ok \=/gi.test(_value)) { + samba.share.guestok = (_value.replace("guest ok = ", "").replace(/["]/g, "") == "yes" ? true : false); + } + + break; + } + }); + + samba.share.additional = samba.share.conf.filter((v, i) => i > 8).map(v => v.replace(/^\s+/, "")); + + FnConsole.log[1]("Samba, ZFS Share Configuration, Get: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + + if (filesystem.mountpoint != samba.share.path || filesystem.namenew) { + if (filesystem.namenew) { + if ((filesystem.name.replace(/^.*\/(.*)$/, "$1") != filesystem.namenew.replace(/^.*\/(.*)$/, "$1") && samba.share.name.toLowerCase() == FnGenerateShareName({ at: false, colon: false, period: false, whitespace: false }, { name: filesystem.name.replace(/^.*\/(.*)$/, "$1") }).toLowerCase()) || samba.share.name.toLowerCase() == FnGenerateShareName({ at: false, colon: false, period: false, whitespace: false }, { name: filesystem.name }).toLowerCase()) { + samba.share.nameunique = true; + + FnSambaShareNamesGet({ zfsonly: false }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Share, Names, Get:" })); + + if (data.replace(/\n/g, "") != "$empty") { //$empty response is received if share names list is empty + samba.shares = data.split(/\n/g).filter(v => v); + + samba.shares.forEach((_value, _index) => { + if (_value.replace(/^\[/, "").replace(/\]$/, "").toLowerCase() == filesystem.namenew.replace(/^.*\/(.*)$/, "$1").toLowerCase() + (samba.share.administrative ? "$" : "")) { + samba.share.nameunique = false; + + return; + } + }); + } + + if (/^global$|^homes$|^printers$/gi.test(samba.share.name)) { + samba.share.nameunique = false; + } + + if (!samba.share.nameunique) { + samba.share.name = FnGenerateShareName({ at: false, colon: false, period: false, whitespace: false }, { name: filesystem.namenew }); + } else { + samba.share.name = FnGenerateShareName({ at: false, colon: false, period: false, whitespace: false }, { name: filesystem.namenew.replace(/^.*\/(.*)$/, "$1") }); + } + + filesystem.name = filesystem.namenew; + samba.share.comment = "ZFS: " + filesystem.namenew; + + FnSambaZfsShareConfigurationPathSetCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, mountpoint: filesystem.mountpoint }, { share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary } }, { silent: display.silent }) + .finally(function () { + process.promise.resolve(); + }); + }) + .fail(function () { + filesystem.name = filesystem.namenew; + samba.share.comment = "ZFS: " + filesystem.namenew; + samba.share.name = FnGenerateShareName({ at: false, colon: false, period: false, whitespace: false }, { name: filesystem.namenew }); + + FnSambaZfsShareConfigurationPathSetCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, mountpoint: filesystem.mountpoint }, { share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary } }, { silent: display.silent }) + .finally(function () { + process.promise.resolve(); + }); + }); + } else { + filesystem.name = filesystem.namenew; + samba.share.comment = "ZFS: " + filesystem.namenew; + + FnSambaZfsShareConfigurationPathSetCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, mountpoint: filesystem.mountpoint }, { share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary } }, { silent: display.silent }) + .finally(function () { + process.promise.resolve(); + }); + } + } else { + FnSambaZfsShareConfigurationPathSetCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, mountpoint: filesystem.mountpoint }, { share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary } }, { silent: display.silent }) + .finally(function () { + process.promise.resolve(); + }); + } + } else { + process.promise.resolve(); + } + }) + .fail(function (message, data) { + FnConsole.warn("Samba, ZFS Share Configuration, Get: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); + + process.promise.resolve(); + }); + + return process.promise.promise(); +} + +function FnSambaZfsShareConfigurationPathSetCommand(pool = { name, id }, filesystem = { name, id, mountpoint }, samba = { share: { additional: [], administrative: false, browseable: true, guestok: false, name, comment, readonly: false, temporary: false } }, display = { silent: true }) { + let process = { + command: ["/bin/sh", "-c", "printf " + FnSambaZfsShareConfigurationGenerate({ name: filesystem.name, id: filesystem.id, mountpoint: filesystem.mountpoint }, { enable: false, share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary } })] + }; + + FnConsole.log[2]("Samba, ZFS Share Configuration, Path, Set: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + if (!display.silent) { + FnDisplayAlert({ status: "success", title: "Samba share configuration successfully updated", description: filesystem.name, breakword: false }, { name: "samba-configure-share", id: filesystem.id, timeout: 4 }); + } + + FnConsole.log[1]("Samba, ZFS Share Configuration, Path, Set: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + }) + .fail(function (message, data) { + if (!display.silent) { + FnDisplayAlert({ status: "danger", title: "Samba share configuration could not be updated", description: filesystem.name, breakword: false }, { name: "samba-configure-share", id: filesystem.id, timeout: 4 }); + } + + FnConsole.warn("Samba, ZFS Share Configuration, Path, Set: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); + }); +} + +function FnSambaZfsShareConfigurationPathsSet(pool = { name, id, altroot: false }, filesystem = { name }, samba = { restart: false }, display = { refresh: false, silent: true }) { + let process = { + command: ["/sbin/zfs", "list", "-H", "-o", "name,mounted,mountpoint,sharesmb", "-r", "-t", "filesystem", filesystem.name], + promise: cockpit.defer() + }; + + FnConsole.log[2]("Samba, ZFS Share Configuration, Paths, Set: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + cockpit.spawn(process.command, { err: "out" }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, ZFS Share Configuration, Paths, Set:" })); + + let filesystems = { + id: data.split(/\n/g).filter(v => v && /\ton$/i.test(v)) + }; + let promise = Promise.resolve(); + + if (filesystems.id.length > 0) { + filesystems.id.forEach((_value, _index) => { + let filesystem = { + properties: _value.split(/\t/g).filter(v => v) + }; + + filesystem.name = filesystem.properties[0]; + filesystem.id = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: filesystem.properties[0], attribute: true }); + filesystem.mounted = filesystem.properties[1]; + filesystem.mountpoint = filesystem.properties[2]; + filesystem.sharesmb = filesystem.properties[3]; + + promise = promise.then(_ => new Promise(resolve => + setTimeout(function () { + if (_index <= (filesystems.id.length - 1)) { + if (filesystem.sharesmb == "on") { + FnSambaZfsShareConfigurationPathSet({ name: pool.name, id: pool.id, altroot: pool.altroot }, { name: filesystem.name, namenew: null, id: filesystem.id, mountpoint: filesystem.mountpoint }) + } + } + + if (_index == (filesystems.id.length - 1)) { + setTimeout(function () { + FnDisplayAlert({ status: "success", title: "Samba share configurations successfully updated", description: pool.name, breakword: false }, { name: "samba-configure-share", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Samba, ZFS Share Configuration, Paths, Set: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + + FnSambaZfsSharesConfigurationReload() + .done(function () { + setTimeout(function () { + if (samba.restart) { + FnSambaRestart() + .finally(function () { + if (display.refresh) { + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 500); + } + + process.promise.resolve(); + }); + } else { + FnSambaConfigurationReload() + .finally(function () { + if (display.refresh) { + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 500); + } + + process.promise.resolve(); + }); + } + }, 300); + }); + }, 500); + } + + resolve(); + }, 500) + )); + }); + } else { + FnDisplayAlert({ status: "success", title: "Samba share configurations successfully updated", description: pool.name, breakword: false }, { name: "samba-configure-share", id: pool.id, timeout: 4 }); + + FnConsole.log[1]("Samba, ZFS Share Configuration, Paths, Set: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + + process.promise.resolve(); + } + }) + .fail(function (message, data) { + FnDisplayAlert({ status: "danger", title: "Samba share configurations could not updated", description: pool.name, breakword: false }, { name: "samba-configure-share", id: pool.id, timeout: 4 }); + + FnConsole.warn("Samba, ZFS Share Configuration, Paths, Set: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); + + if (display.refresh) { + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: true, status: false }); + }, 500); + } + + process.promise.resolve(); + }); + + return process.promise.promise(); +} + +function FnSambaZfsShareConfigure(pool = { name, id }, filesystem = { name, id, mountpoint }, samba = { share: { additional: [], administrative: false, browseable: true, guestok: false, name, comment, nameexisting, readonly: false, temporary: false }, restart: false }) { + $("#spinner-storagepool-filesystem-samba-configure-" + filesystem.id + " span").text("Configuring Samba share..."); + + FnSambaShareNamesGet({ zfsonly: false }) + .done(function (data) { + FnConsole.log[4](FnConsoleVerbose({ data: data, message: "Samba, Share, Names, Get:" })); + + samba.share.nameunique = true; + samba.share.errormessage = "Share name is already in use."; + + if (data.replace(/\n/g, "") != "$empty") { //$empty response is received if share names list is empty + samba.shares = data.split(/\n/g).filter(v => v); + + samba.shares.forEach((_value, _index) => { + if (_value.replace(/^\[/, "").replace(/\]$/, "").toLowerCase() == samba.share.name.toLowerCase() + (samba.share.administrative ? "$" : "")) { + if (samba.share.name != samba.share.nameexisting) { //Allow the name since the share is already enabled with this name + samba.share.nameunique = false; + + return; + } + } + }); + } + + if (/^global$|^homes$|^printers$/gi.test(samba.share.name)) { + samba.share.nameunique = false; + samba.share.errormessage = "Share name can not be a restricted name."; + } + + if (!samba.share.nameunique) { + $("#validationwrapper-storagepool-filesystem-samba-configure-name-" + filesystem.id).addClass("has-error"); + $("#helpblock-storagepool-filesystem-samba-configure-name-" + filesystem.id).addClass("has-error").removeClass("hidden").text(samba.share.errormessage); + $("#input-storagepool-filesystem-samba-configure-name-" + filesystem.id).focus(); + + $("#spinner-storagepool-filesystem-samba-configure-" + filesystem.id).addClass("hidden"); + $("#spinner-storagepool-filesystem-samba-configure-" + filesystem.id + " span").text(""); + $("#btn-storagepool-filesystem-samba-configure-apply-" + filesystem.id).prop("disabled", false); + + FnConsole.warn("Samba, ZFS Share Configuration, Update: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + samba.share.errormessage); + } else { + FnSambaZfsShareConfigureCommand({ name: pool.name, id: pool.id }, { name: filesystem.name, id: filesystem.id, mountpoint: filesystem.mountpoint }, { share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary }, restart: samba.restart }); + } + }); +} + +function FnSambaZfsShareConfigureCommand(pool = { name, id }, filesystem = { name, id, mountpoint }, samba = { share: { additional: [], administrative: false, browseable: true, guestok: false, name, comment, readonly: false, temporary: false }, restart: false }) { + let process = { + command: ["/bin/sh", "-c", "printf " + FnSambaZfsShareConfigurationGenerate({ name: filesystem.name, id: filesystem.id, mountpoint: filesystem.mountpoint }, { enable: false, share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary } })] + }; + + FnConsole.log[2]("Samba, ZFS Share Configuration, Update: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnDisplayAlert({ status: "success", title: "Samba share configuration successfully updated", description: filesystem.name, breakword: false }, { name: "samba-configure-share", id: filesystem.id, timeout: 4 }); + + FnConsole.log[1]("Samba, ZFS Share Configuration, Update: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + + if (samba.restart) { + FnSambaRestart(); + } else { + FnSambaConfigurationReload(); + } + }) + .fail(function (message, data) { + FnDisplayAlert({ status: "danger", title: "Samba share configuration could not be updated", description: filesystem.name, breakword: false }, { name: "samba-configure-share", id: filesystem.id, timeout: 4 }); + + FnConsole.warn("Samba, ZFS Share Configuration, Update: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); + }) + .finally(function () { + $("#modal-storagepool-filesystem-samba-configure-" + filesystem.id).modal("hide"); + + setTimeout(function () { + FnStoragePoolRefresh({ name: pool.name, id: pool.id }, { storagepool: true, filesystems: true, snapshots: false, status: false }); + }, 200); + }); +} + +function FnSambaZfsShareDisable(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id }) { + let process = { + command: ["/bin/rm", "-f", "/" + (pool.altroot || pool.readonly ? "run" : "etc") + "/cockpit/zfs/shares/" + FnGenerateShareFileName({ name: filesystem.name }) + ".conf"] + }; + + FnConsole.log[2]("Samba, Share, Disable: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnConsole.log[1]("Samba, Share, Disable: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + }) + .fail(function (message, data) { + FnConsole.warn("Samba, Share, Disable: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); + }); +} + +function FnSambaZfsShareEnable(pool = { name, id }, filesystem = { name, id, mountpoint }, samba = { share: { additional: [], administrative: false, browseable: true, guestok: false, name, comment, readonly: false, temporary: false } }) { + let process = { + command: ["/bin/sh", "-c", "printf " + FnSambaZfsShareConfigurationGenerate({ name: filesystem.name, id: filesystem.id, mountpoint: filesystem.mountpoint }, { enable: true, share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: samba.share.temporary } })] + }; + + FnConsole.log[2]("Samba, Share, Enable: In Progress, Pool: " + pool.name + ", File System: " + filesystem.name); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnConsole.log[1]("Samba, Share, Enable: Success, Pool: " + pool.name + ", File System: " + filesystem.name); + }) + .fail(function (message, data) { + FnConsole.warn("Samba, Share, Enable: Failed, Pool: " + pool.name + ", File System: " + filesystem.name + ", Message: " + (data ? data : message)); + }); +} + +function FnSambaZfsSharesConfigurationReload() { + let process = { + command: ["/bin/sh", "-c", "echo '# COCKPIT ZFS MANAGER\n# WARNING: DO NOT EDIT, AUTO-GENERATED CONFIGURATION' > /etc/cockpit/zfs/shares.conf && /bin/ls /etc/cockpit/zfs/shares/*.conf 2> /dev/null | /bin/sed -e 's/^/include = /' >> /etc/cockpit/zfs/shares.conf && echo '# COCKPIT ZFS MANAGER\n# WARNING: DO NOT EDIT, AUTO-GENERATED CONFIGURATION' > /run/cockpit/zfs/shares.conf && /bin/ls /run/cockpit/zfs/shares/*.conf 2> /dev/null | /bin/sed -e 's/^/include = /' >> /run/cockpit/zfs/shares.conf"] + }; + + FnConsole.log[2]("Samba, ZFS Shares Configuration, Reload: In Progress"); + FnConsole.log[3](FnConsoleCommand({ command: process.command })); + + return cockpit.spawn(process.command, { err: "out", superuser: "require" }) + .done(function () { + FnConsole.log[1]("Samba, ZFS Shares Configuration, Reload: Success"); + }) + .fail(function (message, data) { + FnConsole.warn("Samba, ZFS Shares Configuration, Reload: Failed, Message: " + (data ? data : message)); + }); +} + +//#endregion + +//#region Dynamic Content Click Actions + +function FnDynamicStatusDiskTrimCancel(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }) { + let dynamic = { + script: "" + }; + + dynamic.script = ` + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-disk-trim-cancel-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolTrimCancel({ name: "` + pool.name + `", id: "` + pool.id + `" }, { id: "` + disk.id + `" }); + }); + \x3C/script> + `; + + $("#dynamics-storagepool-status-" + pool.id).append(dynamic.script); +} + +function FnDynamicStatusDiskTrimResume(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }) { + let dynamic = { + script: "" + }; + + dynamic.script = ` + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-disk-trim-resume-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolTrimStart({ name: "` + pool.name + `", id: "` + pool.id + `" }, { id: "` + disk.id + `" }, { resume: true, secure: false }, { name: null, id: null }); + }); + \x3C/script> + `; + + $("#dynamics-storagepool-status-" + pool.id).append(dynamic.script); +} + +function FnDynamicStatusDiskTrimSuspend(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }) { + let dynamic = { + script: "" + }; + + dynamic.script = ` + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-disk-trim-suspend-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolTrimSuspend({ name: "` + pool.name + `", id: "` + pool.id + `" }, { id: "` + disk.id + `" }); + }); + \x3C/script> + `; + + $("#dynamics-storagepool-status-" + pool.id).append(dynamic.script); +} + +function FnDynamicStatusStoragePoolScrubPause(pool = { name, id, status: { config: { items: { index: 0 } } } }) { + let dynamic = { + script: "" + }; + + dynamic.script = ` + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-scrub-pause-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolScrubPause({ name: "` + pool.name + `", id: "` + pool.id + `" }, { refresh: true }); + }); + \x3C/script> + `; + + $("#dynamics-storagepool-status-" + pool.id).append(dynamic.script); +} + +function FnDynamicStatusStoragePoolScrubResume(pool = { name, id, status: { config: { items: { index: 0 } } } }) { + let dynamic = { + script: "" + }; + + dynamic.script = ` + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-scrub-resume-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolScrubStart({ name: "` + pool.name + `", id: "` + pool.id + `" }, { resume: true }), { refresh: true }; + }); + \x3C/script> + `; + + $("#dynamics-storagepool-status-" + pool.id).append(dynamic.script); +} + +function FnDynamicStatusStoragePoolScrubStart(pool = { name, id, status: { config: { items: { index: 0 } } } }) { + let dynamic = { + script: "" + }; + + dynamic.script = ` + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-scrub-start-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolScrubStart({ name: "` + pool.name + `", id: "` + pool.id + `" }, { resume: false }, { refresh: true }); + }); + \x3C/script> + `; + + $("#dynamics-storagepool-status-" + pool.id).append(dynamic.script); +} + +function FnDynamicStatusStoragePoolScrubStop(pool = { name, id, status: { config: { items: { index: 0 } } } }) { + let dynamic = { + script: "" + }; + + dynamic.script = ` + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-scrub-stop-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolScrubStop({ name: "` + pool.name + `", id: "` + pool.id + `" }, { refresh: true }); + }); + \x3C/script> + `; + + $("#dynamics-storagepool-status-" + pool.id).append(dynamic.script); +} + +function FnDynamicStatusStoragePoolTrimCancel(pool = { name, id, status: { config: { items: { index: 0 } } } }) { + let dynamic = { + script: "" + }; + + dynamic.script = ` + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-trim-cancel-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolTrimCancel({ name: "` + pool.name + `", id: "` + pool.id + `" }, { id: null }); + }); + \x3C/script> + `; + + $("#dynamics-storagepool-status-" + pool.id).append(dynamic.script); +} + +function FnDynamicStatusStoragePoolTrimResume(pool = { name, id, status: { config: { items: { index: 0 } } } }) { + let dynamic = { + script: "" + }; + + dynamic.script = ` + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-trim-resume-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolTrimStart({ name: "` + pool.name + `", id: "` + pool.id + `" }, { id: null }, { resume: true, secure: false }, { name: null, id: null }); + }); + \x3C/script> + `; + + $("#dynamics-storagepool-status-" + pool.id).append(dynamic.script); +} + +function FnDynamicStatusStoragePoolTrimSuspend(pool = { name, id, status: { config: { items: { index: 0 } } } }) { + let dynamic = { + script: "" + }; + + dynamic.script = ` + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-trim-suspend-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolTrimSuspend({ name: "` + pool.name + `", id: "` + pool.id + `" }, { id: null }); + }); + \x3C/script> + `; + + $("#dynamics-storagepool-status-" + pool.id).append(dynamic.script); +} + +//#endregion + +//#region Modals Register + +function FnModalsRegister() { + $("#modals").append(`
    `); + $("#modals").append(`
    `); + + FnModalAbout(); + FnModalConfigure(); + FnModalUpdate(); + FnModalWelcome(); + FnModalStoragePoolsCreate(); + FnModalStoragePoolsImport(); + FnModalFileSystemsUnlock(); +} + +//#endregion + +//#region Modal Cockpit ZFS Manager + +function FnModalAbout() { + let modal = { + window: "" + }; + + modal.window = ` + + `; + + $("#modals").append(modal.window); +} + +function FnModalConfigure() { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-configure").on("click", function () { + FnModalConfigureContent({ id: $("#modal-configure") }); + }); + \x3C/script> + `; + + $("#modals").append(modal.window); +} + +function FnModalConfigureContent(modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#switch-configure-samba-manage input").on("click", function () { + if (!$(this).prop("checked")) { + $("#switch-configure-samba-windowscompatibility input").prop("disabled", true); + $("#switch-configure-samba-windowscompatibility").parent().addClass("hidden"); + } else { + $("#switch-configure-samba-windowscompatibility input").removeClass("hidden").prop("disabled", false); + $("#switch-configure-samba-windowscompatibility").parent().removeClass("hidden"); + } + }); + + $("#switch-configure-zfs-storagepool-boot input").on("click", function () { + if (!$(this).prop("checked")) { + $("#switch-configure-zfs-storagepool-bootlockdown input").prop("disabled", true); + $("#switch-configure-zfs-storagepool-bootlockdown").parent().addClass("hidden"); + } else { + $("#switch-configure-zfs-storagepool-bootlockdown input").prop("disabled", false); + $("#switch-configure-zfs-storagepool-bootlockdown").parent().removeClass("hidden"); + } + }); + + $("#btn-configure-apply").on("click", function () { + $("#spinner-configure").removeClass("hidden"); + $(this).prop("disabled", true); + + let user = { + cockpit: { + manage: $("#switch-configure-cockpit-manage input").prop("checked") + }, + disks: { + base2: $("#switch-configure-disks-base2 input").prop("checked"), + }, + loglevel: $("#btnspan-configure-zfs-storagepool-loglevel").attr("data-field-value"), + samba: { + manage: $("#switch-configure-samba-manage input").prop("checked"), + windowscompatibility: $("#switch-configure-samba-windowscompatibility input").prop("checked") + }, + updates: { + check: $("#switch-configure-updates-check input").prop("checked") + }, + zfs: { + filesystem: { + cloneorigin: $("#switch-configure-zfs-filesystem-cloneorigin input").prop("checked"), + quotarestrict: $("#switch-configure-zfs-filesystem-quotarestrict input").prop("checked"), + readonlylockdown: $("#switch-configure-zfs-filesystem-readonlylockdown input").prop("checked"), + snapshotactions: $("#switch-configure-zfs-filesystem-snapshotactions input").prop("checked") + }, + snapshot: { + filesystemlist: $("#switch-configure-zfs-snapshot-filesystemlist input").prop("checked") + }, + status: { + errorcolors: $("#switch-configure-zfs-status-errorcolors input").prop("checked"), + trimunsupported: $("#switch-configure-zfs-status-trimunsupported input").prop("checked") + }, + storagepool: { + activetab: $("#btnspan-configure-zfs-storagepool-activetab").attr("data-field-value"), + boot: $("#switch-configure-zfs-storagepool-boot input").prop("checked"), + bootlockdown: $("#switch-configure-zfs-storagepool-bootlockdown input").prop("checked"), + count: $("#switch-configure-zfs-storagepool-count input").prop("checked"), + refreshall: $("#switch-configure-zfs-storagepool-refreshall input").prop("checked"), + root: $("#switch-configure-zfs-storagepool-root input").prop("checked") + } + } + }; + + FnConfigure({ cockpit: { manage: user.cockpit.manage }, disks: { base2: user.disks.base2 }, loglevel: user.loglevel, samba: { manage: user.samba.manage, windowscompatibility: user.samba.windowscompatibility }, updates: { check: user.updates.check }, zfs: { filesystem: { cloneorigin: user.zfs.filesystem.cloneorigin, quotarestrict: user.zfs.filesystem.quotarestrict, readonlylockdown: user.zfs.filesystem.readonlylockdown, snapshotactions: user.zfs.filesystem.snapshotactions }, snapshot: { filesystemlist: user.zfs.snapshot.filesystemlist }, status: { errorcolors: user.zfs.status.errorcolors, trimunsupported: user.zfs.status.trimunsupported }, storagepool: { activetab: user.zfs.storagepool.activetab, boot: user.zfs.storagepool.boot, bootlockdown: user.zfs.storagepool.bootlockdown, count: user.zfs.storagepool.count, refreshall: user.zfs.storagepool.refreshall, root: user.zfs.storagepool.root } } }, { name: "configure", welcome: false }) + }); + + $("#dropdown-configure-zfs-storagepool-activetab").on("click", "li a", function () { + $("#btnspan-configure-zfs-storagepool-activetab").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + + $("#dropdown-configure-zfs-storagepool-loglevel").on("click", "li a", function () { + $("#btnspan-configure-zfs-storagepool-loglevel").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalUpdate() { + let modal = { + window: "" + }; + + modal.window = ` + + `; + + $("#modals").append(modal.window); +} + +function FnModalUpdateContent(modal = { id }) { + modal.content = ` + + `; + + modal.id.empty().append(modal.content); + + $("#progressbar-update .progress-bar").css("width", "100%"); +} + +function FnModalWelcome() { + let modal = { + window: "" + }; + + modal.window = ` + + `; + + $("#modals").append(modal.window); +} + +function FnModalWelcomeContent(modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#switch-welcome-samba-manage input").on("click", function () { + if (!$(this).prop("checked")) { + $("#switch-welcome-samba-windowscompatibility input").prop("disabled", true); + $("#switch-welcome-samba-windowscompatibility").parent().addClass("hidden"); + } else { + $("#switch-welcome-samba-windowscompatibility input").removeClass("hidden").prop("disabled", false); + $("#switch-welcome-samba-windowscompatibility").parent().removeClass("hidden"); + } + }); + + $("#switch-welcome-zfs-storagepool-boot input").on("click", function () { + if (!$(this).prop("checked")) { + $("#switch-welcome-zfs-storagepool-bootlockdown input").prop("disabled", true); + $("#switch-welcome-zfs-storagepool-bootlockdown").parent().addClass("hidden"); + } else { + $("#switch-welcome-zfs-storagepool-bootlockdown input").prop("disabled", false); + $("#switch-welcome-zfs-storagepool-bootlockdown").parent().removeClass("hidden"); + } + }); + + $("#btn-welcome-apply").on("click", function () { + $("#spinner-welcome").removeClass("hidden"); + $(this).prop("disabled", true); + + let user = { + cockpit: { + manage: $("#switch-welcome-cockpit-manage input").prop("checked") + }, + loglevel: $("#btnspan-welcome-zfs-storagepool-loglevel").attr("data-field-value"), + samba: { + manage: $("#switch-welcome-samba-manage input").prop("checked"), + windowscompatibility: $("#switch-welcome-samba-windowscompatibility input").prop("checked") + }, + updates: { + check: $("#switch-welcome-updates-check input").prop("checked") + }, + zfs: { + storagepool: { + boot: $("#switch-welcome-zfs-storagepool-boot input").prop("checked"), + bootlockdown: $("#switch-welcome-zfs-storagepool-bootlockdown input").prop("checked"), + root: $("#switch-welcome-zfs-storagepool-root input").prop("checked") + } + } + }; + + FnConfigure({ cockpit: { manage: user.cockpit.manage }, disks: { base2: ` + zfsmanager.configuration.disks.base2 + ` }, loglevel: user.loglevel, samba: { manage: user.samba.manage, windowscompatibility: user.samba.windowscompatibility }, updates: { check: user.updates.check }, zfs: { filesystem: { cloneorigin: ` + zfsmanager.configuration.zfs.filesystem.cloneorigin + `, quotarestrict: ` + zfsmanager.configuration.zfs.filesystem.quotarestrict + `, readonlylockdown: ` + zfsmanager.configuration.zfs.filesystem.readonlylockdown + `, snapshotactions: ` + zfsmanager.configuration.zfs.filesystem.snapshotactions + ` }, snapshot: { filesystemlist: ` + zfsmanager.configuration.zfs.snapshot.filesystemlist + ` }, status: { errorcolors: ` + zfsmanager.configuration.zfs.status.errorcolors + `, trimunsupported: ` + zfsmanager.configuration.zfs.status.trimunsupported + ` }, storagepool: { activetab: ` + zfsmanager.configuration.zfs.storagepool.activetab + `, boot: user.zfs.storagepool.boot, bootlockdown: user.zfs.storagepool.bootlockdown, count: ` + zfsmanager.configuration.zfs.storagepool.count + `, refreshall: ` + zfsmanager.configuration.zfs.storagepool.refreshall + `, root: user.zfs.storagepool.root } } }, { name: "welcome", welcome: true }) + }); + + $("#dropdown-welcome-zfs-storagepool-activetab").on("click", "li a", function () { + $("#btnspan-welcome-zfs-storagepool-activetab").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + + $("#dropdown-welcome-zfs-storagepool-loglevel").on("click", "li a", function () { + $("#btnspan-welcome-zfs-storagepool-loglevel").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +//#endregion + +//#region Modal Storage Pools + +function FnModalStoragePoolsCreate() { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepools-create").on("click", function () { + FnModalStoragePoolsCreateContent({ id: $("#modal-storagepools-create") }); + FnDisksAvailableGet({ name: "storagepools-create-disks", id: null, default: true }); + + $("#input-storagepools-create-refreservation").val("10"); + $("#validationwrapper-storagepools-create-refreservation .min-slider-handle").attr("tabindex", "1003"); + setTimeout(function() { + $("#input-storagepools-create-name").focus(); + }, 600); + }); + \x3C/script> + `; + + $("#modals-storagepools").append(modal.window); +} + +function FnModalStoragePoolsCreateContent(modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#input-storagepools-create-refreservation").tooltip({ trigger: "manual" }) + .on("keyup", function (element) { + let $this = $(this); + let sd = $this.siblings("[data-provide=slider]").slider(); + + if ($this.val().trim() && !$.isNumeric(this.value)) { + this.value = sd.slider("getValue"); + } + }) + .on("keypress blur", function (element) { + if (element.which == 13 || element.type === "blur") { + element.preventDefault(); + + let $this = $(this); + let sd = $this.siblings("[data-provide=slider]").slider(); + let max = sd.slider("getAttribute", "max"); + let min = sd.slider("getAttribute", "min"); + + if (!$.isNumeric(this.value) || (this.value > max || this.value < min)) { + let warningInfo = $.isNumeric(this.value) ? "Valid value should be between " + min + " and " + max : "Valid value should be number"; + $this.attr("data-original-title", warningInfo).tooltip("show").addClass("warning"); + this.value = sd.slider("getValue"); + setTimeout(function () { + $this.tooltip("hide"); + }, 3000); + } else { + if ($this.is(".warning")) { + $this.tooltip("hide"); + } + + this.value = $this.val().trim(); + sd.slider("setValue", this.value); + } + } + }) + .siblings("[data-provide=slider]").each(function () { + $("#input-storagepools-create-refreservation").val(this.value); + $(this).slider().on("change", function (element) { + $("#input-storagepools-create-refreservation").val(element.value.newValue); + }); + }); + + $("#input-storagepools-create-refreservation").on("change textInput input", function (element) { + if ($(this).val() > 20) { //Force reset to maximum allowed value + $(this).val(20); + } else if ($(this).val() < 0) { //Force reset to minimum allowed value + $(this).val(0); + } + + if ($.isNumeric($(this).val())) { + $("#slider-storagepools-create-refreservation").slider("setValue", $(this).val()); + } + }); + + $("#switch-storagepools-create-disks-wwn input").on("click", function () { + $("#btnspan-storagepools-create-disks-identifier").text("Block Device"); + $("#dropdown-storagepools-create-disks-identifier li").siblings().removeClass("active"); + $("#dropdown-storagepools-create-disks-identifier li[value='blockdevice']").addClass("active"); + $("#helpblock-storagepools-create-disks-identifierwarning").addClass("hidden").text(""); + ` + (zfsmanager.zfs.warnings.nvmevdev ? `$("#helpblock-storagepools-create-disks-identifierwarningzfs").addClass("hidden");` : ``) + ` + + let disk = { + identifier: ($(this).prop("checked") ? "wwn" : "blockdevice"), + identifiertext: ($(this).prop("checked") ? "WWN" : "Block Device") + }; + + if ($(this).prop("checked")) { + $("#controllabel-storagepools-create-disks-identifier").addClass("hidden"); + $("#validationwrapper-storagepools-create-disks-identifier").addClass("hidden"); + } else { + $("#controllabel-storagepools-create-disks-identifier").removeClass("hidden"); + $("#validationwrapper-storagepools-create-disks-identifier").removeClass("hidden"); + } + + $("#listgroup-storagepools-create-disks input[name='checkbox-storagepools-create-disks']").map(function () { + if ($(this).attr("data-disk-id-" + disk.identifier)) { + $(this).next().find(".select-ct-disk-row-id").text((disk.identifier == "blockdevice" ? "/dev/" : "") + $(this).attr("data-disk-id-" + disk.identifier)); + $(this).attr("data-disk-name", $(this).attr("data-disk-id-" + disk.identifier)); + } else { + $(this).next().find(".select-ct-disk-row-id").text("/dev/" + $(this).attr("data-disk-id-blockdevice")); + $(this).attr("data-disk-name", $(this).attr("data-disk-id-blockdevice")); + $("#helpblock-storagepools-create-disks-identifierwarning").removeClass("hidden").text("One or more disks is missing a " + disk.identifiertext + " identifier."); + } + }); + }); + + $("#btn-storagepools-create-apply").on("click", function () { + $("#spinner-storagepools-create").removeClass("hidden"); + $(this).prop("disabled", true); + + let disks = { + id: [] + }; + let filesystem = { + compression: "", + dedup: "off", + recordsize: "131072", + refreservationpercent: 0, + selinux: false + }; + let pool = { + ashift: 0, + autoexpand: "", + autoreplace: "", + autotrim: "", + force: false, + name: "", + virtualdevice: "" + } + let validation = { + disks: false, + name: false + }; + + $("#listgroup-storagepools-create-disks input[name='checkbox-storagepools-create-disks']:checked").map(function () { + disks.id.push($(this).attr("data-disk-name")); + }); + + if ($("#input-storagepools-create-name").val().length == 0) { + $("#helpblock-storagepools-create-name").addClass("has-error").removeClass("hidden").text("Name can not be empty."); + + validation.name = false; + } else if (/^[a-zA-Z0-9-_.: ]*$/.test($("#input-storagepools-create-name").val()) == false) { + $("#helpblock-storagepools-create-name").addClass("has-error").removeClass("hidden").text("Name contains invalid characters."); + + validation.name = false; + } else if (/^[0-9]/.test($("#input-storagepools-create-name").val())) { + $("#helpblock-storagepools-create-name").addClass("has-error").removeClass("hidden").text("Name can not begin with numerical characters."); + + validation.name = false; + } else if (/^[.]/.test($("#input-storagepools-create-name").val())) { + $("#helpblock-storagepools-create-name").addClass("has-error").removeClass("hidden").text("Name can not begin with a period (.)."); + + validation.name = false; + } else if (/^[_]/.test($("#input-storagepools-create-name").val())) { + $("#helpblock-storagepools-create-name").addClass("has-error").removeClass("hidden").text("Name can not begin with an underscore (_)."); + + validation.name = false; + } else if (/^[-]/.test($("#input-storagepools-create-name").val())) { + $("#helpblock-storagepools-create-name").addClass("has-error").removeClass("hidden").text("Name can not begin with a hypen (-)."); + + validation.name = false; + } else if (/^[:]/.test($("#input-storagepools-create-name").val())) { + $("#helpblock-storagepools-create-name").addClass("has-error").removeClass("hidden").text("Name can not begin with an colon (:)."); + + validation.name = false; + } else if (/^[ ]/.test($("#input-storagepools-create-name").val())) { + $("#helpblock-storagepools-create-name").addClass("has-error").removeClass("hidden").text("Name can not begin with whitespace ( )."); + + validation.name = false; + } else if (/[ ]$/.test($("#input-storagepools-create-name").val())) { + $("#helpblock-storagepools-create-name").addClass("has-error").removeClass("hidden").text("Name can not end with whitespace ( )."); + + validation.name = false; + } else if (/^c[0-9]|^log|^mirror|^raidz|^raidz1|^raidz2|^raidz3|^spare/.test($("#input-storagepools-create-name").val())) { + $("#helpblock-storagepools-create-name").addClass("has-error").removeClass("hidden").text("Name can not begin with a reserved name."); + + validation.name = false; + } else { + $("#validationwrapper-storagepools-create-name").removeClass("has-error"); + $("#helpblock-storagepools-create-name").addClass("hidden").text(""); + + validation.name = true; + } + if (disks.id.length < 1 && $("#btnspan-storagepools-create-virtualdevice").attr("data-field-value") == "disk") { + $("#helpblock-storagepools-create-disks").removeClass("hidden").text("One or more disks is needed for Disk."); + + validation.disks = false; + } else if (disks.id.length < 2 && $("#btnspan-storagepools-create-virtualdevice").attr("data-field-value") == "mirror") { + $("#helpblock-storagepools-create-disks").removeClass("hidden").text("Two or more disks is needed for Mirror."); + + validation.disks = false; + } else if (disks.id.length < 2 && $("#btnspan-storagepools-create-virtualdevice").attr("data-field-value") == "raidz1") { + $("#helpblock-storagepools-create-disks").removeClass("hidden").text("Two or more disks is needed for RaidZ1."); + + validation.disks = false; + } else if (disks.id.length < 3 && $("#btnspan-storagepools-create-virtualdevice").attr("data-field-value") == "raidz2") { + $("#helpblock-storagepools-create-disks").removeClass("hidden").text("Three or more disks is needed for RaidZ2."); + + validation.disks = false; + } else if (disks.id.length < 4 && $("#btnspan-storagepools-create-virtualdevice").attr("data-field-value") == "raidz3") { + $("#helpblock-storagepools-create-disks").removeClass("hidden").text("Four or more disks is needed for RaidZ3."); + + validation.disks = false; + } else { + $("#validationwrapper-storagepools-create-disks").removeClass("has-error"); + $("#helpblock-storagepools-create-disks").removeClass("hidden").text(""); + + validation.disks = true; + } + + if (!validation.name || !validation.disks) { + if (!validation.name) { + $("#validationwrapper-storagepools-create-name").addClass("has-error"); + $("#input-storagepools-create-name").focus(); + } + if (!validation.disks) { + $("#validationwrapper-storagepools-create-disks").addClass("has-error"); + } + + $("#spinner-storagepools-create").addClass("hidden"); + $(this).prop("disabled", false); + } + + if (validation.name && validation.disks) { + filesystem.compression = ($("#switch-storagepools-create-compression input").prop("checked") ? "lz4" : "off"); + filesystem.dedup = $("#btnspan-storagepools-create-dedup").attr("data-field-value"); + filesystem.recordsize = $("#btnspan-storagepools-create-recordsize").attr("data-field-value"); + filesystem.refreservationpercent = ($("#input-storagepools-create-refreservation").val() != "0" ? $("#input-storagepools-create-refreservation").val() : "0"); + filesystem.selinux = $("#switch-storagepools-create-selinux input").prop("checked"); + + pool.ashift = $("#btnspan-storagepools-create-ashift").attr("data-field-value"); + pool.autoexpand = ($("#switch-storagepools-create-autoexpand input").prop("checked") ? "on" : "off"); + pool.autoreplace = ($("#switch-storagepools-create-autoreplace input").prop("checked") ? "on" : "off"); + pool.autotrim = ($("#switch-storagepools-create-autotrim input").prop("checked") ? "on" : "off"); + pool.force = $("#switch-storagepools-create-force input").prop("checked"); + pool.name = $("#input-storagepools-create-name").val(); + pool.virtualdevice = ($("#btnspan-storagepools-create-virtualdevice").attr("data-field-value") == "disk" ? "" : $("#btnspan-storagepools-create-virtualdevice").attr("data-field-value")); + + FnStoragePoolCreate({ name: pool.name, ashift: pool.ashift, autoexpand: pool.autoexpand, autoreplace: pool.autoreplace, autotrim: pool.autotrim, force: pool.force, virtualdevice: pool.virtualdevice }, { compression: filesystem.compression, dedup: filesystem.dedup, recordsize: filesystem.recordsize, refreservationpercent: filesystem.refreservationpercent, selinux: filesystem.selinux }, { id: disks.id }); + } + }); + + $("#dropdown-storagepools-create-virtualdevice").on("click", "li a", function () { + $("#btnspan-storagepools-create-virtualdevice").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + + $("#dropdown-storagepools-create-ashift").on("click", "li a", function () { + $("#btnspan-storagepools-create-ashift").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + + $("#dropdown-storagepools-create-disks-identifier").on("click", "li a", function () { + $("#btnspan-storagepools-create-disks-identifier").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + + $("#helpblock-storagepools-create-disks-identifierwarning").addClass("hidden").text(""); + ` + (zfsmanager.zfs.warnings.nvmevdev ? `$("#helpblock-storagepools-create-disks-identifierwarningzfs").addClass("hidden");` : ``) + ` + + let disk = { + identifier: $(this).parent().attr("value"), + identifiertext: $(this).parent().text() + }; + + $("#listgroup-storagepools-create-disks input[name='checkbox-storagepools-create-disks']").map(function () { + if ($(this).attr("data-disk-id-" + disk.identifier)) { + $(this).next().find(".select-ct-disk-row-id").text((disk.identifier == "blockdevice" ? "/dev/" : "") + $(this).attr("data-disk-id-" + disk.identifier)); + $(this).attr("data-disk-name", $(this).attr("data-disk-id-" + disk.identifier)); + } else { + $(this).next().find(".select-ct-disk-row-id").text("/dev/" + $(this).attr("data-disk-id-blockdevice")); + $(this).attr("data-disk-name", $(this).attr("data-disk-id-blockdevice")); + $("#helpblock-storagepools-create-disks-identifierwarning").removeClass("hidden").text("One or more disks is missing a " + disk.identifiertext + " identifier."); + + ` + (zfsmanager.zfs.warnings.nvmevdev ? ` + if (disk.identifier == "vdev" && /^nvme/gi.test($(this).attr("data-disk-id-blockdevice"))) { + $("#helpblock-storagepools-create-disks-identifierwarningzfs").removeClass("hidden"); + } + ` : ``) + ` + } + }); + }); + + $("#dropdown-storagepools-create-dedup").on("click", "li a", function () { + $("#btnspan-storagepools-create-dedup").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + + $("#dropdown-storagepools-create-recordsize").on("click", "li a", function () { + $("#btnspan-storagepools-create-recordsize").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalStoragePoolsImport() { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepools-import").on("click", function () { + FnModalStoragePoolsImportContent({ id: $("#modal-storagepools-import") }); + FnStoragePoolsImportableGet({ destroyed: false }); + }); + \x3C/script> + `; + + $("#modals-storagepools").append(modal.window); +} + +function FnModalStoragePoolsImportContent(modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#switch-storagepools-import-destroyed input").on("click", function () { + $("#helpblock-storagepools-import-storagepools").addClass("hidden").text(""); + $("#helpblock-storagepools-import-storagepools-warning").addClass("hidden").text(""); + + FnStoragePoolsImportableGet({ destroyed: ($(this).prop("checked") ? true : false) }); + }); + + $("#switch-storagepools-import-rename input").on("click", function () { + if ($(this).prop("checked")) { + $("#controllabel-storagepools-import-namenew").removeClass("hidden"); + $("#validationwrapper-storagepools-import-namenew").removeClass("hidden"); + $("#input-storagepools-import-namenew").focus(); + } else { + $("#controllabel-storagepools-import-namenew").addClass("hidden"); + $("#validationwrapper-storagepools-import-namenew").addClass("hidden"); + $("#validationwrapper-storagepools-import-namenew").removeClass("has-error"); + $("#helpblock-storagepools-import-namenew").removeClass("has-error").addClass("hidden").text(""); + $("#input-storagepools-import-namenew").val(""); + } + }); + + $("#switch-storagepools-import-selinux input").on("click", function () { + if ($(this).prop("checked") && $("#switch-storagepools-import-readonly input").prop("checked")) { + $("#switch-storagepools-import-readonly input").click(); + } + }); + + $("#switch-storagepools-import-readonly input").on("click", function () { + if ($(this).prop("checked") && $("#switch-storagepools-import-selinux input").prop("checked")) { + $("#switch-storagepools-import-selinux input").click(); + } + }); + + $("#btn-storagepools-import-apply").on("click", function () { + $("#spinner-storagepools-import").removeClass("hidden"); + $(this).prop("disabled", true); + + let disks = { + id: { + blockdevice: true, + disk: false, + path: false, + vdev: false + }, + identifier: "" + }; + + let filesystem = { + mount: true, + selinux: true + }; + + let pool = { + altroot: "", + name: [], + namenew: "", + guid: [], + destroyed: false, + force: false, + ignoremissinglog: false, + readonly: false, + recoverymode: false + }; + + let validation = { + altroot: false, + name: false, + namenew: false, + storagepools: false + }; + + $("#listgroup-storagepools-import-storagepools input[name='checkbox-storagepools-import-storagepools']:checked").map(function () { + pool.guid.push($(this).attr("data-pool-import-guid")); + pool.name.push($(this).attr("data-pool-import-name")); + + disks.id.disk = ($(this).attr("data-pool-import-id-disk") == "true" ? true : false); + disks.id.path = ($(this).attr("data-pool-import-id-path") == "true" ? true : false); + disks.id.vdev = ($(this).attr("data-pool-import-id-vdev") == "true" ? true : false); + }); + + if (pool.guid.length != 1) { + $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text("One storage pool is needed for import."); + + validation.storagepools = false; + } else { + $("#validationwrapper-storagepools-import-storagepools").removeClass("has-error"); + $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text(""); + + validation.storagepools = true; + + pool.guid = pool.guid.join(" "); + pool.name = pool.name.join(" "); + } + + if (validation.storagepools && !$("#switch-storagepools-import-rename input").prop("checked")) { + if (pool.name.length == 0) { + $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text("Storage pool name can not be empty. New name is needed."); + + validation.name = false; + } else if (/^[a-zA-Z0-9-_.: ]*$/.test(pool.name) == false) { + $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text("Storage pool name contains invalid characters. New name is needed."); + + validation.name = false; + } else if (/^[0-9]/.test(pool.name)) { + $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text("Storage pool name can not begin with numerical characters. New name is needed."); + + validation.name = false; + } else if (/^[.]/.test(pool.name)) { + $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text("Storage pool name can not begin with a period (.). New name is needed."); + + validation.name = false; + } else if (/^[_]/.test(pool.name)) { + $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text("Storage pool name can not begin with an underscore (_). New name is needed."); + + validation.name = false; + } else if (/^[-]/.test(pool.name)) { + $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text("Storage pool name can not begin with a hypen (-). New name is needed."); + + validation.name = false; + } else if (/^[:]/.test(pool.name)) { + $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text("Storage pool name can not begin with an colon (:). New name is needed."); + + validation.name = false; + } else if (/^[ ]/.test(pool.name)) { + $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text("Storage pool name can not begin with whitespace ( ). New name is needed."); + + validation.name = false; + } else if (/[ ]$/.test(pool.name)) { + $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text("Storage pool name can not end with whitespace ( ). New name is needed."); + + validation.name = false; + } else if (/^c[0-9]|^log|^mirror|^raidz|^raidz1|^raidz2|^raidz3|^spare/.test(pool.name)) { + $("#helpblock-storagepools-import-storagepools").removeClass("hidden").text("Storage pool name can not begin with a reserved name. New name is needed."); + + validation.name = false; + } else { + validation.name = true; + } + + if (!validation.name && !$("#switch-storagepools-import-rename input").prop("checked")) { + $("#switch-storagepools-import-rename input").click(); + $("#input-storagepools-import-namenew").focus(); + } + } + + if (validation.storagepools && !validation.name && $("#switch-storagepools-import-rename input").prop("checked") && $("#input-storagepools-import-namenew").val().length >= 2) { + validation.name = true; + } + + if ($("#switch-storagepools-import-rename input").prop("checked")) { + if ($("#input-storagepools-import-namenew").val().length == 0) { + $("#helpblock-storagepools-import-namenew").addClass("has-error").removeClass("hidden").text("New name can not be empty."); + + validation.namenew = false; + } else if (/^[a-zA-Z0-9-_.: ]*$/.test($("#input-storagepools-import-namenew").val()) == false) { + $("#helpblock-storagepools-import-namenew").addClass("has-error").removeClass("hidden").text("New name contains invalid characters."); + + validation.namenew = false; + } else if (/^[0-9]/.test($("#input-storagepools-import-namenew").val())) { + $("#helpblock-storagepools-import-namenew").addClass("has-error").removeClass("hidden").text("New name can not begin with numerical characters."); + + validation.namenew = false; + } else if (/^[.]/.test($("#input-storagepools-import-namenew").val())) { + $("#helpblock-storagepools-import-namenew").addClass("has-error").removeClass("hidden").text("New name can not begin with a period (.)."); + + validation.namenew = false; + } else if (/^[_]/.test($("#input-storagepools-import-namenew").val())) { + $("#helpblock-storagepools-import-namenew").addClass("has-error").removeClass("hidden").text("New name can not begin with an underscore (_)."); + + validation.namenew = false; + } else if (/^[-]/.test($("#input-storagepools-import-namenew").val())) { + $("#helpblock-storagepools-import-namenew").addClass("has-error").removeClass("hidden").text("New name can not begin with a hypen (-)."); + + validation.namenew = false; + } else if (/^[:]/.test($("#input-storagepools-import-namenew").val())) { + $("#helpblock-storagepools-import-namenew").addClass("has-error").removeClass("hidden").text("New name can not begin with an colon (:)."); + + validation.namenew = false; + } else if (/^[ ]/.test($("#input-storagepools-import-namenew").val())) { + $("#helpblock-storagepools-import-namenew").addClass("has-error").removeClass("hidden").text("New name can not begin with whitespace ( )."); + + validation.namenew = false; + } else if (/[ ]$/.test($("#input-storagepools-import-namenew").val())) { + $("#helpblock-storagepools-import-namenew").addClass("has-error").removeClass("hidden").text("New name can not end with whitespace ( )."); + + validation.namenew = false; + } else if (/^c[0-9]|^log|^mirror|^raidz|^raidz1|^raidz2|^raidz3|^spare/.test($("#input-storagepools-import-namenew").val())) { + $("#helpblock-storagepools-import-namenew").addClass("has-error").removeClass("hidden").text("New name can not begin with a reserved name."); + + validation.namenew = false; + } else { + $("#validationwrapper-storagepools-import-namenew").removeClass("has-error"); + $("#helpblock-storagepools-import-namenew").addClass("hidden").text(""); + + validation.namenew = true; + } + } else { + $("#validationwrapper-storagepools-import-namenew").removeClass("has-error"); + $("#helpblock-storagepools-import-namenew").removeClass("has-error").addClass("hidden").text(""); + + validation.namenew = true; + } + + if (/^[a-zA-Z0-9-_.:/ ]*$/.test($("#input-storagepools-import-altroot").val()) == false) { + $("#helpblock-storagepools-import-altroot").addClass("has-error").removeClass("hidden").text("Alt Root contains invalid characters."); + + validation.altroot = false; + } else if ($("#input-storagepools-import-altroot").val() && /^[/]/.test($("#input-storagepools-import-altroot").val()) == false) { + $("#helpblock-storagepools-import-altroot").addClass("has-error").removeClass("hidden").text("Alt Root is an absolute path and must begin with a forward slash (/)."); + + validation.altroot = false; + } else if (/^[.]/.test($("#input-storagepools-import-altroot").val())) { + $("#helpblock-storagepools-import-altroot").addClass("has-error").removeClass("hidden").text("Alt Root can not begin with a period (.)."); + + validation.altroot = false; + } else if (/[.]$/.test($("#input-storagepools-import-altroot").val())) { + $("#helpblock-storagepools-import-altroot").addClass("has-error").removeClass("hidden").text("Alt Root can not end with a period (.)."); + + validation.altroot = false; + } else if (/[/][.][/]/g.test($("#input-storagepools-import-altroot").val())) { + $("#helpblock-storagepools-import-altroot").addClass("has-error").removeClass("hidden").text("Alt Root can not contain a period as a sub directory (/./)."); + + validation.altroot = false; + } else if (/[/][.][.][/]/g.test($("#input-storagepools-import-altroot").val())) { + $("#helpblock-storagepools-import-altroot").addClass("has-error").removeClass("hidden").text("Alt Root can not contain a double period as a sub directory (/../)."); + + validation.altroot = false; + } else if (/[/][/]/g.test($("#input-storagepools-import-altroot").val())) { + $("#helpblock-storagepools-import-altroot").addClass("has-error").removeClass("hidden").text("Alt Root can not contain double forward slashes (//)."); + + validation.altroot = false; + } else if (/[.][.]/g.test($("#input-storagepools-import-altroot").val())) { + $("#helpblock-storagepools-import-altroot").addClass("has-error").removeClass("hidden").text("Alt Root can not contain a double period (..)."); + + validation.altroot = false; + } else if (/^[ ]/.test($("#input-storagepools-import-altroot").val())) { + $("#helpblock-storagepools-import-altroot").addClass("has-error").removeClass("hidden").text("Alt Root can not begin with whitespace ( )."); + + validation.altroot = false; + } else if (/[ ]$/.test($("#input-storagepools-import-altroot").val())) { + $("#helpblock-storagepools-import-altroot").addClass("has-error").removeClass("hidden").text("Alt Root can not end with whitespace ( )."); + + validation.altroot = false; + } else { + $("#validationwrapper-storagepools-import-altroot").removeClass("has-error"); + $("#helpblock-storagepools-import-altroot").addClass("hidden").text(""); + + validation.altroot = true; + } + + if (!validation.altroot || !validation.name || !validation.namenew || !validation.storagepools) { + if (!validation.name || !validation.storagepools) { + $("#validationwrapper-storagepools-import-storagepools").addClass("has-error"); + } + if (!validation.namenew) { + $("#validationwrapper-storagepools-import-namenew").addClass("has-error"); + $("#input-storagepools-import-namenew").focus(); + } + if (!validation.altroot) { + $("#validationwrapper-storagepools-import-altroot").addClass("has-error"); + $("#input-storagepools-import-altroot").focus(); + } + + $("#spinner-storagepools-import").addClass("hidden"); + $(this).prop("disabled", false); + } + + if (validation.altroot && validation.name && validation.namenew && validation.storagepools) { + disks.identifier = $("#btnspan-storagepools-import-disks-identifier").attr("data-field-value"); + + filesystem.mount = $("#switch-storagepools-import-mount input").prop("checked"); + filesystem.selinux = $("#switch-storagepools-import-selinux input").prop("checked"); + + pool.altroot = $("#input-storagepools-import-altroot").val(); + pool.destroyed = $("#switch-storagepools-import-destroyed input").prop("checked"); + pool.force = $("#switch-storagepools-import-force input").prop("checked"); + pool.ignoremissinglog = $("#switch-storagepools-import-ignoremissinglog input").prop("checked"); + pool.namenew = ($("#switch-storagepools-import-rename input").prop("checked") ? $("#input-storagepools-import-namenew").val() : ""); + pool.readonly = $("#switch-storagepools-import-readonly input").prop("checked"); + pool.recoverymode = $("#switch-storagepools-import-recoverymode input").prop("checked"); + + FnStoragePoolImport({ name: pool.name, altroot: pool.altroot, destroyed: pool.destroyed, force: pool.force, guid: pool.guid, ignoremissinglog: pool.ignoremissinglog, namenew: pool.namenew, readonly: pool.readonly, recoverymode: pool.recoverymode }, { mount: filesystem.mount, selinux: filesystem.selinux }, { id: { blockdevice: disks.id.blockdevice, disk: disks.id.disk, path: disks.id.path, vdev: disks.id.vdev }, identifier: disks.identifier }); + } + }); + + $("#dropdown-storagepools-import-disks-identifier").on("click", "li a", function () { + $("#btnspan-storagepools-import-disks-identifier").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +//#endregion + +//#region Modal Storage Pool + +function FnModalStoragePoolConfigure(pool = { name, id, boot: false, guid, readonly: false, root: false }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-configure-` + pool.id + `").on("click", function () { + FnModalStoragePoolConfigureContent({ name: "` + pool.name + `", id: "` + pool.id + `", guid: "` + pool.guid + `", readonly: ` + pool.readonly + ` }, { id: $("#modal-storagepool-configure-` + pool.id + `") }); + FnStoragePoolConfigurationGet({ name: "` + pool.name + `", id: "` + pool.id + `", boot: ` + pool.boot + `, root: ` + pool.root + ` }, { name: "storagepool-configure", id: "` + pool.id + `" }); + }); + \x3C/script> + `; + + $("#modals-storagepool-" + pool.id).append(modal.window); +} + +function FnModalStoragePoolConfigureContent(pool = { name, id, guid, readonly: false }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#switch-storagepool-configure-multihost-` + pool.id + ` input").on("click", function () { + FnSystemHostIdGet({ name: "storagepool-configure", id: "` + pool.id + `" }); + + if (!$(this).prop("checked")) { + $("#controllabel-storagepool-configure-hostid-` + pool.id + `").addClass("hidden"); + $("#validationwrapper-storagepool-configure-hostid-` + pool.id + `").addClass("hidden"); + } + }); + + $("#btn-storagepool-configure-apply-` + pool.id + `").on("click", function () { + $("#spinner-storagepool-configure-` + pool.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let modal = { + id: "" + }; + let pool = { + ashift: 0, + autoexpand: "", + autoreplace: "", + autotrim: "", + comment: "", + delegation: "", + failmode: "", + listsnapshots: "", + multihost: "" + }; + let system = { + hostid: false + }; + let validation = { + comment: false + }; + + if ($("#input-storagepool-configure-comment-` + pool.id + `").val().length > 32) { + $("#helpblock-storagepool-configure-comment-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Comment can not be longer than 32 characters."); + + validation.comment = false; + } else if (/^[ -~]*$/.test($("#input-storagepool-configure-comment-` + pool.id + `").val()) == false) { + $("#helpblock-storagepool-configure-comment-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Comment contains invalid characters."); + + validation.comment = false; + } else { + $("#validationwrapper-storagepool-configure-comment-` + pool.id + `").removeClass("has-error"); + $("#helpblock-storagepool-configure-comment-` + pool.id + `").addClass("hidden").text(""); + + validation.comment = true; + } + + if (!validation.comment) { + $("#validationwrapper-storagepool-configure-comment-` + pool.id + `").addClass("has-error"); + $("#input-storagepool-configure-comment-` + pool.id + `").focus(); + + $("#spinner-storagepool-configure-` + pool.id + `").addClass("hidden"); + $(this).prop("disabled", false); + } + + if (validation.comment) { + modal.id = $("#modal-storagepool-configure-` + pool.id + `"); + + pool.ashift = ($("#btnspan-storagepool-configure-ashift-` + pool.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-configure-ashift-` + pool.id + `").attr("data-field-value-new") : null); + pool.autoexpand = ($("#switch-storagepool-configure-autoexpand-` + pool.id + ` input").prop("checked") ? "on" : "off"); + pool.autoreplace = ($("#switch-storagepool-configure-autoreplace-` + pool.id + ` input").prop("checked") ? "on" : "off"); + pool.autotrim = ($("#switch-storagepool-configure-autotrim-` + pool.id + ` input").prop("checked") ? "on" : "off"); + pool.comment = $("#input-storagepool-configure-comment-` + pool.id + `").val(); + pool.delegation = ($("#switch-storagepool-configure-delegation-` + pool.id + ` input").prop("checked") ? "on" : "off"); + pool.failmode = ($("#btnspan-storagepool-configure-failmode-` + pool.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-configure-failmode-` + pool.id + `").attr("data-field-value-new") : null); + pool.listsnapshots = ($("#switch-storagepool-configure-listsnapshots-` + pool.id + ` input").prop("checked") ? "on" : "off"); + pool.multihost = ($("#switch-storagepool-configure-multihost-` + pool.id + ` input").prop("checked") ? "on" : "off"); + + if (!$("#validationwrapper-storagepool-configure-hostid-` + pool.id + `").hasClass("hidden")) { + system.hostid = $("#btnspan-storagepool-configure-hostid-` + pool.id + `").attr("data-field-value"); + } else { + if ($("#btnspan-storagepool-configure-hostid-` + pool.id + `").attr("data-field-value") == "missing") { //Host ID is missing - Generate Host ID before disabling multihost property to avoid error + system.hostid = "libc"; + } + } + + //Set values to null if unchanged, so that they are skipped in the configure function + if (pool.ashift == $("#btnspan-storagepool-configure-ashift-` + pool.id + `").attr("data-field-value")) { + pool.ashift = null; + } + if (pool.autoexpand == $("#switch-storagepool-configure-autoexpand-` + pool.id + `").attr("data-field-value")) { + pool.autoexpand = null; + } + if (pool.autoreplace == $("#switch-storagepool-configure-autoreplace-` + pool.id + `").attr("data-field-value")) { + pool.autoreplace = null; + } + if (pool.autotrim == $("#switch-storagepool-configure-autotrim-` + pool.id + `").attr("data-field-value")) { + pool.autotrim = null; + } + if (pool.comment == $("#input-storagepool-configure-comment-` + pool.id + `").attr("data-field-value")) { + pool.comment = null; + } else if (pool.comment != $("#input-storagepool-configure-comment-` + pool.id + `").attr("data-field-value") && !pool.comment) { + pool.comment = "$empty"; + } + if (pool.failmode == $("#btnspan-storagepool-configure-failmode-` + pool.id + `").attr("data-field-value")) { + pool.failmode = null; + } + if (pool.delegation == $("#switch-storagepool-configure-delegation-` + pool.id + `").attr("data-field-value")) { + pool.delegation = null; + } + if (pool.listsnapshots == $("#switch-storagepool-configure-listsnapshots-` + pool.id + `").attr("data-field-value")) { + pool.listsnapshots = null; + } + if (pool.multihost == $("#switch-storagepool-configure-multihost-` + pool.id + `").attr("data-field-value")) { + pool.multihost = null; + } + + FnStoragePoolConfigure({ name: "` + pool.name + `", id: "` + pool.id + `", ashift: pool.ashift, autoexpand: pool.autoexpand, autoreplace: pool.autoreplace, autotrim: pool.autotrim, comment: pool.comment, delegation: pool.delegation, failmode: pool.failmode, listsnapshots: pool.listsnapshots, multihost: pool.multihost, readonly: ` + pool.readonly + ` }, { hostid: system.hostid }, { id: modal.id }); + } + }); + + $("#dropdown-storagepool-configure-ashift-` + pool.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-configure-ashift-` + pool.id + `").text($(this).text()).attr("data-field-value-new", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + + $("#dropdown-storagepool-configure-failmode-` + pool.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-configure-failmode-` + pool.id + `").text($(this).text()).attr("data-field-value-new", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + + $("#dropdown-storagepool-configure-hostid-` + pool.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-configure-hostid-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalStoragePoolConfigureFeatures(pool = { name, id, boot: false, readonly: false }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-configure-features-` + pool.id + `").on("click", function () { + FnModalStoragePoolConfigureFeaturesContent({ name: "` + pool.name + `", id: "` + pool.id + `", boot: ` + pool.boot + `, readonly: ` + pool.readonly + ` }, { id: $("#modal-storagepool-configure-features-` + pool.id + `") }); + FnStoragePoolConfigurationFeaturesGet({ name: "` + pool.name + `", id: "` + pool.id + `", boot: ` + pool.boot + ` }, { name: "storagepool-configure-features", id: "` + pool.id + `" }); + }); + \x3C/script> + `; + + $("#modals-storagepool-" + pool.id).append(modal.window); +} + +function FnModalStoragePoolConfigureFeaturesContent(pool = { name, id, boot: false, readonly: false }, modal = { id }) { + pool.version = $("#tr-storagepool-" + pool.id).attr("data-pool-version"); + + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("[id^=switch-storagepool-configure-features-][id$='-` + pool.id + `'] input").on("click", function () { + if ($(this).prop("checked") && $(this).parent().attr("data-field-value") == "disabled") { + $("#alert-storagepool-configure-features-compatibility-` + pool.id + `").removeClass("hidden"); + } + + FnModalStoragePoolConfigureFeaturesDependencies({ name: "` + pool.name + `", id: "` + pool.id + `" }, { switch: { id: $(this) } }); + }); + + $("#btn-storagepool-configure-features-apply-` + pool.id + `").on("click", function () { + $("#spinner-storagepool-configure-features-` + pool.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let modal = { + id: "" + }; + + let pool = { + feature: { + allocation_classes: ($("#switch-storagepool-configure-features-allocation_classes-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-allocation_classes-` + pool.id + ` input").prop("disabled") ? "enabled" : null), + async_destroy: ($("#switch-storagepool-configure-features-async_destroy-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-async_destroy-` + pool.id + ` input").prop("disabled") ? "enabled" : null), + bookmark_v2: ($("#switch-storagepool-configure-features-bookmark_v2-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-bookmark_v2-` + pool.id + ` input").prop("disabled") ? "enabled" : null), + bookmarks: ($("#switch-storagepool-configure-features-bookmarks-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-bookmarks-` + pool.id + ` input").prop("disabled") ? "enabled" : null), + device_removal: ($("#switch-storagepool-configure-features-device_removal-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-device_removal-` + pool.id + ` input").prop("disabled") ? "enabled" : null), + edonr: ($("#switch-storagepool-configure-features-edonr-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-edonr-` + pool.id + ` input").prop("disabled") ? "enabled" : null), + embedded_data: ($("#switch-storagepool-configure-features-embedded_data-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-embedded_data-` + pool.id + ` input").prop("disabled") ? "enabled" : null), + empty_bpobj: ($("#switch-storagepool-configure-features-empty_bpobj-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-empty_bpobj-` + pool.id + ` input").prop("disabled") ? "enabled" : null), + enabled_txg: ($("#switch-storagepool-configure-features-enabled_txg-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-enabled_txg-` + pool.id + ` input").prop("disabled") ? "enabled" : null), + encryption: ($("#switch-storagepool-configure-features-encryption-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-encryption-` + pool.id + ` input").prop("disabled") ? "enabled" : null), + extensible_dataset: ($("#switch-storagepool-configure-features-extensible_dataset-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-extensible_dataset-` + pool.id + ` input").prop("disabled") ? "enabled" : null), + filesystem_limits: ($("#switch-storagepool-configure-features-filesystem_limits-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-filesystem_limits-` + pool.id + ` input").prop("disabled") ? "enabled" : null), + hole_birth: ($("#switch-storagepool-configure-features-hole_birth-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-hole_birth-` + pool.id + ` input").prop("disabled") ? "enabled" : null), + large_blocks: ($("#switch-storagepool-configure-features-large_blocks-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-large_blocks-` + pool.id + ` input").prop("disabled") ? "enabled" : null), + large_dnode: ($("#switch-storagepool-configure-features-large_dnode-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-large_dnode-` + pool.id + ` input").prop("disabled") ? "enabled" : null), + lz4_compress: ($("#switch-storagepool-configure-features-lz4_compress-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-lz4_compress-` + pool.id + ` input").prop("disabled") ? "enabled" : null), + multi_vdev_crash_dump: ($("#switch-storagepool-configure-features-multi_vdev_crash_dump-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-multi_vdev_crash_dump-` + pool.id + ` input").prop("disabled") ? "enabled" : null), + obsolete_counts: ($("#switch-storagepool-configure-features-obsolete_counts-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-obsolete_counts-` + pool.id + ` input").prop("disabled") ? "enabled" : null), + project_quota: ($("#switch-storagepool-configure-features-project_quota-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-project_quota-` + pool.id + ` input").prop("disabled") ? "enabled" : null), + resilver_defer: ($("#switch-storagepool-configure-features-resilver_defer-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-resilver_defer-` + pool.id + ` input").prop("disabled") ? "enabled" : null), + sha512: ($("#switch-storagepool-configure-features-sha512-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-sha512-` + pool.id + ` input").prop("disabled") ? "enabled" : null), + skein: ($("#switch-storagepool-configure-features-skein-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-skein-` + pool.id + ` input").prop("disabled") ? "enabled" : null), + spacemap_histogram: ($("#switch-storagepool-configure-features-spacemap_histogram-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-spacemap_histogram-` + pool.id + ` input").prop("disabled") ? "enabled" : null), + spacemap_v2: ($("#switch-storagepool-configure-features-spacemap_v2-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-spacemap_v2-` + pool.id + ` input").prop("disabled") ? "enabled" : null), + userobj_accounting: ($("#switch-storagepool-configure-features-userobj_accounting-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-userobj_accounting-` + pool.id + ` input").prop("disabled") ? "enabled" : null), + zpool_checkpoint: ($("#switch-storagepool-configure-features-zpool_checkpoint-` + pool.id + ` input").prop("checked") && !$("#switch-storagepool-configure-features-zpool_checkpoint-` + pool.id + ` input").prop("disabled") ? "enabled" : null) + } + }; + + FnStoragePoolConfigureFeatures({ name: "` + pool.name + `", id: "` + pool.id + `", feature: { allocation_classes: pool.feature.allocation_classes, async_destroy: pool.feature.async_destroy, bookmark_v2: pool.feature.bookmark_v2, bookmarks: pool.feature.bookmarks, device_removal: pool.feature.device_removal, edonr: pool.feature.edonr, embedded_data: pool.feature.embedded_data, empty_bpobj: pool.feature.empty_bpobj, enabled_txg: pool.feature.enabled_txg, encryption: pool.feature.encryption, extensible_dataset: pool.feature.extensible_dataset, filesystem_limits: pool.feature.filesystem_limits, hole_birth: pool.feature.hole_birth, large_blocks: pool.feature.large_blocks, large_dnode: pool.feature.large_dnode, lz4_compress: pool.feature.lz4_compress, multi_vdev_crash_dump: pool.feature.multi_vdev_crash_dump, obsolete_counts: pool.feature.obsolete_counts, project_quota: pool.feature.project_quota, resilver_defer: pool.feature.resilver_defer, sha512: pool.feature.sha512, skein: pool.feature.skein, spacemap_histogram: pool.feature.spacemap_histogram, spacemap_v2: pool.feature.spacemap_v2, userobj_accounting: pool.feature.userobj_accounting, zpool_checkpoint: pool.feature.zpool_checkpoint }, readonly: ` + pool.readonly + ` }, { id: $("#modal-storagepool-configure-features-` + pool.id + `") }); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalStoragePoolConfigureFeaturesDependencies(pool = { name, id }, modal = { switch: { id } }) { + if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-bookmarks-" + pool.id) { + if ($("#switch-storagepool-configure-features-bookmarks-" + pool.id + " input").prop("checked")) { + if (!$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").click(); + } + } else { + if ($("#switch-storagepool-configure-features-bookmark_v2-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-bookmark_v2-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-bookmark_v2-" + pool.id + " input").click(); + } + if ($("#switch-storagepool-configure-features-encryption-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-encryption-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-encryption-" + pool.id + " input").click(); + } + } + } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-bookmark_v2-" + pool.id) { + if ($("#switch-storagepool-configure-features-bookmark_v2-" + pool.id + " input").prop("checked")) { + if (!$("#switch-storagepool-configure-features-bookmarks-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-bookmarks-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-bookmarks-" + pool.id + " input").click(); + } + if (!$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").click(); + } + } else { + if ($("#switch-storagepool-configure-features-encryption-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-encryption-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-encryption-" + pool.id + " input").click(); + } + } + } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-device_removal-" + pool.id) { + if (!$("#switch-storagepool-configure-features-device_removal-" + pool.id + " input").prop("checked")) { + if ($("#switch-storagepool-configure-features-obsolete_counts-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-obsolete_counts-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-obsolete_counts-" + pool.id + " input").click(); + } + } + } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-edonr-" + pool.id) { + if ($("#switch-storagepool-configure-features-edonr-" + pool.id + " input").prop("checked")) { + if (!$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").click(); + } + } + } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-enabled_txg-" + pool.id) { + if (!$("#switch-storagepool-configure-features-enabled_txg-" + pool.id + " input").prop("checked")) { + if ($("#switch-storagepool-configure-features-hole_birth-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-hole_birth-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-hole_birth-" + pool.id + " input").click(); + } + } + } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-encryption-" + pool.id) { + if ($("#switch-storagepool-configure-features-encryption-" + pool.id + " input").prop("checked")) { + if (!$("#switch-storagepool-configure-features-bookmarks-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-bookmarks-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-bookmarks-" + pool.id + " input").click(); + } + if (!$("#switch-storagepool-configure-features-bookmark_v2-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-bookmark_v2-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-bookmark_v2-" + pool.id + " input").click(); + } + if (!$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").click(); + } + } + } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-extensible_dataset-" + pool.id) { + if (!$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("checked")) { + if ($("#switch-storagepool-configure-features-bookmarks-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-bookmarks-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-bookmarks-" + pool.id + " input").click(); + } + if ($("#switch-storagepool-configure-features-bookmark_v2-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-bookmark_v2-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-bookmark_v2-" + pool.id + " input").click(); + } + if ($("#switch-storagepool-configure-features-edonr-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-edonr-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-edonr-" + pool.id + " input").click(); + } + if ($("#switch-storagepool-configure-features-encryption-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-encryption-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-encryption-" + pool.id + " input").click(); + } + if ($("#switch-storagepool-configure-features-filesystem_limits-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-filesystem_limits-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-filesystem_limits-" + pool.id + " input").click(); + } + if ($("#switch-storagepool-configure-features-large_blocks-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-large_blocks-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-large_blocks-" + pool.id + " input").click(); + } + if ($("#switch-storagepool-configure-features-large_dnode-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-large_dnode-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-large_dnode-" + pool.id + " input").click(); + } + if ($("#switch-storagepool-configure-features-project_quota-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-project_quota-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-project_quota-" + pool.id + " input").click(); + } + if ($("#switch-storagepool-configure-features-sha512-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-sha512-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-sha512-" + pool.id + " input").click(); + } + if ($("#switch-storagepool-configure-features-skein-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-skein-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-skein-" + pool.id + " input").click(); + } + if ($("#switch-storagepool-configure-features-userobj_accounting-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-userobj_accounting-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-userobj_accounting-" + pool.id + " input").click(); + } + } + } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-filesystem_limits-" + pool.id) { + if ($("#switch-storagepool-configure-features-filesystem_limits-" + pool.id + " input").prop("checked")) { + if (!$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").click(); + } + } + } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-hole_birth-" + pool.id) { + if ($("#switch-storagepool-configure-features-hole_birth-" + pool.id + " input").prop("checked")) { + if (!$("#switch-storagepool-configure-features-enabled_txg-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-enabled_txg-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-enabled_txg-" + pool.id + " input").click(); + } + } + } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-large_blocks-" + pool.id) { + if ($("#switch-storagepool-configure-features-large_blocks-" + pool.id + " input").prop("checked")) { + if (!$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").click(); + } + } + } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-large_dnode-" + pool.id) { + if ($("#switch-storagepool-configure-features-large_dnode-" + pool.id + " input").prop("checked")) { + if (!$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").click(); + } + } + } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-obsolete_counts-" + pool.id) { + if ($("#switch-storagepool-configure-features-obsolete_counts-" + pool.id + " input").prop("checked")) { + if (!$("#switch-storagepool-configure-features-device_removal-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-device_removal-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-device_removal-" + pool.id + " input").click(); + } + } + } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-project_quota-" + pool.id) { + if ($("#switch-storagepool-configure-features-project_quota-" + pool.id + " input").prop("checked")) { + if (!$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").click(); + } + } + } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-sha512-" + pool.id) { + if ($("#switch-storagepool-configure-features-sha512-" + pool.id + " input").prop("checked")) { + if (!$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").click(); + } + } + } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-skein-" + pool.id) { + if ($("#switch-storagepool-configure-features-skein-" + pool.id + " input").prop("checked")) { + if (!$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").click(); + } + } + } else if (modal.switch.id.parent().attr("id") == "switch-storagepool-configure-features-userobj_accounting-" + pool.id) { + if ($("#switch-storagepool-configure-features-userobj_accounting-" + pool.id + " input").prop("checked")) { + if (!$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("checked") && !$("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").prop("disabled")) { + $("#switch-storagepool-configure-features-extensible_dataset-" + pool.id + " input").click(); + } + } + } +} + +function FnModalStoragePoolDestroy(pool = { name, id, altroot: false }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-destroy-` + pool.id + `").on("click", function () { + FnModalStoragePoolDestroyContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + ` }, { id: $("#modal-storagepool-destroy-` + pool.id + `") }); + }); + \x3C/script> + `; + + $("#modals-storagepool-" + pool.id).append(modal.window); +} + +function FnModalStoragePoolDestroyContent(pool = { name, id, altroot: false }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-destroy-apply-` + pool.id + `").on("click", function () { + $("#spinner-storagepool-destroy-` + pool.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let pool = { + force: $("#switch-storagepool-destroy-force-` + pool.id + ` input").prop("checked"), + labelclear: $("#switch-storagepool-destroy-labelclear-` + pool.id + ` input").prop("checked") + }; + let samba = { + restart: $("#switch-storagepool-destroy-samba-restart-` + pool.id + ` input").prop("checked") + }; + + FnStoragePoolDestroy({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, force: pool.force, labelclear: pool.labelclear }, { restart: samba.restart }); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalStoragePoolExport(pool = { name, id, altroot: false, readonly: false }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-export-` + pool.id + `").on("click", function () { + FnModalStoragePoolExportContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { id: $("#modal-storagepool-export-` + pool.id + `") }); + }); + \x3C/script> + `; + + $("#modals-storagepool-" + pool.id).append(modal.window); +} + +function FnModalStoragePoolExportContent(pool = { name, id, altroot: false, readonly: false }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-export-apply-` + pool.id + `").on("click", function () { + $("#spinner-storagepool-export-` + pool.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let pool = { + force: $("#switch-storagepool-export-force-` + pool.id + ` input").prop("checked") + }; + let samba = { + restart: $("#switch-storagepool-export-samba-restart-` + pool.id + ` input").prop("checked") + }; + + FnStoragePoolExport({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, force: pool.force, readonly: ` + pool.readonly + ` }, { restart: samba.restart }); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +//#endregion + +//#region Modal File Systems + +function FnModalFileSystemsCreate(pool = { name, id, altroot: false, feature: { allocation_classes: true, edonr: true, encryption: true, large_blocks: true, large_dnode: true, lz4_compress: true, sha512: true, skein: true } }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-filesystems-create-` + pool.id + `").on("click", function () { + FnModalFileSystemsCreateContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, feature: { allocation_classes: ` + pool.feature.allocation_classes + `, edonr: ` + pool.feature.edonr + `, encryption: ` + pool.feature.encryption + `, large_blocks: ` + pool.feature.large_blocks + `, large_dnode: ` + pool.feature.large_dnode + `, lz4_compress: ` + pool.feature.lz4_compress + `, sha512: ` + pool.feature.sha512 + `, skein: ` + pool.feature.skein + ` } }, { id: $("#modal-storagepool-filesystems-create-` + pool.id + `") }); + FnFileSystemsNamesGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { existing: { name: null, clone: false, encryption: false, encryptionroot: null, origin: null}, override: true }, { dropdown: { id: $("#dropdown-storagepool-filesystems-create-parentfilesystem-` + pool.id + `"), selected: "` + pool.name + `" } }); + FnFileSystemConfigurationInheritedGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + pool.name + `" }, { name: "storagepool-filesystems-create", id: "` + pool.id + `" }); + + $("#input-storagepool-filesystems-create-quota-` + pool.id + `").val("0"); + $("#validationwrapper-storagepool-filesystems-create-quota-` + pool.id + ` .min-slider-handle").attr("tabindex", "15"); + setTimeout(function() { + $("#input-storagepool-filesystems-create-name-` + pool.id + `").focus(); + }, 600); + }); + \x3C/script> + `; + + $("#modals-storagepool-filesystems-" + pool.id).append(modal.window); +} + +function FnModalFileSystemsCreateContent(pool = { name, id, altroot: false, feature: { allocation_classes: true, edonr: true, encryption: true, large_blocks: true, large_dnode: true, lz4_compress: true, sha512: true, skein: true } }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#input-storagepool-filesystems-create-quota-` + pool.id + `").tooltip({ trigger: "manual" }) + .on("keyup", function (element) { + let $this = $(this); + let sd = $this.siblings("[data-provide=slider]").slider(); + + if ($this.val().trim() && !$.isNumeric(this.value)) { + this.value = sd.slider("getValue"); + } + }) + .on("keypress blur", function (element) { + if (element.which == 13 || element.type === "blur") { + element.preventDefault(); + + let $this = $(this); + let sd = $this.siblings("[data-provide=slider]").slider(); + let max = sd.slider("getAttribute", "max"); + let min = sd.slider("getAttribute", "min"); + + if (!$.isNumeric(this.value) || (this.value > max || this.value < min)) { + let warningInfo = $.isNumeric(this.value) ? "Valid value should be between " + min + " and " + max : "Valid value should be number"; + $this.attr("data-original-title", warningInfo).tooltip("show").addClass("warning"); + this.value = sd.slider("getValue"); + setTimeout(function () { + $this.tooltip("hide"); + }, 3000); + } else { + if ($this.is(".warning")) { + $this.tooltip("hide"); + } + + this.value = $this.val().trim(); + sd.slider("setValue", this.value); + } + } + }) + .siblings("[data-provide=slider]").each(function () { + $("#input-storagepool-filesystems-create-quota-` + pool.id + `").val(this.value); + $(this).slider().on("change", function (element) { + $("#input-storagepool-filesystems-create-quota-` + pool.id + `").val(element.value.newValue); + }); + }); + + $("#input-storagepool-filesystems-create-quota-` + pool.id + `").on("change textInput input", function (element) { + if ($(this).val() > 1000) { //Force reset to maximum allowed value + $(this).val(1000); + } else if ($(this).val() < 0) { //Force reset to minimum allowed value + $(this).val(0); + } + + if ($.isNumeric($(this).val())) { + $("#slider-storagepool-filesystems-create-quota-` + pool.id + `").slider("setValue", $(this).val()); + } + }); + + $("#switch-storagepool-filesystems-create-encryption-` + pool.id + ` input").on("click", function () { + $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").removeClass("has-error").addClass("hidden").text(""); + $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").removeClass("has-error").addClass("hidden").text(""); + + if ($(this).prop("checked")) { + $("#controllabel-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").removeClass("hidden"); + $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").removeClass("hidden"); + $("#controllabel-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").removeClass("hidden"); + $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").removeClass("hidden"); + $("#controllabel-storagepool-filesystems-create-encryption-cipher-` + pool.id + `").removeClass("hidden"); + $("#validationwrapper-storagepool-filesystems-create-encryption-cipher-` + pool.id + `").removeClass("hidden"); + } else { + $("#controllabel-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").addClass("hidden"); + $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").addClass("hidden"); + $("#input-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").val(""); + $("#controllabel-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").addClass("hidden"); + $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").addClass("hidden"); + $("#input-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").val(""); + $("#controllabel-storagepool-filesystems-create-encryption-cipher-` + pool.id + `").addClass("hidden"); + $("#validationwrapper-storagepool-filesystems-create-encryption-cipher-` + pool.id + `").addClass("hidden"); + } + }); + + $("#switch-storagepool-filesystems-create-sharenfs-` + pool.id + ` input").on("click", function () { + $("#validationwrapper-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").removeClass("has-error").addClass("hidden").text(""); + + if ($(this).prop("checked")) { + $("#controllabel-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").removeClass("hidden"); + $("#validationwrapper-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").removeClass("hidden"); + + FnSystemNfsVersionGet({ alert: { id: $("#alert-storagepool-filesystems-create-sharenfs-options-` + pool.id + `") } }); + } else { + $("#validationwrapper-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").addClass("hidden"); + $("#controllabel-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").addClass("hidden"); + } + }); + + $("#btn-storagepool-filesystems-create-apply-` + pool.id + `").on("click", function () { + $("#spinner-storagepool-filesystems-create-` + pool.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let filesystem = { + name: "", + id: "", + atime: "", + casesensitivity: "", + cipher: "", + compression: "", + dedup: "", + dnodesize: "", + encryption: "", + passphrase: "", + quota: "none", + readonly: "", + recordsize: "", + selinux: "", + sharesmb: "", + special_small_blocks: "", + xattr: "" + }; + let validation = { + encryption: false, + name: false, + sharenfs: false + }; + + if ($("#input-storagepool-filesystems-create-name-` + pool.id + `").val().length == 0) { + $("#helpblock-storagepool-filesystems-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not be empty."); + + validation.name = false; + } else if (/^[a-zA-Z0-9-_.: ]*$/.test($("#input-storagepool-filesystems-create-name-` + pool.id + `").val()) == false) { + $("#helpblock-storagepool-filesystems-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name contains invalid characters."); + + validation.name = false; + } else if (/^[.]/.test($("#input-storagepool-filesystems-create-name-` + pool.id + `").val())) { + $("#helpblock-storagepool-filesystems-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a period (.)."); + + validation.name = false; + } else if (/^[_]/.test($("#input-storagepool-filesystems-create-name-` + pool.id + `").val())) { + $("#helpblock-storagepool-filesystems-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with an underscore (_)."); + + validation.name = false; + } else if (/^[-]/.test($("#input-storagepool-filesystems-create-name-` + pool.id + `").val())) { + $("#helpblock-storagepool-filesystems-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a hypen (-)."); + + validation.name = false; + } else if (/^[:]/.test($("#input-storagepool-filesystems-create-name-` + pool.id + `").val())) { + $("#helpblock-storagepool-filesystems-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with an colon (:)."); + + validation.name = false; + } else if (/^[ ]/.test($("#input-storagepool-filesystems-create-name-` + pool.id + `").val())) { + $("#helpblock-storagepool-filesystems-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with whitespace ( )."); + + validation.name = false; + } else if (/[ ]$/.test($("#input-storagepool-filesystems-create-name-` + pool.id + `").val())) { + $("#helpblock-storagepool-filesystems-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not end with whitespace ( )."); + + validation.name = false; + } else { + $("#validationwrapper-storagepool-filesystems-create-name-` + pool.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystems-create-name-` + pool.id + `").addClass("hidden").text(""); + + validation.name = true; + } + if ($("#switch-storagepool-filesystems-create-encryption-` + pool.id + ` input").prop("checked")) { + if ($("#input-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").val().length == 0 && $("#switch-storagepool-filesystems-create-encryption-` + pool.id + ` input").prop("disabled")) { + $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").removeClass("has-error").addClass("hidden").text(""); + $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").removeClass("has-error").addClass("hidden").text(""); + + validation.encryption = true; + } else if ($("#input-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").val().length == 0) { + $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").addClass("has-error"); + $("#helpblock-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Passphrase can not be empty."); + $("#input-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").focus(); + + validation.encryption = false; + } else if ($("#input-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").val().length < 8) { + $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").addClass("has-error"); + $("#helpblock-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Passphrase requires a minimum of 8 characters."); + $("#input-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").focus(); + + validation.encryption = false; + } else if (/^[a-zA-Z0-9-_. \`~!@#$%^\(\)+\\[\\]{}:',/?]*$/.test($("#input-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").val()) == false) { + $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").addClass("has-error"); + $("#helpblock-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Passphrase contains invalid characters."); + $("#input-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").focus(); + + validation.encryption = false; + } else if ($("#input-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").val().length < 8 || $("#input-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").val() != $("#input-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").val()) { + $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").removeClass("has-error").removeClass("hidden").text(""); + $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").addClass("has-error"); + $("#helpblock-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Passphrase does not match"); + $("#input-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").focus(); + + validation.encryption = false; + } else { + $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").removeClass("has-error").addClass("hidden").text(""); + $("#validationwrapper-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystems-create-encryption-passphrase-confirm-` + pool.id + `").removeClass("has-error").addClass("hidden").text(""); + + validation.encryption = true; + } + } else { + validation.encryption = true; + } + + if ($("#switch-storagepool-filesystems-create-sharenfs-` + pool.id + ` input").prop("checked")) { + if (/^[a-zA-Z0-9-_.:/@#+=!&*(), ]*$/.test($("#input-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").val()) == false) { + $("#validationwrapper-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").addClass("has-error"); + $("#helpblock-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").addClass("has-error").removeClass("hidden").text("NFS Share options contain invalid characters."); + $("#input-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").focus(); + + validation.sharenfs = false; + } else { + validation.sharenfs = true; + } + } else { + validation.sharenfs = true; + } + + if (!validation.name || !validation.encryption || !validation.sharenfs) { + if (!validation.name) { + $("#validationwrapper-storagepool-filesystems-create-name-` + pool.id + `").addClass("has-error"); + $("#input-storagepool-filesystems-create-name-` + pool.id + `").focus(); + } + + $("#spinner-storagepool-filesystems-create-` + pool.id + `").addClass("hidden"); + $(this).prop("disabled", false); + } + + if (validation.name && validation.encryption && validation.sharenfs) { + filesystem.atime = $("#btnspan-storagepool-filesystems-create-atime-` + pool.id + `").attr("data-field-value"); + filesystem.casesensitivity = $("#btnspan-storagepool-filesystems-create-casesensitivity-` + pool.id + `").attr("data-field-value"); + filesystem.cipher = $("#btnspan-storagepool-filesystems-create-encryption-cipher-` + pool.id + `").attr("data-field-value"); + filesystem.compression = $("#btnspan-storagepool-filesystems-create-compression-` + pool.id + `").attr("data-field-value"); + filesystem.dedup = $("#btnspan-storagepool-filesystems-create-dedup-` + pool.id + `").attr("data-field-value"); + filesystem.dnodesize = $("#btnspan-storagepool-filesystems-create-dnodesize-` + pool.id + `").attr("data-field-value"); + filesystem.encryption = $("#switch-storagepool-filesystems-create-encryption-` + pool.id + ` input").prop("checked"); + filesystem.name = $("#btnspan-storagepool-filesystems-create-parentfilesystem-` + pool.id + `").attr("data-field-value") + "/" + $("#input-storagepool-filesystems-create-name-` + pool.id + `").val(); + filesystem.id = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: filesystem.name, attribute: true }); + filesystem.passphrase = $("#input-storagepool-filesystems-create-encryption-passphrase-` + pool.id + `").val(); + filesystem.readonly = ($("#switch-storagepool-filesystems-create-readonly-` + pool.id + ` input").prop("checked") ? "on" : "off"); + filesystem.recordsize = $("#btnspan-storagepool-filesystems-create-recordsize-` + pool.id + `").attr("data-field-value"); + filesystem.selinux = ($("#switch-storagepool-filesystems-create-selinux-` + pool.id + ` input").prop("checked") ? "on" : "off"); + filesystem.sharesmb = ($("#switch-storagepool-filesystems-create-samba-share-` + pool.id + ` input").prop("checked") ? "on" : "off"); + filesystem.special_small_blocks = $("#btnspan-storagepool-filesystems-create-special_small_blocks-` + pool.id + `").attr("data-field-value"); + filesystem.xattr = $("#btnspan-storagepool-filesystems-create-xattr-` + pool.id + `").attr("data-field-value"); + + if ($("#switch-storagepool-filesystems-create-sharenfs-` + pool.id + ` input").prop("checked")) { + if ($("#input-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").val().toLowerCase() == "on" || $("#input-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").val() == "sec=sys,rw,crossmnt,no_subtree_check,no_root_squash" || !$("#input-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").val()) { + filesystem.sharenfs = "on"; + } else { + filesystem.sharenfs = $("#input-storagepool-filesystems-create-sharenfs-options-` + pool.id + `").val(); + } + } else { + filesystem.sharenfs = "off"; + } + + if ($("#input-storagepool-filesystems-create-quota-` + pool.id + `").val() > 0) { //Remove friendly text so final value is sent + filesystem.quota = $("#input-storagepool-filesystems-create-quota-` + pool.id + `").val() + $("#btnspan-storagepool-filesystems-create-quota-` + pool.id + `").attr("data-field-value").replace(/iB$/g, ""); + } else { + filesystem.quota = "none"; + } + + FnFileSystemCreate({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + ` }, { name: filesystem.name, id: filesystem.id, atime: filesystem.atime, casesensitivity: filesystem.casesensitivity, cipher: filesystem.cipher, compression: filesystem.compression, dedup: filesystem.dedup, dnodesize: filesystem.dnodesize, encryption: filesystem.encryption, passphrase: filesystem.passphrase, quota: filesystem.quota, readonly: filesystem.readonly, recordsize: filesystem.recordsize, selinux: filesystem.selinux, sharenfs: filesystem.sharenfs, sharesmb: filesystem.sharesmb, special_small_blocks: filesystem.special_small_blocks, xattr: filesystem.xattr }); + } + }); + + $("#dropdown-storagepool-filesystems-create-parentfilesystem-` + pool.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-filesystems-create-parentfilesystem-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + + FnFileSystemConfigurationInheritedGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: $(this).text() }, { name: "storagepool-filesystems-create", id: "` + pool.id + `" }); + }); + + $("#dropdown-storagepool-filesystems-create-atime-` + pool.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-filesystems-create-atime-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + + $("#dropdown-storagepool-filesystems-create-casesensitivity-` + pool.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-filesystems-create-casesensitivity-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + + $("#dropdown-storagepool-filesystems-create-compression-` + pool.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-filesystems-create-compression-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + + $("#dropdown-storagepool-filesystems-create-dedup-` + pool.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-filesystems-create-dedup-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + + $("#dropdown-storagepool-filesystems-create-dnodesize-` + pool.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-filesystems-create-dnodesize-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + + $("#dropdown-storagepool-filesystems-create-encryption-cipher-` + pool.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-filesystems-create-encryption-cipher-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + + $("#dropdown-storagepool-filesystems-create-quota-` + pool.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-filesystems-create-quota-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).text()); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + + let size = { + slider: { + value: $("#input-storagepool-filesystems-create-quota-` + pool.id + `").val(), + valuemax: $("#input-storagepool-filesystems-create-quota-` + pool.id + `").attr("data-filesystem-quota-max-" + $(this).text().toLowerCase()) + } + }; + + $("#slider-storagepool-filesystems-create-quota-` + pool.id + `").data("slider").options.max = size.slider.valuemax; + $("#slider-storagepool-filesystems-create-quota-` + pool.id + `").data("slider").options.step = (size.slider.valuemax < 10 ? "0.1" : "1"); + $("#slider-storagepool-filesystems-create-quota-` + pool.id + `").slider("setValue", 0); //Force display update + $("#slider-storagepool-filesystems-create-quota-` + pool.id + `").slider("setValue", size.slider.value); + $("#input-storagepool-filesystems-create-quota-` + pool.id + `").val($("#slider-storagepool-filesystems-create-quota-` + pool.id + `").data("slider").getValue()); + }); + + $("#dropdown-storagepool-filesystems-create-recordsize-` + pool.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-filesystems-create-recordsize-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + + $("#dropdown-storagepool-filesystems-create-special_small_blocks-` + pool.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-filesystems-create-special_small_blocks-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + + $("#dropdown-storagepool-filesystems-create-xattr-` + pool.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-filesystems-create-xattr-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalFileSystemsUnlock() { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepools-filesystems-unlock").on("click", function () { + FnModalFileSystemsUnlockContent({ id: $("#modal-storagepools-filesystems-unlock") }); + FnFileSystemsLockedGet(); + + setTimeout(function() { + $("#input-storagepools-filesystems-unlock-passphrase").focus(); + }, 600); + }); + \x3C/script> + `; + + $("#modals-storagepools-filesystems").append(modal.window); +} + +function FnModalFileSystemsUnlockContent(modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#switch-storagepools-filesystems-unlock-mount input").on("click", function () { + if ($(this).prop("checked")) { + $("#switch-storagepools-filesystems-unlock-overlay").parent().removeClass("hidden"); + } else { + $("#switch-storagepools-filesystems-unlock-overlay").parent().addClass("hidden"); + } + }); + + $("#btn-storagepools-filesystems-unlock-apply").on("click", function () { + $("#spinner-storagepools-filesystems-unlock").removeClass("hidden"); + $(this).prop("disabled", true); + + let filesystem = { + mount: true, + passphrase: "" + }; + let filesystems = { + id: [] + }; + let modal = { + name: "storagepools-filesystems-unlock", + id: "" + }; + let samba = { + enable: false + }; + let validation = { + filesystems: false, + passphrase: false + }; + + $("#listgroup-storagepools-filesystems-unlock-filesystems input[name='checkbox-storagepools-filesystems-unlock-filesystems']:checked").map(function () { + filesystems.id.push($(this).attr("data-filesystem-name")); + }); + + if (filesystems.id.length == 0) { + $("#validationwrapper-storagepools-filesystems-unlock-filesystems").addClass("has-error"); + $("#helpblock-storagepools-filesystems-unlock-filesystems").removeClass("hidden").text("One or more file systems is needed for unlock."); + + validation.filesystems = false; + } else { + $("#validationwrapper-storagepools-filesystems-unlock-filesystems").removeClass("has-error"); + $("#helpblock-storagepools-filesystems-unlock-filesystems").removeClass("hidden").text(""); + + validation.filesystems = true; + } + + if ($("#input-storagepools-filesystems-unlock-passphrase").val().length == 0) { + $("#helpblock-storagepools-filesystems-unlock-passphrase").addClass("has-error").removeClass("hidden").text("Passphrase can not be empty."); + + validation.passphrase = false; + } else if ($("#input-storagepools-filesystems-unlock-passphrase").val().length < 8) { + $("#helpblock-storagepools-filesystems-unlock-passphrase").addClass("has-error").removeClass("hidden").text("Passphrase requires a minimum of 8 characters."); + + validation.passphrase = false; + } else if (/^[a-zA-Z0-9-_. \`~!@#$%^\(\)+\\[\\]{}:',/?]*$/.test($("#input-storagepools-filesystems-unlock-passphrase").val()) == false) { + $("#helpblock-storagepools-filesystems-unlock-passphrase").addClass("has-error").removeClass("hidden").text("Passphrase contains invalid characters."); + + validation.passphrase = false; + } else { + $("#validationwrapper-storagepools-filesystems-unlock-passphrase").removeClass("has-error"); + $("#helpblock-storagepools-filesystems-unlock-passphrase").removeClass("has-error").addClass("hidden").text(""); + + validation.passphrase = true; + } + + if (!validation.filesystems || !validation.passphrase) { + if (!validation.passphrase) { + $("#validationwrapper-storagepools-filesystems-unlock-passphrase").addClass("has-error"); + $("#input-storagepools-filesystems-unlock-passphrase").focus(); + } + + $("#spinner-storagepools-filesystems-unlock").addClass("hidden"); + $(this).prop("disabled", false); + } + + if (validation.filesystems && validation.passphrase) { + filesystem.mount = $("#switch-storagepools-filesystems-unlock-mount input").prop("checked"); + filesystem.overlay = $("#switch-storagepools-filesystems-unlock-overlay input").prop("checked"); + filesystem.passphrase = $("#input-storagepools-filesystems-unlock-passphrase").val(); + + FnFileSystemsUnlock({ id: filesystems.id }, { mount: filesystem.mount, overlay: filesystem.overlay, passphrase: filesystem.passphrase }, { name: modal.name, id: modal.id }); + } + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +//#endregion + +//#region Modal File System + +function FnModalFileSystemChangePassphrase(pool = { name, id }, filesystem = { name, id }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-filesystem-changepassphrase-` + filesystem.id + `").on("click", function () { + FnModalFileSystemChangePassphraseContent({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `" }, { id: $("#modal-storagepool-filesystem-changepassphrase-` + filesystem.id + `") }); + + setTimeout(function() { + $("#input-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").focus(); + }, 600); + }); + \x3C/script> + `; + + $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); +} + +function FnModalFileSystemChangePassphraseContent(pool = { name, id }, filesystem = { name, id }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-filesystem-changepassphrase-apply-` + filesystem.id + `").on("click", function () { + $("#spinner-storagepool-filesystem-changepassphrase-` + filesystem.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let filesystem = { + passphrase: "" + }; + let validation = { + passphrase: false + }; + + if ($("#input-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").val().length == 0) { + $("#validationwrapper-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").addClass("has-error"); + $("#helpblock-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Passphrase can not be empty."); + $("#input-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").focus(); + + validation.passphrase = false; + } else if ($("#input-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").val().length < 8) { + $("#validationwrapper-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").addClass("has-error"); + $("#helpblock-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Passphrase requires a minimum of 8 characters."); + $("#input-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").focus(); + + validation.passphrase = false; + } else if (/^[a-zA-Z0-9-_. \`~!@#$%^\(\)+\\[\\]{}:',/?]*$/.test($("#input-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").val()) == false) { + $("#validationwrapper-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").addClass("has-error"); + $("#helpblock-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Passphrase contains invalid characters."); + $("#input-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").focus(); + + validation.passphrase = false; + } else if ($("#input-storagepool-filesystem-changepassphrase-passphrase-confirm-` + filesystem.id + `").val().length < 8 || $("#input-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").val() != $("#input-storagepool-filesystem-changepassphrase-passphrase-confirm-` + filesystem.id + `").val()) { + $("#validationwrapper-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").removeClass("has-error").removeClass("hidden").text(""); + $("#validationwrapper-storagepool-filesystem-changepassphrase-passphrase-confirm-` + filesystem.id + `").addClass("has-error"); + $("#helpblock-storagepool-filesystem-changepassphrase-passphrase-confirm-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Passphrase does not match."); + $("#input-storagepool-filesystem-changepassphrase-passphrase-confirm-` + filesystem.id + `").focus(); + + validation.passphrase = false; + } else { + $("#validationwrapper-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").removeClass("has-error").removeClass("hidden").text(""); + $("#validationwrapper-storagepool-filesystem-changepassphrase-passphrase-confirm-` + filesystem.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystem-changepassphrase-passphrase-confirm-` + filesystem.id + `").removeClass("has-error").removeClass("hidden").text(""); + + validation.passphrase = true; + } + + if (!validation.passphrase) { + $("#spinner-storagepool-filesystem-changepassphrase-` + filesystem.id + `").addClass("hidden"); + $(this).prop("disabled", false); + } + + if (validation.passphrase) { + $("#validationwrapper-storagepool-filesystem-changepassphrase-filesystem-` + filesystem.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystem-changepassphrase-filesystem-` + filesystem.id + `").removeClass("has-error").addClass("hidden").text(""); + + filesystem.passphrase = $("#input-storagepool-filesystem-changepassphrase-passphrase-` + filesystem.id + `").val(); + + FnFileSystemChangePassphrase({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", passphrase: filesystem.passphrase }); + } + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalFileSystemConfigure(pool = { name, id, altroot: false, feature: { allocation_classes: true, edonr: true, large_blocks: true, large_dnode: true, lz4_compress: true, sha512: true, skein: true }, readonly: false }, filesystem = { name, id, origin, type }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-filesystem-configure-` + filesystem.id + `").on("click", function () { + FnModalFileSystemConfigureContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, feature: { allocation_classes: ` + pool.feature.allocation_classes + `, edonr: ` + pool.feature.edonr + `, large_blocks: ` + pool.feature.large_blocks + `, large_dnode: ` + pool.feature.large_dnode + `, lz4_compress: ` + pool.feature.lz4_compress + `, sha512: ` + pool.feature.sha512 + `, skein: ` + pool.feature.skein + ` }, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", origin: "` + filesystem.origin + `", type: "` + filesystem.type + `" }, { id: $("#modal-storagepool-filesystem-configure-` + filesystem.id + `") }); + FnFileSystemConfigurationGet({ name: "` + pool.name + `", id: "` + pool.id + `", readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `" }, { name: "storagepool-filesystem-configure", id: "` + filesystem.id + `" }); + ` + (pool.altroot ? `FnStoragePoolAlternativeRootGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "storagepool-filesystem-configure", id: "` + filesystem.id + `" });` : ``) + ` + + $("#input-storagepool-filesystem-configure-quota-` + filesystem.id + `").val("0"); + $("#validationwrapper-storagepool-filesystem-configure-quota-` + filesystem.id + ` .min-slider-handle").attr("tabindex", "14"); + $("#input-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").val("0"); + $("#validationwrapper-storagepool-filesystem-configure-refreservation-` + filesystem.id + ` .min-slider-handle").attr("tabindex", "18"); + }); + \x3C/script> + `; + + $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); +} + +function FnModalFileSystemConfigureContent(pool = { name, id, altroot: false, feature: { allocation_classes: true, edonr: true, large_blocks: true, large_dnode: true, lz4_compress: true, sha512: true, skein: true }, readonly: false }, filesystem = { name, id, origin, type }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#input-storagepool-filesystem-configure-quota-` + filesystem.id + `").tooltip({ trigger: "manual" }) + .on("keyup", function (element) { + let $this = $(this); + let sd = $this.siblings("[data-provide=slider]").slider(); + + if ($this.val().trim() && !$.isNumeric(this.value)) { + this.value = sd.slider("getValue"); + } + }) + .on("keypress blur", function (element) { + if (element.which == 13 || element.type === "blur") { + element.preventDefault(); + + let $this = $(this); + let sd = $this.siblings("[data-provide=slider]").slider(); + let max = sd.slider("getAttribute", "max"); + let min = sd.slider("getAttribute", "min"); + + if (!$.isNumeric(this.value) || (this.value > max || this.value < min)) { + let warningInfo = $.isNumeric(this.value) ? "Valid value should be between " + min + " and " + max : "Valid value should be number"; + $this.attr("data-original-title", warningInfo).tooltip("show").addClass("warning"); + this.value = sd.slider("getValue"); + setTimeout(function () { + $this.tooltip("hide"); + }, 3000); + } else { + if ($this.is(".warning")) { + $this.tooltip("hide"); + } + + this.value = $this.val().trim(); + sd.slider("setValue", this.value); + } + } + }) + .siblings("[data-provide=slider]").each(function () { + $("#input-storagepool-filesystem-configure-quota-` + filesystem.id + `").val(this.value); + $(this).slider().on("change", function (element) { + $("#input-storagepool-filesystem-configure-quota-` + filesystem.id + `").val(element.value.newValue); + }); + }); + + $("#input-storagepool-filesystem-configure-quota-` + filesystem.id + `").on("change textInput input", function (element) { + if ($(this).val() > 1000) { //Force reset to maximum allowed value + $(this).val(1000); + } else if ($(this).val() < 0) { //Force reset to minimum allowed value + $(this).val(0); + } + + if ($.isNumeric($(this).val())) { + $("#slider-storagepool-filesystem-configure-quota-` + filesystem.id + `").slider("setValue", $(this).val()); + } + }); + + $("#input-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").tooltip({ trigger: "manual" }) + .on("keyup", function (element) { + let $this = $(this); + let sd = $this.siblings("[data-provide=slider]").slider(); + + if ($this.val().trim() && !$.isNumeric(this.value)) { + this.value = sd.slider("getValue"); + } + }) + .on("keypress blur", function (element) { + if (element.which == 13 || element.type === "blur") { + element.preventDefault(); + + let $this = $(this); + let sd = $this.siblings("[data-provide=slider]").slider(); + let max = sd.slider("getAttribute", "max"); + let min = sd.slider("getAttribute", "min"); + + if (!$.isNumeric(this.value) || (this.value > max || this.value < min)) { + let warningInfo = $.isNumeric(this.value) ? "Valid value should be between " + min + " and " + max : "Valid value should be number"; + $this.attr("data-original-title", warningInfo).tooltip("show").addClass("warning"); + this.value = sd.slider("getValue"); + setTimeout(function () { + $this.tooltip("hide"); + }, 3000); + } else { + if ($this.is(".warning")) { + $this.tooltip("hide"); + } + + this.value = $this.val().trim(); + sd.slider("setValue", this.value); + } + } + }) + .siblings("[data-provide=slider]").each(function () { + $("#input-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").val(this.value); + $(this).slider().on("change", function (element) { + $("#input-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").val(element.value.newValue); + }); + }); + + $("#input-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").on("change textInput input", function (element) { + if ($(this).val() > 1000) { //Force reset to maximum allowed value + $(this).val(1000); + } else if ($(this).val() < 0) { //Force reset to minimum allowed value + $(this).val(0); + } + + if ($.isNumeric($(this).val())) { + $("#slider-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").slider("setValue", $(this).val()); + } + }); + + $("#switch-storagepool-filesystem-configure-sharenfs-` + filesystem.id + ` input").on("click", function () { + $("#validationwrapper-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").removeClass("has-error").addClass("hidden").text(""); + + if ($(this).prop("checked")) { + $("#controllabel-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").removeClass("hidden"); + $("#validationwrapper-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").removeClass("hidden"); + + FnSystemNfsVersionGet({ alert: { id: $("#alert-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `") } }); + } else { + $("#validationwrapper-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").addClass("hidden"); + $("#controllabel-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").addClass("hidden"); + } + }); + + $("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").on("input", function (element) { + if ($("#switch-storagepool-filesystem-configure-sharesmb-` + filesystem.id + `").attr("data-field-value") == "on") { + if ($(this).val() != $(this).attr("data-field-value")) { + $("#switch-storagepool-filesystem-configure-samba-restart-` + filesystem.id + `").parent().removeClass("hidden"); + } else { + $("#switch-storagepool-filesystem-configure-samba-restart-` + filesystem.id + `").parent().addClass("hidden"); + } + } + }); + + $("#btn-storagepool-filesystem-configure-apply-` + filesystem.id + `").on("click",function () { + $("#spinner-storagepool-filesystem-configure-` + filesystem.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let filesystem = { + aclinherit: "", + acltype: "", + atime: "", + canmount: "", + checksum: "", + compression: "", + context: "", + dedup: "", + dnodesize: "", + defcontext: "", + fscontext: "", + mountpoint: "", + quota: "none", + readonly: "", + recordsize: "", + refreservation: "0B", + rootcontext: "", + selinux: "", + sharenfs: "", + sharesmb: "", + special_small_blocks: "0B", + xattr: "" + }; + let modal = { + id: $("#modal-storagepool-filesystem-configure-` + filesystem.id + `") + }; + let samba = { + restart: false + }; + let validation = { + mountpoint: false, + sharenfs: false + }; + + if ($("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val().length == 0) { + $("#helpblock-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Mountpoint can not be empty."); + + validation.mountpoint = false; + } else if (/^[a-zA-Z0-9-_.:/ ]*$/.test($("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val()) == false) { + $("#helpblock-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Mountpoint contains invalid characters."); + + validation.mountpoint = false; + } else if ($("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val() && /^[/]/.test($("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val()) == false) { + $("#helpblock-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Mountpoint is an absolute path and must begin with a forward slash (/)."); + + validation.mountpoint = false; + } else if (/^[.]/.test($("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Mountpoint can not begin with a period (.)."); + + validation.mountpoint = false; + } else if (/[.]$/.test($("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Mountpoint can not end with a period (.)."); + + validation.mountpoint = false; + } else if (/[/][.][/]/g.test($("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Mountpoint can not contain a period as a sub directory (/./)."); + + validation.mountpoint = false; + } else if (/[/][.][.][/]/g.test($("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Mountpoint can not contain a double period as a sub directory (/../)."); + + validation.mountpoint = false; + } else if (/[/][/]/g.test($("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Mountpoint can not contain double forward slashes (//)."); + + validation.mountpoint = false; + } else if (/[.][.]/g.test($("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Mountpoint can not contain a double period (..)."); + + validation.mountpoint = false; + } else if (/^[ ]/.test($("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Mountpoint can not begin with whitespace ( )."); + + validation.mountpoint = false; + } else if (/[ ]$/.test($("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Mountpoint can not end with whitespace ( )."); + + validation.mountpoint = false; + } else { + $("#validationwrapper-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("hidden").text(""); + + validation.mountpoint = true; + } + + if ($("#switch-storagepool-filesystem-configure-sharenfs-` + filesystem.id + ` input").prop("checked")) { + if (/^[a-zA-Z0-9-_.:/@#+=!&*(), ]*$/.test($("#input-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").val()) == false) { + $("#validationwrapper-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").addClass("has-error"); + $("#helpblock-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("NFS Share options contain invalid characters."); + $("#input-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").focus(); + + validation.sharenfs = false; + } else { + validation.sharenfs = true; + } + } else { + validation.sharenfs = true; + } + + if (!validation.mountpoint || !validation.sharenfs) { + if (!validation.mountpoint) { + $("#validationwrapper-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").addClass("has-error"); + $("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").focus(); + } + + $("#spinner-storagepool-filesystem-configure-` + filesystem.id + `").addClass("hidden"); + $(this).prop("disabled", false); + } + + if (validation.mountpoint && validation.sharenfs) { + filesystem.aclinherit = ($("#btnspan-storagepool-filesystem-configure-aclinherit-` + filesystem.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-filesystem-configure-aclinherit-` + filesystem.id + `").attr("data-field-value-new") : null); + filesystem.acltype = ($("#btnspan-storagepool-filesystem-configure-acltype-` + filesystem.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-filesystem-configure-acltype-` + filesystem.id + `").attr("data-field-value-new") : null); + filesystem.atime = ($("#btnspan-storagepool-filesystem-configure-atime-` + filesystem.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-filesystem-configure-atime-` + filesystem.id + `").attr("data-field-value-new") : null); + filesystem.canmount = ($("#btnspan-storagepool-filesystem-configure-canmount-` + filesystem.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-filesystem-configure-canmount-` + filesystem.id + `").attr("data-field-value-new") : null); + filesystem.checksum = ($("#btnspan-storagepool-filesystem-configure-checksum-` + filesystem.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-filesystem-configure-checksum-` + filesystem.id + `").attr("data-field-value-new") : null); + filesystem.compression = ($("#btnspan-storagepool-filesystem-configure-compression-` + filesystem.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-filesystem-configure-compression-` + filesystem.id + `").attr("data-field-value-new") : null); + filesystem.context = ($("#switch-storagepool-filesystem-configure-selinux-` + filesystem.id + ` input").prop("checked") ? "system_u:object_r:samba_share_t:s0" : "none"); + filesystem.dedup = ($("#btnspan-storagepool-filesystem-configure-dedup-` + filesystem.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-filesystem-configure-dedup-` + filesystem.id + `").attr("data-field-value-new") : null); + filesystem.dnodesize = ($("#btnspan-storagepool-filesystem-configure-dnodesize-` + filesystem.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-filesystem-configure-dnodesize-` + filesystem.id + `").attr("data-field-value-new") : null); + filesystem.defcontext = ($("#switch-storagepool-filesystem-configure-selinux-` + filesystem.id + ` input").prop("checked") ? "system_u:object_r:samba_share_t:s0" : "none"); + filesystem.fscontext = ($("#switch-storagepool-filesystem-configure-selinux-` + filesystem.id + ` input").prop("checked") ? "system_u:object_r:samba_share_t:s0" : "none"); + filesystem.mountpoint = $("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").val(); + filesystem.readonly = ($("#switch-storagepool-filesystem-configure-readonly-` + filesystem.id + ` input").prop("checked") ? "on" : "off"); + filesystem.recordsize = ($("#btnspan-storagepool-filesystem-configure-recordsize-` + filesystem.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-filesystem-configure-recordsize-` + filesystem.id + `").attr("data-field-value-new") : null); + filesystem.rootcontext = ($("#switch-storagepool-filesystem-configure-selinux-` + filesystem.id + ` input").prop("checked") ? "system_u:object_r:samba_share_t:s0" : "none"); + filesystem.selinux = $("#switch-storagepool-filesystem-configure-selinux-` + filesystem.id + ` input").prop("checked"); + filesystem.sharesmb = ` + (zfsmanager.configuration.samba.manage ? `$("#switch-storagepool-filesystem-configure-sharesmb-` + filesystem.id + `").attr("data-field-value");` : `($("#switch-storagepool-filesystem-configure-sharesmb-` + filesystem.id + ` input").prop("checked") ? "on" : "off");`) + ` + filesystem.special_small_blocks = ($("#btnspan-storagepool-filesystem-configure-special_small_blocks-` + filesystem.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-filesystem-configure-special_small_blocks-` + filesystem.id + `").attr("data-field-value-new") : null); + filesystem.xattr = ($("#btnspan-storagepool-filesystem-configure-xattr-` + filesystem.id + `").attr("data-field-value-new") != "" ? $("#btnspan-storagepool-filesystem-configure-xattr-` + filesystem.id + `").attr("data-field-value-new") : null); + + if ($("#input-storagepool-filesystem-configure-quota-` + filesystem.id + `").val() > 0) { //Remove friendly text so final value is sent + filesystem.quota = $("#input-storagepool-filesystem-configure-quota-` + filesystem.id + `").val() + $("#btnspan-storagepool-filesystem-configure-quota-` + filesystem.id + `").attr("data-field-value").replace(/iB$/g, ""); + } else { + filesystem.quota = "none"; + } + + if ($("#input-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").val() > 0) { //Remove friendly text so final value is sent + filesystem.refreservation = $("#input-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").val() + $("#btnspan-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").attr("data-field-value").replace(/iB$/g, ""); + } else { + filesystem.refreservation = "0B"; + } + + if ($("#switch-storagepool-filesystem-configure-sharenfs-` + filesystem.id + ` input").prop("checked")) { + if ($("#input-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").val().toLowerCase() == "on" || $("#input-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").val() == "sec=sys,rw,crossmnt,no_subtree_check,no_root_squash" || !$("#input-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").val()) { + filesystem.sharenfs = "on"; + } else { + filesystem.sharenfs = $("#input-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").val(); + } + } else { + filesystem.sharenfs = "off"; + } + + //Set values to null if unchanged, so that they are skipped in the configure function + if (/^Inherited/.test(filesystem.aclinherit) && $("#btnspan-storagepool-filesystem-configure-aclinherit-` + filesystem.id + `").attr("data-field-source") == "inherited") { + filesystem.aclinherit = null; + } else if (/^Default/.test(filesystem.aclinherit) && $("#btnspan-storagepool-filesystem-configure-aclinherit-` + filesystem.id + `").attr("data-field-source") == "default") { + filesystem.aclinherit = null; + } else if (filesystem.aclinherit == $("#btnspan-storagepool-filesystem-configure-aclinherit-` + filesystem.id + `").attr("data-field-value") && $("#btnspan-storagepool-filesystem-configure-aclinherit-` + filesystem.id + `").attr("data-field-source") == "local") { + filesystem.aclinherit = null; + } + + if (/^Inherited/.test(filesystem.acltype) && $("#btnspan-storagepool-filesystem-configure-acltype-` + filesystem.id + `").attr("data-field-source") == "inherited") { + filesystem.acltype = null; + } else if (/^Default/.test(filesystem.acltype) && $("#btnspan-storagepool-filesystem-configure-acltype-` + filesystem.id + `").attr("data-field-source") == "default") { + filesystem.acltype = null; + } else if (filesystem.acltype == $("#btnspan-storagepool-filesystem-configure-acltype-` + filesystem.id + `").attr("data-field-value") && $("#btnspan-storagepool-filesystem-configure-acltype-` + filesystem.id + `").attr("data-field-source") == "local") { + filesystem.acltype = null; + } + + if (/^Inherited/.test(filesystem.atime) && $("#btnspan-storagepool-filesystem-configure-atime-` + filesystem.id + `").attr("data-field-source") == "inherited") { + filesystem.atime = null; + } else if (/^Default/.test(filesystem.atime) && $("#btnspan-storagepool-filesystem-configure-atime-` + filesystem.id + `").attr("data-field-source") == "default") { + filesystem.atime = null; + } else if (filesystem.atime == $("#btnspan-storagepool-filesystem-configure-atime-` + filesystem.id + `").attr("data-field-value") && $("#btnspan-storagepool-filesystem-configure-atime-` + filesystem.id + `").attr("data-field-source") == "local") { + filesystem.atime = null; + } + + if (filesystem.canmount == $("#btnspan-storagepool-filesystem-configure-canmount-` + filesystem.id + `").attr("data-field-value")) { + filesystem.canmount = null; + } + + if (/^Inherited/.test(filesystem.checksum) && $("#btnspan-storagepool-filesystem-configure-checksum-` + filesystem.id + `").attr("data-field-source") == "inherited") { + filesystem.checksum = null; + } else if (/^Default/.test(filesystem.checksum) && $("#btnspan-storagepool-filesystem-configure-checksum-` + filesystem.id + `").attr("data-field-source") == "default") { + filesystem.checksum = null; + } else if (filesystem.checksum == $("#btnspan-storagepool-filesystem-configure-checksum-` + filesystem.id + `").attr("data-field-value") && $("#btnspan-storagepool-filesystem-configure-checksum-` + filesystem.id + `").attr("data-field-source") == "local") { + filesystem.checksum = null; + } + + if (/^Inherited/.test(filesystem.compression) && $("#btnspan-storagepool-filesystem-configure-compression-` + filesystem.id + `").attr("data-field-source") == "inherited") { + filesystem.compression = null; + } else if (/^Default/.test(filesystem.compression) && $("#btnspan-storagepool-filesystem-configure-compression-` + filesystem.id + `").attr("data-field-source") == "default") { + filesystem.compression = null; + } else if (filesystem.compression == $("#btnspan-storagepool-filesystem-configure-compression-` + filesystem.id + `").attr("data-field-value") && $("#btnspan-storagepool-filesystem-configure-compression-` + filesystem.id + `").attr("data-field-source") == "local") { + filesystem.compression = null; + } + + + if (/^Inherited/.test(filesystem.dedup) && $("#btnspan-storagepool-filesystem-configure-dedup-` + filesystem.id + `").attr("data-field-source") == "inherited") { + filesystem.dedup = null; + } else if (/^Default/.test(filesystem.dedup) && $("#btnspan-storagepool-filesystem-configure-dedup-` + filesystem.id + `").attr("data-field-source") == "default") { + filesystem.dedup = null; + } else if (filesystem.dedup == $("#btnspan-storagepool-filesystem-configure-dedup-` + filesystem.id + `").attr("data-field-value") && $("#btnspan-storagepool-filesystem-configure-dedup-` + filesystem.id + `").attr("data-field-source") == "local") { + filesystem.dedup = null; + } + + if (/^Inherited/.test(filesystem.dnodesize) && $("#btnspan-storagepool-filesystem-configure-dnodesize-` + filesystem.id + `").attr("data-field-source") == "inherited") { + filesystem.dnodesize = null; + } else if (/^Default/.test(filesystem.dnodesize) && $("#btnspan-storagepool-filesystem-configure-dnodesize-` + filesystem.id + `").attr("data-field-source") == "default") { + filesystem.dnodesize = null; + } else if (filesystem.dnodesize == $("#btnspan-storagepool-filesystem-configure-dnodesize-` + filesystem.id + `").attr("data-field-value") && $("#btnspan-storagepool-filesystem-configure-dnodesize-` + filesystem.id + `").attr("data-field-source") == "local") { + filesystem.dnodesize = null; + } + + if (filesystem.mountpoint == $("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").attr("data-field-value")) { + filesystem.mountpoint = null; + } else { + ` + (pool.altroot ? `filesystem.mountpoint = filesystem.mountpoint.replace(new RegExp("^" + $("#input-storagepool-filesystem-configure-mountpoint-` + filesystem.id + `").attr("data-field-altroot")), "");` : ``) + ` + + samba.restart = $("#switch-storagepool-filesystem-configure-samba-restart-` + filesystem.id + ` input").prop("checked"); + } + + if (filesystem.quota == $("#input-storagepool-filesystem-configure-quota-` + filesystem.id + `").attr("data-field-value")) { + filesystem.quota = null; + } + + if (filesystem.readonly == $("#switch-storagepool-filesystem-configure-readonly-` + filesystem.id + `").attr("data-field-value")) { + filesystem.readonly = null; + } + + if (/^Inherited/.test(filesystem.recordsize) && $("#btnspan-storagepool-filesystem-configure-recordsize-` + filesystem.id + `").attr("data-field-source") == "inherited") { + filesystem.recordsize = null; + } else if (/^Default/.test(filesystem.recordsize) && $("#btnspan-storagepool-filesystem-configure-recordsize-` + filesystem.id + `").attr("data-field-source") == "default") { + filesystem.recordsize = null; + } else if (filesystem.recordsize == $("#btnspan-storagepool-filesystem-configure-recordsize-` + filesystem.id + `").attr("data-field-value") && $("#btnspan-storagepool-filesystem-configure-recordsize-` + filesystem.id + `").attr("data-field-source") == "local") { + filesystem.recordsize = null; + } + + if (filesystem.refreservation == $("#input-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").attr("data-field-value")) { + filesystem.refreservation = null; + } + + if (filesystem.selinux == $("#switch-storagepool-filesystem-configure-selinux-` + filesystem.id + `").attr("data-field-value")) { + filesystem.context = null; + filesystem.defcontext = null; + filesystem.fscontext = null; + filesystem.rootcontext = null; + filesystem.selinux = null; + } + + if (filesystem.sharenfs == $("#input-storagepool-filesystem-configure-sharenfs-options-` + filesystem.id + `").attr("data-field-value")) { + filesystem.sharenfs = null; + } + + if (/^Inherited/.test(filesystem.special_small_blocks) && $("#btnspan-storagepool-filesystem-configure-special_small_blocks-` + filesystem.id + `").attr("data-field-source") == "inherited") { + filesystem.special_small_blocks = null; + } else if (/^Default/.test(filesystem.special_small_blocks) && $("#btnspan-storagepool-filesystem-configure-special_small_blocks-` + filesystem.id + `").attr("data-field-source") == "default") { + filesystem.special_small_blocks = null; + } else if (filesystem.special_small_blocks == $("#btnspan-storagepool-filesystem-configure-special_small_blocks-` + filesystem.id + `").attr("data-field-value") && $("#btnspan-storagepool-filesystem-configure-special_small_blocks-` + filesystem.id + `").attr("data-field-source") == "local") { + filesystem.special_small_blocks = null; + } + + if (/^Inherited/.test(filesystem.xattr) && $("#btnspan-storagepool-filesystem-configure-xattr-` + filesystem.id + `").attr("data-field-source") == "inherited") { + filesystem.xattr = null; + } else if (/^Default/.test(filesystem.xattr) && $("#btnspan-storagepool-filesystem-configure-xattr-` + filesystem.id + `").attr("data-field-source") == "default") { + filesystem.xattr = null; + } else if (filesystem.xattr == $("#btnspan-storagepool-filesystem-configure-xattr-` + filesystem.id + `").attr("data-field-value") && $("#btnspan-storagepool-filesystem-configure-xattr-` + filesystem.id + `").attr("data-field-source") == "local") { + filesystem.xattr = null; + } + + FnFileSystemConfigure({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", aclinherit: filesystem.aclinherit, acltype: filesystem.acltype, atime: filesystem.atime, canmount: filesystem.canmount, checksum: filesystem.checksum, compression: filesystem.compression, context: filesystem.context, dedup: filesystem.dedup, dnodesize: filesystem.dnodesize, defcontext: filesystem.defcontext, fscontext: filesystem.fscontext, mountpoint: filesystem.mountpoint, quota: filesystem.quota, readonly: filesystem.readonly, recordsize: filesystem.recordsize, refreservation: filesystem.refreservation, rootcontext: filesystem.rootcontext, sharenfs: filesystem.sharenfs, sharesmb: filesystem.sharesmb, special_small_blocks: filesystem.special_small_blocks, type: "` + filesystem.type + `", xattr: filesystem.xattr }, { restart: samba.restart }, { id: modal.id }); + } + }); + + $("#dropdown-storagepool-filesystem-configure-aclinherit-` + filesystem.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-filesystem-configure-aclinherit-` + filesystem.id + `").text($(this).text()).attr("data-field-value-new", (/^Default/.test($(this).text()) ? "Default" : $(this).parent().attr("value"))); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + + $("#dropdown-storagepool-filesystem-configure-acltype-` + filesystem.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-filesystem-configure-acltype-` + filesystem.id + `").text($(this).text()).attr("data-field-value-new", (/^Default/.test($(this).text()) ? "Default" : $(this).parent().attr("value"))); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + + $("#dropdown-storagepool-filesystem-configure-atime-` + filesystem.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-filesystem-configure-atime-` + filesystem.id + `").text($(this).text()).attr("data-field-value-new", (/^Default/.test($(this).text()) ? "Default" : $(this).parent().attr("value"))); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + + $("#dropdown-storagepool-filesystem-configure-canmount-` + filesystem.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-filesystem-configure-canmount-` + filesystem.id + `").text($(this).text()).attr("data-field-value-new", (/^Default/.test($(this).text()) ? "Default" : $(this).parent().attr("value"))); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + + $("#dropdown-storagepool-filesystem-configure-checksum-` + filesystem.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-filesystem-configure-checksum-` + filesystem.id + `").text($(this).text()).attr("data-field-value-new", (/^Default/.test($(this).text()) ? "Default" : $(this).parent().attr("value"))); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + + $("#dropdown-storagepool-filesystem-configure-compression-` + filesystem.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-filesystem-configure-compression-` + filesystem.id + `").text($(this).text()).attr("data-field-value-new", (/^Default/.test($(this).text()) ? "Default" : $(this).parent().attr("value"))); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + + $("#dropdown-storagepool-filesystem-configure-dedup-` + filesystem.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-filesystem-configure-dedup-` + filesystem.id + `").text($(this).text()).attr("data-field-value-new", (/^Default/.test($(this).text()) ? "Default" : $(this).parent().attr("value"))); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + + $("#dropdown-storagepool-filesystem-configure-dnodesize-` + filesystem.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-filesystem-configure-dnodesize-` + filesystem.id + `").text($(this).text()).attr("data-field-value-new", (/^Default/.test($(this).text()) ? "Default" : $(this).parent().attr("value"))); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + + $("#dropdown-storagepool-filesystem-configure-quota-` + filesystem.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-filesystem-configure-quota-` + filesystem.id + `").text($(this).text()).attr("data-field-value", $(this).text()); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + + let size = { + slider: { + value: $("#input-storagepool-filesystem-configure-quota-` + filesystem.id + `").val(), + valuemax: $("#input-storagepool-filesystem-configure-quota-` + filesystem.id + `").attr("data-filesystem-quota-max-" + $(this).text().toLowerCase()) + } + }; + + $("#slider-storagepool-filesystem-configure-quota-` + filesystem.id + `").data("slider").options.max = size.slider.valuemax; + $("#slider-storagepool-filesystem-configure-quota-` + filesystem.id + `").data("slider").options.step = (size.slider.valuemax < 10 ? "0.1" : "1"); + $("#slider-storagepool-filesystem-configure-quota-` + filesystem.id + `").slider("setValue", 0); //Force display update + $("#slider-storagepool-filesystem-configure-quota-` + filesystem.id + `").slider("setValue", size.slider.value); + $("#input-storagepool-filesystem-configure-quota-` + filesystem.id + `").val($("#slider-storagepool-filesystem-configure-quota-` + filesystem.id + `").data("slider").getValue()); + }); + + $("#dropdown-storagepool-filesystem-configure-recordsize-` + filesystem.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-filesystem-configure-recordsize-` + filesystem.id + `").text($(this).text()).attr("data-field-value-new", (/^Default/.test($(this).text()) ? "Default" : $(this).parent().attr("value"))); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + + $("#dropdown-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").text($(this).text()).attr("data-field-value", $(this).text()); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + + let size = { + slider: { + value: $("#input-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").val(), + valuemax: $("#input-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").attr("data-filesystem-refreservation-max-" + $(this).text().toLowerCase()) + } + }; + + $("#slider-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").data("slider").options.max = size.slider.valuemax; + $("#slider-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").data("slider").options.step = (size.slider.valuemax < 10 ? "0.1" : "1"); + $("#slider-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").slider("setValue", 0); //Force display update + $("#slider-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").slider("setValue", size.slider.value); + $("#input-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").val($("#slider-storagepool-filesystem-configure-refreservation-` + filesystem.id + `").data("slider").getValue()); + }); + + $("#dropdown-storagepool-filesystem-configure-special_small_blocks-` + filesystem.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-filesystem-configure-special_small_blocks-` + filesystem.id + `").text($(this).text()).attr("data-field-value-new", (/^Default/.test($(this).text()) ? "Default" : $(this).parent().attr("value"))); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + + $("#dropdown-storagepool-filesystem-configure-xattr-` + filesystem.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-filesystem-configure-xattr-` + filesystem.id + `").text($(this).text()).attr("data-field-value-new", (/^Default/.test($(this).text()) ? "Default" : $(this).parent().attr("value"))); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalFileSystemDestroy(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, sharesmb: false, type }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-filesystem-destroy-` + filesystem.id + `").on("click", function () { + FnModalFileSystemDestroyContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", sharesmb: ` + filesystem.sharesmb + `, type: "` + filesystem.type + `" }, { id: $("#modal-storagepool-filesystem-destroy-` + filesystem.id + `") }); + FnFileSystemChildDatasetsGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", clones: true }, { name: "storagepool-filesystem-destroy", id: "` + filesystem.id + `" }); + }); + \x3C/script> + `; + + $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); +} + +function FnModalFileSystemDestroyContent(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, sharesmb: false, type }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#switch-storagepool-filesystem-destroy-recursive-` + filesystem.id + ` input").on("click", function () { + if ($(this).prop("checked") && $("#switch-storagepool-filesystem-destroy-recursiveall-` + filesystem.id + ` input").prop("checked")) { + $("#switch-storagepool-filesystem-destroy-recursiveall-` + filesystem.id + ` input").click(); + } + + $("#panel-storagepool-filesystem-destroy-child-filesystemswithclones-` + filesystem.id + `").addClass("hidden"); + $("#panel-storagepool-filesystem-destroy-child-filesystemswithclones-` + filesystem.id + ` .collapse").collapse("hide"); + $("#panel-storagepool-filesystem-destroy-child-snapshotswithclones-` + filesystem.id + `").addClass("hidden"); + $("#panel-storagepool-filesystem-destroy-child-snapshotswithclones-` + filesystem.id + ` .collapse").collapse("hide"); + + if ($(this).prop("checked") && $("#panelgroup-storagepool-filesystem-destroy-` + filesystem.id + `").attr("data-filesystem-child-filesystems") > 0) { + $("#panel-storagepool-filesystem-destroy-child-filesystems-` + filesystem.id + `").removeClass("hidden"); + } else { + $("#panel-storagepool-filesystem-destroy-child-filesystems-` + filesystem.id + `").addClass("hidden"); + $("#panel-storagepool-filesystem-destroy-child-filesystems-` + filesystem.id + ` .collapse").collapse("hide"); + } + if ($(this).prop("checked") && $("#panelgroup-storagepool-filesystem-destroy-` + filesystem.id + `").attr("data-filesystem-child-snapshots") > 0) { + $("#panel-storagepool-filesystem-destroy-child-snapshots-` + filesystem.id + `").removeClass("hidden"); + } else { + $("#panel-storagepool-filesystem-destroy-child-snapshots-` + filesystem.id + `").addClass("hidden"); + $("#panel-storagepool-filesystem-destroy-child-snapshots-` + filesystem.id + ` .collapse").collapse("hide"); + } + if ($(this).prop("checked") && ($("#panelgroup-storagepool-filesystem-destroy-` + filesystem.id + `").attr("data-filesystem-child-filesystems") > 0 || $("#panelgroup-storagepool-filesystem-destroy-` + filesystem.id + `").attr("data-filesystem-child-snapshots") > 0)) { + $("#panelgroup-storagepool-filesystem-destroy-` + filesystem.id + `").addClass("modal-ct-bodytext-1"); + } else { + $("#panelgroup-storagepool-filesystem-destroy-` + filesystem.id + `").removeClass("modal-ct-bodytext-1"); + } + }); + + $("#switch-storagepool-filesystem-destroy-recursiveall-` + filesystem.id + ` input").on("click", function () { + if ($(this).prop("checked") && $("#switch-storagepool-filesystem-destroy-recursive-` + filesystem.id + ` input").prop("checked")) { + $("#switch-storagepool-filesystem-destroy-recursive-` + filesystem.id + ` input").click(); + } + + $("#panel-storagepool-filesystem-destroy-child-filesystems-` + filesystem.id + `").addClass("hidden"); + $("#panel-storagepool-filesystem-destroy-child-filesystems-` + filesystem.id + ` .collapse").collapse("hide"); + $("#panel-storagepool-filesystem-destroy-child-snapshots-` + filesystem.id + `").addClass("hidden"); + $("#panel-storagepool-filesystem-destroy-child-snapshots-` + filesystem.id + ` .collapse").collapse("hide"); + + if ($(this).prop("checked") && $("#panelgroup-storagepool-filesystem-destroy-` + filesystem.id + `").attr("data-filesystem-child-filesystemswithclones") > 0) { + $("#panel-storagepool-filesystem-destroy-child-filesystemswithclones-` + filesystem.id + `").removeClass("hidden"); + } else { + $("#panel-storagepool-filesystem-destroy-child-filesystemswithclones-` + filesystem.id + `").addClass("hidden"); + $("#panel-storagepool-filesystem-destroy-child-filesystemswithclones-` + filesystem.id + ` .collapse").collapse("hide"); + } + if ($(this).prop("checked") && $("#panelgroup-storagepool-filesystem-destroy-` + filesystem.id + `").attr("data-filesystem-child-snapshotswithclones") > 0) { + $("#panel-storagepool-filesystem-destroy-child-snapshotswithclones-` + filesystem.id + `").removeClass("hidden"); + } else { + $("#panel-storagepool-filesystem-destroy-child-snapshotswithclones-` + filesystem.id + `").addClass("hidden"); + $("#panel-storagepool-filesystem-destroy-child-snapshotswithclones-` + filesystem.id + ` .collapse").collapse("hide"); + } + if ($(this).prop("checked") && ($("#panelgroup-storagepool-filesystem-destroy-` + filesystem.id + `").attr("data-filesystem-child-filesystemswithclones") > 0 || $("#panelgroup-storagepool-filesystem-destroy-` + filesystem.id + `").attr("data-filesystem-child-snapshotswithclones") > 0)) { + $("#panelgroup-storagepool-filesystem-destroy-` + filesystem.id + `").addClass("modal-ct-bodytext-1"); + } else { + $("#panelgroup-storagepool-filesystem-destroy-` + filesystem.id + `").removeClass("modal-ct-bodytext-1"); + } + }); + + $("#btn-storagepool-filesystem-destroy-apply-` + filesystem.id + `").on("click", function () { + $("#spinner-storagepool-filesystem-destroy-` + filesystem.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let filesystem = { + force: $("#switch-storagepool-filesystem-destroy-force-` + filesystem.id + ` input").prop("checked"), + recursive: $("#switch-storagepool-filesystem-destroy-recursive-` + filesystem.id + ` input").prop("checked"), + recursiveall: $("#switch-storagepool-filesystem-destroy-recursiveall-` + filesystem.id + ` input").prop("checked") + }; + let samba = { + restart: $("#switch-storagepool-filesystem-destroy-samba-restart-` + filesystem.id + ` input").prop("checked") + }; + + FnFileSystemDestroy({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", force: filesystem.force, recursive: filesystem.recursive, recursiveall: filesystem.recursiveall, sharesmb: ` + filesystem.sharesmb + `, type: "` + filesystem.type + `" }, { restart: samba.restart }); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalFileSystemLock(pool = { name, id }, filesystem = { name, id, type }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-filesystem-lock-` + filesystem.id + `").on("click", function () { + FnModalFileSystemLockContent({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", type: "` + filesystem.type + `" }, { id: $("#modal-storagepool-filesystem-lock-` + filesystem.id + `") }); + }); + \x3C/script> + `; + + $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); +} + +function FnModalFileSystemLockContent(pool = { name, id }, filesystem = { name, id, type }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-filesystem-lock-apply-` + filesystem.id + `").on("click", function () { + $("#spinner-storagepool-filesystem-lock-` + filesystem.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + FnFileSystemLock({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", type: "` + filesystem.type + `" }, { refresh: true }); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalFileSystemMount(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, sharesmb: false, type }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-filesystem-mount-` + filesystem.id + `").on("click", function () { + FnModalFileSystemMountContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", sharesmb: ` + filesystem.sharesmb + `, type: "` + filesystem.type + `" }, { id: $("#modal-storagepool-filesystem-mount-` + filesystem.id + `") }); + FnFileSystemsMountedGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `" }, { alert: { id: $("#div-storagepool-filesystem-mount-warning-` + filesystem.id + `"), mount: true } }); + }); + \x3C/script> + `; + + $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); +} + +function FnModalFileSystemMountContent(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, sharesmb: false, type }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#switch-storagepool-filesystem-mount-samba-enable-` + filesystem.id + ` input").on("click", function () { + if ($(this).prop("checked")) { + ` + (filesystem.name == pool.name ? `$("#alert-storagepool-filesystem-samba-warning-` + filesystem.id + `").removeClass("hidden");` : ``) + ` + } else { + ` + (filesystem.name == pool.name ? `$("#alert-storagepool-filesystem-samba-warning-` + filesystem.id + `").addClass("hidden");` : ``) + ` + } + }); + + $("#btn-storagepool-filesystem-mount-apply-` + filesystem.id + `").on("click", function () { + $("#spinner-storagepool-filesystem-mount-` + filesystem.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let filesystem = { + overlay: $("#switch-storagepool-filesystem-mount-overlay-` + filesystem.id + ` input").prop("checked") + }; + let samba = { + enable: ` + ((pool.readonly || filesystem.sharesmb) ? false : `$("#switch-storagepool-filesystem-mount-samba-enable-` + filesystem.id + ` input").prop("checked")`) + ` + }; + + FnFileSystemMount({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", overlay: filesystem.overlay, type: "` + filesystem.type + `" }, { enable: samba.enable }, { refresh: true }); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalFileSystemPromote(pool = { name, id }, filesystem = { name, id, origin, type }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-filesystem-promote-` + filesystem.id + `").on("click", function () { + FnModalFileSystemPromoteContent({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", origin: "` + filesystem.origin + `", type: "` + filesystem.type + `" }, { id: $("#modal-storagepool-filesystem-promote-` + filesystem.id + `") }); + }); + \x3C/script> + `; + + $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); +} + +function FnModalFileSystemPromoteContent(pool = { name, id }, filesystem = { name, id, origin, type }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-filesystem-promote-apply-` + filesystem.id + `").on("click", function () { + $("#spinner-storagepool-filesystem-promote-` + filesystem.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + FnFileSystemPromote({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", type: "` + filesystem.type + `" }); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalFileSystemRename(pool = { name, id, altroot: false }, filesystem = { name, id, clone: false, encryption: false, encryptionroot, origin, sharesmb: false, type }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-filesystem-rename-` + filesystem.id + `").on("click", function () { + FnModalFileSystemRenameContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", clone: ` + filesystem.clone + `, encryption: ` + filesystem.encryption + `, origin: "` + filesystem.origin + `", sharesmb: ` + filesystem.sharesmb + `, type: "` + filesystem.type + `" }, { id: $("#modal-storagepool-filesystem-rename-` + filesystem.id + `") }); + FnFileSystemsNamesGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { existing: { name: "` + filesystem.name + `", clone: ` + filesystem.clone + `, encryption: ` + filesystem.encryption + `, encryptionroot: "` + filesystem.encryptionroot + `", origin: "` + filesystem.origin + `" }, override: false }, { dropdown: { id: $("#dropdown-storagepool-filesystem-rename-parentfilesystem-` + filesystem.id + `"), selected: "` + filesystem.name.replace(/\/[^\/]+$/, "") + `" } }); + + setTimeout(function() { + $("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").focus(); + }, 600); + }); + \x3C/script> + `; + + $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); +} + +function FnModalFileSystemRenameContent(pool = { name, id, altroot: false }, filesystem = { name, id, clone: false, encryption: false, origin, sharesmb: false, type }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-filesystem-rename-apply-` + filesystem.id + `").on("click", function () { + $("#spinner-storagepool-filesystem-rename-` + filesystem.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let filesystem = { + createnonexistparents: false, + force: false, + namenew: "", + parent: "" + }; + let samba = { + restart: false + }; + let validation = { + name: false + }; + + if ($("#btnspan-storagepool-filesystem-rename-parentfilesystem-` + filesystem.id + `").attr("data-field-value") + "/" + $("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val() == "` + filesystem.name + `") { + $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name or parent file system must be different."); + + validation.name = false; + } else if (new RegExp("^" + "` + filesystem.name + `/").test($("#btnspan-storagepool-filesystem-rename-parentfilesystem-` + filesystem.id + `").attr("data-field-value") + "/" + $("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not be a descendant of current file system."); + + validation.name = false; + } else if ($("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val().length == 0) { + $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not be empty."); + + validation.name = false; + } else if (/^[a-zA-Z0-9-_.:/ ]*$/.test($("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val()) == false) { + $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name contains invalid characters."); + + validation.name = false; + } else if (/^[.]/.test($("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a period (.)."); + + validation.name = false; + } else if (/^[_]/.test($("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with an underscore (_)."); + + validation.name = false; + } else if (/^[-]/.test($("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a hypen (-)."); + + validation.name = false; + } else if (/^[:]/.test($("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with an colon (:)."); + + validation.name = false; + } else if (/^[/]/.test($("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a forward slash (/)."); + + validation.name = false; + } else if (/[/]$/.test($("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not end with a forward slash (/)."); + + validation.name = false; + } else if (/^ |\\/ /.test($("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with whitespace ( )."); + + validation.name = false; + } else if (/ $| \\//.test($("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not end with whitespace ( )."); + + validation.name = false; + } else { + $("#validationwrapper-storagepool-filesystem-rename-name-` + filesystem.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("hidden").text(""); + + validation.name = true; + } + + if (!validation.name) { + $("#validationwrapper-storagepool-filesystem-rename-name-` + filesystem.id + `").addClass("has-error"); + $("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").focus(); + + $("#spinner-storagepool-filesystem-rename-` + filesystem.id + `").addClass("hidden"); + $(this).prop("disabled", false); + } + + if (validation.name) { + filesystem.createnonexistparents = $("#switch-storagepool-filesystem-rename-createnonexistparents-` + filesystem.id + ` input").prop("checked"); + filesystem.force = $("#switch-storagepool-filesystem-rename-force-` + filesystem.id + ` input").prop("checked"); + filesystem.namenew = $("#btnspan-storagepool-filesystem-rename-parentfilesystem-` + filesystem.id + `").attr("data-field-value") + "/" + $("#input-storagepool-filesystem-rename-name-` + filesystem.id + `").val(); + filesystem.parent = $("#btnspan-storagepool-filesystem-rename-parentfilesystem-` + filesystem.id + `").attr("data-field-value"); + + samba.restart = $("#switch-storagepool-filesystem-rename-samba-restart-` + filesystem.id + ` input").prop("checked") + + FnFileSystemRename({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", createnonexistparents: filesystem.createnonexistparents, force: filesystem.force, namenew: filesystem.namenew, parent: filesystem.parent, sharesmb: ` + filesystem.sharesmb + `, type: "` + filesystem.type + `" }, { restart: samba.restart }); + } + }); + + $("#dropdown-storagepool-filesystem-rename-parentfilesystem-` + filesystem.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-filesystem-rename-parentfilesystem-` + filesystem.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalFileSystemSambaConfigure(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, mountpoint }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-filesystem-samba-configure-` + filesystem.id + `").on("click", function () { + FnModalFileSystemSambaConfigureContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", mountpoint: "` + filesystem.mountpoint + `" }, { id: $("#modal-storagepool-filesystem-samba-configure-` + filesystem.id + `") }); + FnSambaZfsShareConfigurationGet({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `" }, { name: "storagepool-filesystem-samba-configure", id: "` + filesystem.id + `" }); + + setTimeout(function() { + $("#input-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").focus(); + }, 600); + }); + \x3C/script> + `; + + $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); +} + +function FnModalFileSystemSambaConfigureContent(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, mountpoint }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#switch-storagepool-filesystem-samba-configure-additional-` + filesystem.id + ` input").on("click", function () { + $("#validationwrapper-storagepool-filesystem-samba-configure-additional-` + filesystem.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystem-samba-configure-additional-` + filesystem.id + `").removeClass("has-error").addClass("hidden").text(""); + + if ($("#switch-storagepool-filesystem-samba-configure-additional-` + filesystem.id + ` input").prop("checked")) { + $("#validationwrapper-storagepool-filesystem-samba-configure-additional-` + filesystem.id + `").removeClass("hidden"); + } else { + $("#validationwrapper-storagepool-filesystem-samba-configure-additional-` + filesystem.id + `").addClass("hidden"); + } + }); + + $("#btn-storagepool-filesystem-samba-configure-apply-` + filesystem.id + `").on("click", function () { + $("#spinner-storagepool-filesystem-samba-configure-` + filesystem.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let samba = { + share: { + additional: ($("#switch-storagepool-filesystem-samba-configure-additional-` + filesystem.id + ` input").prop("checked") ? $("#textarea-storagepool-filesystem-samba-configure-additional-` + filesystem.id + `").val().split("\\n").filter(v => v) : []), + administrative: false, + browseable: true, + comment: "", + guestok: false, + name: "", + nameexisting: "", + readonly: false + } + }; + let validation = { + comment: false, + name: false, + additional: false + }; + + if ($("#input-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").val().length == 0) { + $("#helpblock-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Share name can not be empty."); + + validation.name = false; + } else if (/^[a-zA-Z0-9-_.@%+!#$^,(){}~ ]*$/.test($("#input-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").val()) == false) { + $("#helpblock-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Share name contains invalid characters."); + + validation.name = false; + } else if (/^[ ]/.test($("#input-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Share name can not begin with whitespace ( )."); + + validation.name = false; + } else if (/[ ]$/.test($("#input-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Share name can not end with whitespace ( )."); + + validation.name = false; + } else { + $("#validationwrapper-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").addClass("hidden").text(""); + + validation.name = true; + } + + if (/^[ -~]*$/.test($("#input-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").val()) == false) { + $("#helpblock-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Comment contains invalid characters."); + + validation.comment = false; + } else if (/^[.]/.test($("#input-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Comment can not begin with a period (.)."); + + validation.comment = false; + } else if (/^[ ]/.test($("#input-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Comment can not begin with whitespace ( )."); + + validation.comment = false; + } else if (/[ ]$/.test($("#input-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Comment can not end with whitespace ( )."); + + validation.comment = false; + } else { + $("#validationwrapper-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").addClass("hidden").text(""); + + validation.comment = true; + } + + if (samba.share.additional.length > 0) { + samba.share.additional.forEach((_value, _index) => { + if (/[\\[\\]]/g.test(_value)) { //Do not allow section names + $("#helpblock-storagepool-filesystem-samba-configure-additional-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Additional must not contain brackets. Line: " + (_index + 1)); + + validation.additional = false; + return; + } else if (/^[#]/.test(_value) == false && /[=]/.test(_value) && /(path|comment|browseable|read only|guest ok).*=/gi.test(_value)) { + $("#helpblock-storagepool-filesystem-samba-configure-additional-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Additional must not contain duplicate properties. Line: " + (_index + 1)); + + validation.additional = false; + return; + } else if (/[#=]/.test(_value) == false) { + $("#helpblock-storagepool-filesystem-samba-configure-additional-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Additional must contain comments or properties only. Line: " + (_index + 1)); + + validation.additional = false; + return; + } else if (_index == (samba.share.additional.length -1)) { + $("#validationwrapper-storagepool-filesystem-samba-configure-additional-` + filesystem.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystem-samba-configure-additional-` + filesystem.id + `").removeClass("has-error").addClass("hidden").text(""); + + validation.additional = true; + } + }); + } else { + validation.additional = true; + } + + if (!validation.name || !validation.comment || !validation.additional) { + if (!validation.name) { + $("#validationwrapper-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").addClass("has-error"); + $("#input-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").focus(); + } + if (!validation.comment) { + $("#validationwrapper-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").addClass("has-error"); + $("#input-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").focus(); + } + if (!validation.additional) { + $("#validationwrapper-storagepool-filesystem-samba-configure-additional-` + filesystem.id + `").addClass("has-error"); + $("#textarea-storagepool-filesystem-samba-configure-additional-` + filesystem.id + `").focus(); + } + + $("#spinner-storagepool-filesystem-samba-configure-` + filesystem.id + `").addClass("hidden"); + $(this).prop("disabled", false); + } + + if (validation.name && validation.comment && validation.additional) { + samba.restart = $("#switch-storagepool-filesystem-samba-configure-restart-` + filesystem.id + ` input").prop("checked"); + samba.share.administrative = $("#switch-storagepool-filesystem-samba-configure-administrative-` + filesystem.id + ` input").prop("checked"); + samba.share.browseable = $("#switch-storagepool-filesystem-samba-configure-browseable-` + filesystem.id + ` input").prop("checked"); + samba.share.comment = $("#input-storagepool-filesystem-samba-configure-comment-` + filesystem.id + `").val(); + samba.share.guestok = $("#switch-storagepool-filesystem-samba-configure-guestok-` + filesystem.id + ` input").prop("checked"); + samba.share.name = $("#input-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").val(); + samba.share.nameexisting = $("#input-storagepool-filesystem-samba-configure-name-` + filesystem.id + `").attr("data-field-value"); + samba.share.readonly = $("#switch-storagepool-filesystem-samba-configure-readonly-` + filesystem.id + ` input").prop("checked"); + + FnSambaZfsShareConfigure({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", mountpoint: "` + filesystem.mountpoint + `" }, { share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, nameexisting: samba.share.nameexisting, readonly: samba.share.readonly, temporary: ` + (pool.altroot || pool.readonly ? true : false) + ` }, restart: samba.restart }); + } + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalFileSystemSambaDisable(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, type }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-filesystem-samba-disable-` + filesystem.id + `").on("click", function () { + FnModalFileSystemSambaDisableContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", type: "` + filesystem.type + `" }, { id: $("#modal-storagepool-filesystem-samba-disable-` + filesystem.id + `") }); + }); + \x3C/script> + `; + + $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); +} + +function FnModalFileSystemSambaDisableContent(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, type }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-filesystem-samba-disable-apply-` + filesystem.id + `").on("click", function () { + $("#spinner-storagepool-filesystem-samba-disable-` + filesystem.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let samba = { + restart: $("#switch-storagepool-filesystem-samba-disable-restart-` + filesystem.id + ` input").prop("checked") + }; + + FnSambaShareDisable({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `" }, { restart: samba.restart }, { modal: true, silent: false }); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalFileSystemSambaEnable(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, mounted: false, mountpoint }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-filesystem-samba-enable-` + filesystem.id + `").on("click", function () { + FnModalFileSystemSambaEnableContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", mounted: ` + filesystem.mounted + `, mountpoint: "` + filesystem.mountpoint + `" }, { id: $("#modal-storagepool-filesystem-samba-enable-` + filesystem.id + `") }); + + setTimeout(function() { + $("#input-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").focus(); + }, 600); + }); + \x3C/script> + `; + + $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); +} + +function FnModalFileSystemSambaEnableContent(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, mounted: false, mountpoint }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#switch-storagepool-filesystem-samba-enable-additional-` + filesystem.id + ` input").on("click", function () { + $("#validationwrapper-storagepool-filesystem-samba-enable-additional-` + filesystem.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystem-samba-enable-additional-` + filesystem.id + `").removeClass("has-error").addClass("hidden").text(""); + + if ($(this).prop("checked")) { + $("#validationwrapper-storagepool-filesystem-samba-enable-additional-` + filesystem.id + `").removeClass("hidden"); + } else { + $("#validationwrapper-storagepool-filesystem-samba-enable-additional-` + filesystem.id + `").addClass("hidden"); + } + }); + + $("#btn-storagepool-filesystem-samba-enable-apply-` + filesystem.id + `").on("click", function () { + $("#spinner-storagepool-filesystem-samba-enable-` + filesystem.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let samba = { + share: { + additional: ($("#switch-storagepool-filesystem-samba-enable-additional-` + filesystem.id + ` input").prop("checked") ? $("#textarea-storagepool-filesystem-samba-enable-additional-` + filesystem.id + `").val().split("\\n").filter(v => v) : []), + administrative: false, + browseable: true, + comment: "", + guestok: false, + name: "", + readonly: false + } + }; + let validation = { + comment: false, + name: false, + additional: false + }; + + if ($("#input-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").val().length == 0) { + $("#helpblock-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Share name can not be empty."); + + validation.name = false; + } else if (/^[a-zA-Z0-9-_.@%+!#$^,(){}~ ]*$/.test($("#input-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").val()) == false) { + $("#helpblock-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Share name contains invalid characters."); + + validation.name = false; + } else if (/^[ ]/.test($("#input-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Share name can not begin with whitespace ( )."); + + validation.name = false; + } else if (/[ ]$/.test($("#input-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Share name can not end with whitespace ( )."); + + validation.name = false; + } else { + $("#validationwrapper-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").addClass("hidden").text(""); + + validation.name = true; + } + + if (/^[ -~]*$/.test($("#input-storagepool-filesystem-samba-enable-comment-` + filesystem.id + `").val()) == false) { + $("#helpblock-storagepool-filesystem-samba-enable-comment-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Comment contains invalid characters."); + + validation.comment = false; + } else if (/^[ ]/.test($("#input-storagepool-filesystem-samba-enable-comment-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-samba-enable-comment-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Comment can not begin with whitespace ( )."); + + validation.comment = false; + } else if (/[ ]$/.test($("#input-storagepool-filesystem-samba-enable-comment-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-samba-enable-comment-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Comment can not end with whitespace ( )."); + + validation.comment = false; + } else { + $("#validationwrapper-storagepool-filesystem-samba-enable-comment-` + filesystem.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystem-samba-enable-comment-` + filesystem.id + `").addClass("hidden").text(""); + + validation.comment = true; + } + + if (samba.share.additional.length > 0) { + samba.share.additional.forEach((_value, _index) => { + if (/[\\[\\]]/g.test(_value)) { //Do not allow section names + $("#helpblock-storagepool-filesystem-samba-enable-additional-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Additional must not contain brackets. Line: " + (_index + 1)); + + validation.additional = false; + return; + } else if (/^[#]/.test(_value) == false && /[=]/.test(_value) && /(path|comment|browseable|read only|guest ok).*=/gi.test(_value)) { + $("#helpblock-storagepool-filesystem-samba-enable-additional-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Additional must not contain duplicate properties. Line: " + (_index + 1)); + + validation.additional = false; + return; + } else if (/[#=]/.test(_value) == false) { + $("#helpblock-storagepool-filesystem-samba-enable-additional-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Additional must contain comments or properties only. Line: " + (_index + 1)); + + validation.additional = false; + return; + } else if (_index == (samba.share.additional.length -1)) { + $("#validationwrapper-storagepool-filesystem-samba-enable-additional-` + filesystem.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystem-samba-enable-additional-` + filesystem.id + `").removeClass("has-error").addClass("hidden").text(""); + + validation.additional = true; + } + }); + } else { + validation.additional = true; + } + + if (!validation.name || !validation.comment || !validation.additional) { + if (!validation.name) { + $("#validationwrapper-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").addClass("has-error"); + $("#input-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").focus(); + } + if (!validation.comment) { + $("#validationwrapper-storagepool-filesystem-samba-enable-comment-` + filesystem.id + `").addClass("has-error"); + $("#input-storagepool-filesystem-samba-enable-comment-` + filesystem.id + `").focus(); + } + if (!validation.additional) { + $("#validationwrapper-storagepool-filesystem-samba-enable-additional-` + filesystem.id + `").addClass("has-error"); + $("#textarea-storagepool-filesystem-samba-enable-additional-` + filesystem.id + `").focus(); + } + + $("#spinner-storagepool-filesystem-samba-enable-` + filesystem.id + `").addClass("hidden"); + $(this).prop("disabled", false); + } + + if (validation.name && validation.comment && validation.additional) { + samba.share.administrative = $("#switch-storagepool-filesystem-samba-enable-administrative-` + filesystem.id + ` input").prop("checked"); + samba.share.browseable = $("#switch-storagepool-filesystem-samba-enable-browseable-` + filesystem.id + ` input").prop("checked"); + samba.share.comment = $("#input-storagepool-filesystem-samba-enable-comment-` + filesystem.id + `").val(); + samba.share.guestok = $("#switch-storagepool-filesystem-samba-enable-guestok-` + filesystem.id + ` input").prop("checked"); + samba.share.name = $("#input-storagepool-filesystem-samba-enable-name-` + filesystem.id + `").val(); + samba.share.readonly = $("#switch-storagepool-filesystem-samba-enable-readonly-` + filesystem.id + ` input").prop("checked"); + + FnSambaShareEnable({ name: "` + pool.name + `", id: "` + pool.id + `", readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", mounted: ` + filesystem.mounted + `, mountpoint: "` + filesystem.mountpoint + `" }, { share: { additional: samba.share.additional, administrative: samba.share.administrative, browseable: samba.share.browseable, guestok: samba.share.guestok, name: samba.share.name, comment: samba.share.comment, readonly: samba.share.readonly, temporary: ` + (pool.altroot || pool.readonly ? true : false) + ` } }, { silent: false }); + } + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalFileSystemSnapshotCreate(pool = { name, id }, filesystem = { name, id }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-filesystem-snapshot-create-` + filesystem.id + `").on("click", function () { + FnModalFileSystemSnapshotCreateContent({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `" }, { id: $("#modal-storagepool-filesystem-snapshot-create-` + filesystem.id + `") }); + }); + \x3C/script> + `; + + $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); +} + +function FnModalFileSystemSnapshotCreateContent(pool = { name, id }, filesystem = { name, id }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#switch-storagepool-filesystem-snapshot-create-customname-` + filesystem.id + ` input").on("click", function () { + $("#validationwrapper-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").removeClass("has-error").addClass("hidden").text(""); + + if ($(this).prop("checked")) { + $("#input-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").val("").prop("readonly", false).focus(); + } else { + $("#input-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").val("YYYY.MM.DD-HH.MM.SS").prop("readonly", true);; + } + }); + + $("#btn-storagepool-filesystem-snapshot-create-apply-` + filesystem.id + `").on("click", function () { + $("#spinner-storagepool-filesystem-snapshot-create-` + filesystem.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let snapshot = { + name: "", + id: "", + recursive: false + }; + let validation = { + name: false + }; + + if ($("#input-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").val().length == 0) { + $("#helpblock-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not be empty."); + + validation.name = false; + } else if (/^[a-zA-Z0-9-_.: ]*$/.test($("#input-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").val()) == false) { + $("#helpblock-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name contains invalid characters."); + + validation.name = false; + } else if (/^[.]/.test($("#input-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a period (.)."); + + validation.name = false; + } else if (/^[_]/.test($("#input-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with an underscore (_)."); + + validation.name = false; + } else if (/^[-]/.test($("#input-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a hypen (-)."); + + validation.name = false; + } else if (/^[:]/.test($("#input-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with an colon (:)."); + + validation.name = false; + } else if (/^[ ]/.test($("#input-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with whitespace ( )."); + + validation.name = false; + } else if (/[ ]$/.test($("#input-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").val())) { + $("#helpblock-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Name can not end with whitespace ( )."); + + validation.name = false; + } else { + $("#validationwrapper-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").addClass("hidden").text(""); + + validation.name = true; + } + + if (!validation.name) { + $("#validationwrapper-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").addClass("has-error"); + $("#input-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").focus(); + + $("#spinner-storagepool-filesystem-snapshot-create-` + filesystem.id + `").addClass("hidden"); + $(this).prop("disabled", false); + } + + if (validation.name) { + snapshot.name = "` + filesystem.name + `" + "@" + $("#input-storagepool-filesystem-snapshot-create-name-` + filesystem.id + `").val(); + snapshot.id = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: snapshot.name, attribute: true }); + snapshot.recursive = $("#switch-storagepool-filesystem-snapshot-create-recursive-` + filesystem.id + ` input").prop("checked"); + + if ($("#switch-storagepool-filesystem-snapshot-create-customname-` + filesystem.id + ` input").prop("checked")) { + FnSnapshotCreate({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: snapshot.name, id: snapshot.id, recursive: snapshot.recursive }, { name: "storagepool-filesystem-snapshot-create", id: "` + filesystem.id + `"}); + } else { + FnSnapshotCreateDateGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: snapshot.name, id: snapshot.id, recursive: snapshot.recursive }, { name: "storagepool-filesystem-snapshot-create", id: "` + filesystem.id + `"}); + } + } + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalFileSystemUnlock(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, sharesmb: false, type }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-filesystem-unlock-` + filesystem.id + `").on("click", function () { + FnModalFileSystemUnlockContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", sharesmb: ` + filesystem.sharesmb + `, type: "` + filesystem.type + `" }, { id: $("#modal-storagepool-filesystem-unlock-` + filesystem.id + `") }); + + setTimeout(function() { + $("#input-storagepool-filesystem-unlock-passphrase-` + filesystem.id + `").focus(); + }, 600); + }); + \x3C/script> + `; + + $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); +} + +function FnModalFileSystemUnlockContent(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, sharesmb: false, type }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#switch-storagepool-filesystem-unlock-mount-` + filesystem.id + ` input").on("click", function () { + if ($(this).prop("checked")) { + $("#switch-storagepool-filesystem-unlock-overlay-` + filesystem.id + `").parent().removeClass("hidden"); + } else { + $("#switch-storagepool-filesystem-unlock-overlay-` + filesystem.id + `").parent().addClass("hidden"); + } + }); + + $("#btn-storagepool-filesystem-unlock-apply-` + filesystem.id + `").on("click", function () { + $("#spinner-storagepool-filesystem-unlock-` + filesystem.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let filesystem = { + mount: true, + passphrase: "" + }; + let samba = { + enable: false + }; + let validation = { + passphrase: false + }; + + if ($("#input-storagepool-filesystem-unlock-passphrase-` + filesystem.id + `").val().length == 0) { + $("#helpblock-storagepool-filesystem-unlock-passphrase-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Passphrase can not be empty."); + + validation.passphrase = false; + } else if ($("#input-storagepool-filesystem-unlock-passphrase-` + filesystem.id + `").val().length < 8) { + $("#helpblock-storagepool-filesystem-unlock-passphrase-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Passphrase requires a minimum of 8 characters."); + + validation.passphrase = false; + } else if (/^[a-zA-Z0-9-_. \`~!@#$%^\(\)+\\[\\]{}:',/?]*$/.test($("#input-storagepool-filesystem-unlock-passphrase-` + filesystem.id + `").val()) == false) { + $("#helpblock-storagepool-filesystem-unlock-passphrase-` + filesystem.id + `").addClass("has-error").removeClass("hidden").text("Passphrase contains invalid characters."); + + validation.passphrase = false; + } else { + $("#validationwrapper-storagepool-filesystem-unlock-passphrase-` + filesystem.id + `").removeClass("has-error"); + $("#helpblock-storagepool-filesystem-unlock-passphrase-` + filesystem.id + `").removeClass("has-error").addClass("hidden").text(""); + + validation.passphrase = true; + } + + if (!validation.passphrase) { + $("#validationwrapper-storagepool-filesystem-unlock-passphrase-` + filesystem.id + `").addClass("has-error"); + $("#input-storagepool-filesystem-unlock-passphrase-` + filesystem.id + `").focus(); + + $("#spinner-storagepool-filesystem-unlock-` + filesystem.id + `").addClass("hidden"); + $(this).prop("disabled", false); + } + + if (validation.passphrase) { + filesystem.mount = $("#switch-storagepool-filesystem-unlock-mount-` + filesystem.id + ` input").prop("checked"); + filesystem.overlay = $("#switch-storagepool-filesystem-unlock-overlay-` + filesystem.id + ` input").prop("checked"); + filesystem.passphrase = $("#input-storagepool-filesystem-unlock-passphrase-` + filesystem.id + `").val(); + + samba.enable = ` + ((pool.readonly || filesystem.sharesmb) ? false : `$("#switch-storagepool-filesystem-unlock-samba-enable-` + filesystem.id + ` input").prop("checked")`) + `; + + FnFileSystemUnlock({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", mount: filesystem.mount, overlay: filesystem.overlay, passphrase: filesystem.passphrase, type: "` + filesystem.type + `" }, { enable: samba.enable }, { name: "storagepool-filesystem-unlock", id: "` + filesystem.id + `" }, { refresh: true }); + } + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalFileSystemUnmount(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, encryptionroot, keystatus, sharesmb: false, type }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-filesystem-unmount-` + filesystem.id + `").on("click", function () { + FnModalFileSystemUnmountContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", encryptionroot: "` + filesystem.encryptionroot + `", keystatus: "` + filesystem.keystatus + `", sharesmb: ` + filesystem.sharesmb + `, type: "` + filesystem.type + `" }, { id: $("#modal-storagepool-filesystem-unmount-` + filesystem.id + `") }); + FnFileSystemsMountedGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `" }, { alert: { id: $("#div-storagepool-filesystem-unmount-warning-` + filesystem.id + `"), mount: false } }); + }); + \x3C/script> + `; + + $("#modals-storagepool-filesystem-" + pool.id).append(modal.window); +} + +function FnModalFileSystemUnmountContent(pool = { name, id, altroot: false, readonly: false }, filesystem = { name, id, encryptionroot, keystatus, sharesmb: false, type }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-filesystem-unmount-apply-` + filesystem.id + `").on("click", function () { + $("#spinner-storagepool-filesystem-unmount-` + filesystem.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let filesystem = { + force: $("#switch-storagepool-filesystem-unmount-force-` + filesystem.id + ` input").prop("checked"), + lock: ` + (filesystem.keystatus == "available" && filesystem.encryptionroot == filesystem.name ? `$("#switch-storagepool-filesystem-unmount-lock-` + filesystem.id + ` input").prop("checked")` : false) + ` + }; + let samba = { + disable: ` + ((!pool.readonly && filesystem.sharesmb) ? `$("#switch-storagepool-filesystem-unmount-samba-disable-` + filesystem.id + ` input").prop("checked")` : false) + `, + restart: $("#switch-storagepool-filesystem-unmount-samba-restart-` + filesystem.id + ` input").prop("checked") + }; + + FnFileSystemUnmount({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + filesystem.name + `", id: "` + filesystem.id + `", force: filesystem.force, lock: filesystem.lock, type: "` + filesystem.type + `" }, { disable: samba.disable, restart: samba.restart }); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +//#endregion + +//#region Modal Snapshots + +function FnModalSnaphshotsCreate(pool = { name, id }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-snapshots-create-` + pool.id + `").on("click", function () { + FnModalSnaphshotsCreateContent({ name: "` + pool.name + `", id: "` + pool.id + `" }, { id: $("#modal-storagepool-snapshots-create-` + pool.id + `") }); + FnFileSystemsNamesGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { existing: { name: null, clone: false, encryption: false, encryptionroot: null, origin: null }, override: true }, { dropdown: { id: $("#dropdown-storagepool-snapshots-create-filesystem-` + pool.id + `"), selected: "` + pool.name + `" } }); + }); + \x3C/script> + `; + + $("#modals-storagepool-snapshots-" + pool.id).append(modal.window); +} + +function FnModalSnaphshotsCreateContent(pool = { name, id }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#switch-storagepool-snapshots-create-customname-` + pool.id + ` input").on("click", function () { + $("#validationwrapper-storagepool-snapshots-create-name-` + pool.id + `").removeClass("has-error"); + $("#helpblock-storagepool-snapshots-create-name-` + pool.id + `").removeClass("has-error").addClass("hidden").text(""); + + if ($(this).prop("checked")) { + $("#input-storagepool-snapshots-create-name-` + pool.id + `").val("").prop("readonly", false).focus(); + } else { + $("#input-storagepool-snapshots-create-name-` + pool.id + `").val("YYYY.MM.DD-HH.MM.SS").prop("readonly", true);; + } + }); + + $("#btn-storagepool-snapshots-create-apply-` + pool.id + `").on("click", function () { + $("#spinner-storagepool-snapshots-create-` + pool.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let snapshot = { + name: "", + id: "", + recursive: false + }; + let validation = { + name: false + }; + + if ($("#input-storagepool-snapshots-create-name-` + pool.id + `").val().length == 0) { + $("#helpblock-storagepool-snapshots-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not be empty."); + + validation.name = false; + } else if (/^[a-zA-Z0-9-_.: ]*$/.test($("#input-storagepool-snapshots-create-name-` + pool.id + `").val()) == false) { + $("#helpblock-storagepool-snapshots-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name contains invalid characters."); + + validation.name = false; + } else if (/^[.]/.test($("#input-storagepool-snapshots-create-name-` + pool.id + `").val())) { + $("#helpblock-storagepool-snapshots-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a period (.)."); + + validation.name = false; + } else if (/^[_]/.test($("#input-storagepool-snapshots-create-name-` + pool.id + `").val())) { + $("#helpblock-storagepool-snapshots-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with an underscore (_)."); + + validation.name = false; + } else if (/^[-]/.test($("#input-storagepool-snapshots-create-name-` + pool.id + `").val())) { + $("#helpblock-storagepool-snapshots-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a hypen (-)."); + + validation.name = false; + } else if (/^[:]/.test($("#input-storagepool-snapshots-create-name-` + pool.id + `").val())) { + $("#helpblock-storagepool-snapshots-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with an colon (:)."); + + validation.name = false; + } else if (/^[ ]/.test($("#input-storagepool-snapshots-create-name-` + pool.id + `").val())) { + $("#helpblock-storagepool-snapshots-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with whitespace ( )."); + + validation.name = false; + } else if (/[ ]$/.test($("#input-storagepool-snapshots-create-name-` + pool.id + `").val())) { + $("#helpblock-storagepool-snapshots-create-name-` + pool.id + `").addClass("has-error").removeClass("hidden").text("Name can not end with whitespace ( )."); + + validation.name = false; + } else { + $("#validationwrapper-storagepool-snapshots-create-name-` + pool.id + `").removeClass("has-error"); + $("#helpblock-storagepool-snapshots-create-name-` + pool.id + `").addClass("hidden").text(""); + + validation.name = true; + } + + if (!validation.name) { + $("#validationwrapper-storagepool-snapshots-create-name-` + pool.id + `").addClass("has-error"); + $("#input-storagepool-snapshots-create-name-` + pool.id + `").focus(); + + $("#spinner-storagepool-snapshots-create-` + pool.id + `").addClass("hidden"); + $(this).prop("disabled", false); + } + + if (validation.name) { + snapshot.name = $("#btnspan-storagepool-snapshots-create-filesystem-` + pool.id + `").attr("data-field-value") + "@" + $("#input-storagepool-snapshots-create-name-` + pool.id + `").val(); + snapshot.id = FnGenerateId({ at: true, colon: true, forwardslash: true, period: true, underscore: true, whitespace: true }, { name: snapshot.name, attribute: true }); + snapshot.recursive = $("#switch-storagepool-snapshots-create-recursive-` + pool.id + ` input").prop("checked"); + + if ($("#switch-storagepool-snapshots-create-customname-` + pool.id + ` input").prop("checked")) { + FnSnapshotCreate({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: snapshot.name, id: snapshot.id, recursive: snapshot.recursive }, { name: "storagepool-snapshots-create", id: "` + pool.id + `"}); + } else { + FnSnapshotCreateDateGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: snapshot.name, id: snapshot.id, recursive: snapshot.recursive }, { name: "storagepool-snapshots-create", id: "` + pool.id + `"}); + } + } + }); + + $("#dropdown-storagepool-snapshots-create-filesystem-` + pool.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-snapshots-create-filesystem-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +//#endregion + +//#region Modal Snapshot + +function FnModalSnapshotClone(pool = { name, id, altroot: false }, snapshot = { name, id, encryption: false, encryptionroot }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-snapshot-clone-` + snapshot.id + `").on("click", function () { + FnModalSnapshotCloneContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + ` }, { name: "` + snapshot.name + `", id: "` + snapshot.id + `", encryption: ` + snapshot.encryption + ` }, { id: $("#modal-storagepool-snapshot-clone-` + snapshot.id + `") }); + FnFileSystemsNamesGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { existing: { name: null, clone: false, encryption: ` + snapshot.encryption + `, encryptionroot: "` + snapshot.encryptionroot + `", origin: null }, override: false }, { dropdown: { id: $("#dropdown-storagepool-snapshot-clone-parentfilesystem-` + snapshot.id + `"), selected: "` + snapshot.name.replace(/^(.*)\@.*$/, "$1") + `" } }); + + setTimeout(function() { + $("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").focus(); + }, 600); + }); + \x3C/script> + `; + + $("#modals-storagepool-snapshot-" + pool.id).append(modal.window); +} + +function FnModalSnapshotCloneContent(pool = { name, id, altroot: false }, snapshot = { name, id, encryption: false }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-snapshot-clone-apply-` + snapshot.id + `").on("click", function () { + $("#spinner-storagepool-snapshot-clone-` + snapshot.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let snapshot = { + clone: { + createnonexistparents: false, + name: "", + parent: "" + } + }; + let validation = { + name: false + }; + + if ($("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").val().length == 0) { + $("#helpblock-storagepool-snapshot-clone-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not be empty."); + + validation.name = false; + } else if (/^[a-zA-Z0-9-_.:/ ]*$/.test($("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").val()) == false) { + $("#helpblock-storagepool-snapshot-clone-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name contains invalid characters."); + + validation.name = false; + } else if (/^[.]/.test($("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").val())) { + $("#helpblock-storagepool-snapshot-clone-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a period (.)."); + + validation.name = false; + } else if (/^[_]/.test($("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").val())) { + $("#helpblock-storagepool-snapshot-clone-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with an underscore (_)."); + + validation.name = false; + } else if (/^[-]/.test($("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").val())) { + $("#helpblock-storagepool-snapshot-clone-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a hypen (-)."); + + validation.name = false; + } else if (/^[:]/.test($("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").val())) { + $("#helpblock-storagepool-snapshot-clone-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with an colon (:)."); + + validation.name = false; + } else if (/^[/]/.test($("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").val())) { + $("#helpblock-storagepool-snapshot-clone-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a forward slash (/)."); + + validation.name = false; + } else if (/[/]$/.test($("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").val())) { + $("#helpblock-storagepool-snapshot-clone-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not end with a forward slash (/)."); + + validation.name = false; + } else if (/^ |\\/ /.test($("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").val())) { + $("#helpblock-storagepool-snapshot-clone-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with whitespace ( )."); + + validation.name = false; + } else if (/ $| \\//.test($("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").val())) { + $("#helpblock-storagepool-snapshot-clone-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not end with whitespace ( )."); + + validation.name = false; + } else { + $("#validationwrapper-storagepool-snapshot-clone-name-` + snapshot.id + `").removeClass("has-error"); + $("#helpblock-storagepool-snapshot-clone-name-` + snapshot.id + `").removeClass("has-error").addClass("hidden").text(""); + + validation.name = true; + } + + if (!validation.name) { + $("#validationwrapper-storagepool-snapshot-clone-name-` + snapshot.id + `").addClass("has-error"); + $("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").focus(); + + $("#spinner-storagepool-snapshot-clone-` + snapshot.id + `").addClass("hidden"); + $(this).prop("disabled", false); + } + + if (validation.name) { + snapshot.clone.createnonexistparents = $("#switch-storagepool-snapshot-clone-createnonexistparents-` + snapshot.id + ` input").prop("checked"); + snapshot.clone.name = $("#btnspan-storagepool-snapshot-clone-parentfilesystem-` + snapshot.id + `").attr("data-field-value") + "/" + $("#input-storagepool-snapshot-clone-name-` + snapshot.id + `").val(); + snapshot.clone.parent = $("#btnspan-storagepool-snapshot-clone-parentfilesystem-` + snapshot.id + `").attr("data-field-value"); + + FnSnapshotClone({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + ` }, { name: "` + snapshot.name + `", id: "` + snapshot.id + `", clone: { name: snapshot.clone.name, createnonexistparents: snapshot.clone.createnonexistparents, parent: snapshot.clone.parent } }); + } + }); + + $("#dropdown-storagepool-snapshot-clone-parentfilesystem-` + snapshot.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-snapshot-clone-parentfilesystem-` + snapshot.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalSnapshotDestroy(pool = { name, id, altroot: false, readonly: false }, snapshot = { name, id, clones: [] }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-snapshot-destroy-` + snapshot.id + `").on("click", function () { + FnModalSnapshotDestroyContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + snapshot.name + `", id: "` + snapshot.id + `", clones: [` + (snapshot.clones.length > 0 ? `"` + snapshot.clones.join(`","`) + `"` : ``) + `] }, { id: $("#modal-storagepool-snapshot-destroy-` + snapshot.id + `") }); + ` + (snapshot.clones.length > 0 ? `FnSnapshotChildFileSystemsGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + snapshot.name + `", id: "` + snapshot.id + `" }, { id: ` + (snapshot.clones.length > 0 ? `["` + snapshot.clones.join(`", "`) + `"]` : `[]`) + ` }, { name: "storagepool-snapshot-destroy", id: "` + snapshot.id + `" });` : ``) + ` + FnSnapshotChildSnapshotsGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + snapshot.name + `", id: "` + snapshot.id + `", exclude: false }, { id: ` + (snapshot.clones.length > 0 ? `["` + snapshot.clones.join(`", "`) + `"]` : `[]`) + ` }, { name: "storagepool-snapshot-destroy", id: "` + snapshot.id + `" }); + }); + \x3C/script> + `; + + $("#modals-storagepool-snapshot-" + pool.id).append(modal.window); +} + +function FnModalSnapshotDestroyContent(pool = { name, id, altroot: false, readonly: false }, snapshot = { name, id, clones: [] }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#switch-storagepool-snapshot-destroy-recursive-` + snapshot.id + ` input").on("click", function () { + if ($(this).prop("checked") && $("#switch-storagepool-snapshot-destroy-recursiveall-` + snapshot.id + ` input").prop("checked")) { + $("#switch-storagepool-snapshot-destroy-recursiveall-` + snapshot.id + ` input").click(); + } + + $("#panel-storagepool-snapshot-destroy-child-filesystems-` + snapshot.id + `").addClass("hidden"); + $("#panel-storagepool-snapshot-destroy-child-filesystems-` + snapshot.id + ` .collapse").collapse("hide"); + $("#panel-storagepool-snapshot-destroy-child-snapshotswithclones-` + snapshot.id + `").addClass("hidden"); + $("#panel-storagepool-snapshot-destroy-child-snapshotswithclones-` + snapshot.id + ` .collapse").collapse("hide"); + + if ($(this).prop("checked") && $("#panelgroup-storagepool-snapshot-destroy-` + snapshot.id + `").attr("data-snapshot-child-snapshots") > 0) { + $("#panel-storagepool-snapshot-destroy-child-snapshots-` + snapshot.id + `").removeClass("hidden"); + } else { + $("#panel-storagepool-snapshot-destroy-child-snapshots-` + snapshot.id + `").addClass("hidden"); + $("#panel-storagepool-snapshot-destroy-child-snapshots-` + snapshot.id + ` .collapse").collapse("hide"); + } + if ($(this).prop("checked") && $("#panelgroup-storagepool-snapshot-destroy-` + snapshot.id + `").attr("data-snapshot-child-snapshots") > 0) { + $("#panelgroup-storagepool-snapshot-destroy-` + snapshot.id + `").addClass("modal-ct-bodytext-1"); + } else { + $("#panelgroup-storagepool-snapshot-destroy-` + snapshot.id + `").removeClass("modal-ct-bodytext-1"); + } + }); + + $("#switch-storagepool-snapshot-destroy-recursiveall-` + snapshot.id + ` input").on("click", function () { + if ($(this).prop("checked") && $("#switch-storagepool-snapshot-destroy-recursive-` + snapshot.id + ` input").prop("checked")) { + $("#switch-storagepool-snapshot-destroy-recursive-` + snapshot.id + ` input").click(); + } + + $("#panel-storagepool-snapshot-destroy-child-filesystems-` + snapshot.id + `").addClass("hidden"); + $("#panel-storagepool-snapshot-destroy-child-filesystems-` + snapshot.id + ` .collapse").collapse("hide"); + $("#panel-storagepool-snapshot-destroy-child-snapshots-` + snapshot.id + `").addClass("hidden"); + $("#panel-storagepool-snapshot-destroy-child-snapshots-` + snapshot.id + ` .collapse").collapse("hide"); + + if ($(this).prop("checked") && $("#panelgroup-storagepool-snapshot-destroy-` + snapshot.id + `").attr("data-snapshot-child-filesystems") > 0) { + $("#panel-storagepool-snapshot-destroy-child-filesystems-` + snapshot.id + `").removeClass("hidden"); + } else { + $("#panel-storagepool-snapshot-destroy-child-filesystems-` + snapshot.id + `").addClass("hidden"); + $("#panel-storagepool-snapshot-destroy-child-filesystems-` + snapshot.id + ` .collapse").collapse("hide"); + } + if ($(this).prop("checked") && $("#panelgroup-storagepool-snapshot-destroy-` + snapshot.id + `").attr("data-snapshot-child-snapshotswithclones") > 0) { + $("#panel-storagepool-snapshot-destroy-child-snapshotswithclones-` + snapshot.id + `").removeClass("hidden"); + } else { + $("#panel-storagepool-snapshot-destroy-child-snapshotswithclones-` + snapshot.id + `").addClass("hidden"); + $("#panel-storagepool-snapshot-destroy-child-snapshotswithclones-` + snapshot.id + ` .collapse").collapse("hide"); + } + if ($(this).prop("checked") && ($("#panelgroup-storagepool-snapshot-destroy-` + snapshot.id + `").attr("data-snapshot-child-snapshotswithclones") > 0 || $("#panelgroup-storagepool-snapshot-destroy-` + snapshot.id + `").attr("data-snapshot-child-snapshotswithclones") > 0)) { + $("#panelgroup-storagepool-snapshot-destroy-` + snapshot.id + `").addClass("modal-ct-bodytext-1"); + } else { + $("#panelgroup-storagepool-snapshot-destroy-` + snapshot.id + `").removeClass("modal-ct-bodytext-1"); + } + }); + + $("#btn-storagepool-snapshot-destroy-apply-` + snapshot.id + `").on("click", function () { + $("#spinner-storagepool-snapshot-destroy-` + snapshot.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let snapshot = { + recursive: $("#switch-storagepool-snapshot-destroy-recursive-` + snapshot.id + ` input").prop("checked"), + recursiveall: $("#switch-storagepool-snapshot-destroy-recursiveall-` + snapshot.id + ` input").prop("checked") + }; + let samba = { + restart: $("#switch-storagepool-snapshot-destroy-samba-restart-` + snapshot.id + ` input").prop("checked") + }; + + FnSnapshotDestroy({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + snapshot.name + `", id: "` + snapshot.id + `", clones: ` + (snapshot.clones.length > 0 ? `["` + snapshot.clones.join(`", "`) + `"]` : `[]`) + `, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { restart: samba.restart }); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalSnapshotRename(pool = { name, id }, snapshot = { name, id, creation }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-snapshot-rename-` + snapshot.id + `").on("click", function () { + FnModalSnapshotRenameContent({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + snapshot.name + `", id: "` + snapshot.id + `", creation: "` + snapshot.creation + `" }, { id: $("#modal-storagepool-snapshot-rename-` + snapshot.id + `") }); + + setTimeout(function() { + $("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").focus(); + }, 600); + }); + \x3C/script> + `; + + $("#modals-storagepool-snapshot-" + pool.id).append(modal.window); +} + +function FnModalSnapshotRenameContent(pool = { name, id }, snapshot = { name, id, creation }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#switch-storagepool-snapshot-rename-creationdate-` + snapshot.id + ` input").on("click", function () { + if ($(this).prop("checked")) { + $("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").val("` + FnDateTimeSnapshot({ date: new Date(snapshot.creation * 1000) }) + `").prop("readonly", true); + } else { + $("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").val("` + snapshot.name.replace(/^.*\@(.*)$/, "$1") + `").prop("readonly", false).focus(); + } + }); + + $("#btn-storagepool-snapshot-rename-apply-` + snapshot.id + `").on("click", function () { + $("#spinner-storagepool-snapshot-rename-` + snapshot.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let snapshot = { + namenew: "", + recursive: false + }; + let validation = { + name: false + }; + + if ("` + snapshot.name.replace(/^(.*)\@.*$/, "$1") + `" + "@" + $("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").val() == "` + snapshot.name + `") { + $("#helpblock-storagepool-snapshot-rename-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name must be different."); + + validation.name = false; + } else if ($("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").val().length == 0) { + $("#helpblock-storagepool-snapshot-rename-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not be empty."); + + validation.name = false; + } else if (/^[a-zA-Z0-9-_.: ]*$/.test($("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").val()) == false) { + $("#helpblock-storagepool-snapshot-rename-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name contains invalid characters."); + + validation.name = false; + } else if (/^[.]/.test($("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").val())) { + $("#helpblock-storagepool-snapshot-rename-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a period (.)."); + + validation.name = false; + } else if (/^[_]/.test($("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").val())) { + $("#helpblock-storagepool-snapshot-rename-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with an underscore (_)."); + + validation.name = false; + } else if (/^[-]/.test($("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").val())) { + $("#helpblock-storagepool-snapshot-rename-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with a hypen (-)."); + + validation.name = false; + } else if (/^[:]/.test($("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").val())) { + $("#helpblock-storagepool-snapshot-rename-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with an colon (:)."); + + validation.name = false; + } else if (/^[ ]/.test($("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").val())) { + $("#helpblock-storagepool-snapshot-rename-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not begin with whitespace ( )."); + + validation.name = false; + } else if (/[ ]$/.test($("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").val())) { + $("#helpblock-storagepool-snapshot-rename-name-` + snapshot.id + `").addClass("has-error").removeClass("hidden").text("Name can not end with whitespace ( )."); + + validation.name = false; + } else { + $("#validationwrapper-storagepool-snapshot-rename-name-` + snapshot.id + `").removeClass("has-error"); + $("#helpblock-storagepool-snapshot-rename-name-` + snapshot.id + `").removeClass("has-error").addClass("hidden").text(""); + + validation.name = true; + } + + if (!validation.name) { + $("#validationwrapper-storagepool-snapshot-rename-name-` + snapshot.id + `").addClass("has-error"); + $("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").focus(); + + $("#spinner-storagepool-snapshot-rename-` + snapshot.id + `").addClass("hidden"); + $(this).prop("disabled", false); + } + + if (validation.name) { + snapshot.namenew = "` + snapshot.name.replace(/^(.*)\@.*$/, "$1") + `" + "@" + $("#input-storagepool-snapshot-rename-name-` + snapshot.id + `").val(); + snapshot.recursive = $("#switch-storagepool-snapshot-rename-recursive-` + snapshot.id + ` input").prop("checked"); + + FnSnapshotRename({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + snapshot.name + `", id: "` + snapshot.id + `", namenew: snapshot.namenew, recursive: snapshot.recursive }); + } + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalSnapshotRollBack(pool = { name, id, altroot: false, readonly: false }, snapshot = { name, id, creation }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-snapshot-rollback-` + snapshot.id + `").on("click", function () { + FnModalSnapshotRollBackContent({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + snapshot.name + `", id: "` + snapshot.id + `", creation: "` + snapshot.creation + `" }, { id: $("#modal-storagepool-snapshot-rollback-` + snapshot.id + `") }); + FnSnapshotRollBackSnapshotsGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "` + snapshot.name + `", id: "` + snapshot.id + `", creation: "` + snapshot.creation + `" }, { name: "storagepool-snapshot-rollback", id: "` + snapshot.id + `" }); + }); + \x3C/script> + `; + + $("#modals-storagepool-snapshot-" + pool.id).append(modal.window); +} + +function FnModalSnapshotRollBackContent(pool = { name, id, altroot: false, readonly: false }, snapshot = { name, id, creation }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#switch-storagepool-snapshot-rollback-recursive-` + snapshot.id + ` input").on("click", function () { + if ($(this).prop("checked") && $("#switch-storagepool-snapshot-rollback-recursiveall-` + snapshot.id + ` input").prop("checked")) { + $("#switch-storagepool-snapshot-rollback-recursiveall-` + snapshot.id + ` input").click(); + } + + $("#panel-storagepool-snapshot-rollback-child-filesystems-` + snapshot.id + `").addClass("hidden"); + $("#panel-storagepool-snapshot-rollback-child-filesystems-` + snapshot.id + ` .collapse").collapse("hide"); + $("#panel-storagepool-snapshot-rollback-child-snapshotswithclones-` + snapshot.id + `").addClass("hidden"); + $("#panel-storagepool-snapshot-rollback-child-snapshotswithclones-` + snapshot.id + ` .collapse").collapse("hide"); + + if ($(this).prop("checked") && $("#panelgroup-storagepool-snapshot-rollback-` + snapshot.id + `").attr("data-snapshot-snapshots") > 0) { + $("#panel-storagepool-snapshot-rollback-snapshots-` + snapshot.id + `").removeClass("hidden"); + } else { + $("#panel-storagepool-snapshot-rollback-snapshots-` + snapshot.id + `").addClass("hidden"); + $("#panel-storagepool-snapshot-rollback-snapshots-` + snapshot.id + ` .collapse").collapse("hide"); + } + }); + + $("#switch-storagepool-snapshot-rollback-recursiveall-` + snapshot.id + ` input").on("click", function () { + if ($(this).prop("checked") && $("#switch-storagepool-snapshot-rollback-recursive-` + snapshot.id + ` input").prop("checked")) { + $("#switch-storagepool-snapshot-rollback-recursive-` + snapshot.id + ` input").click(); + } + + if ($(this).prop("checked")) { + $("#switch-storagepool-snapshot-rollback-force-` + snapshot.id + `").parent().removeClass("hidden"); + } else { + $("#switch-storagepool-snapshot-rollback-force-` + snapshot.id + `").parent().addClass("hidden"); + + if ($("#switch-storagepool-snapshot-rollback-force-` + snapshot.id + ` input").prop("checked")) { + $("#switch-storagepool-snapshot-rollback-force-` + snapshot.id + ` input").click(); + } + } + + $("#panel-storagepool-snapshot-rollback-child-filesystems-` + snapshot.id + `").addClass("hidden"); + $("#panel-storagepool-snapshot-rollback-child-filesystems-` + snapshot.id + ` .collapse").collapse("hide"); + $("#panel-storagepool-snapshot-rollback-snapshots-` + snapshot.id + `").addClass("hidden"); + $("#panel-storagepool-snapshot-rollback-snapshots-` + snapshot.id + ` .collapse").collapse("hide"); + + if ($(this).prop("checked") && $("#panelgroup-storagepool-snapshot-rollback-` + snapshot.id + `").attr("data-snapshot-child-filesystems") > 0) { + $("#panel-storagepool-snapshot-rollback-child-filesystems-` + snapshot.id + `").removeClass("hidden"); + } else { + $("#panel-storagepool-snapshot-rollback-child-filesystems-` + snapshot.id + `").addClass("hidden"); + $("#panel-storagepool-snapshot-rollback-child-filesystems-` + snapshot.id + ` .collapse").collapse("hide"); + } + if ($(this).prop("checked") && $("#panelgroup-storagepool-snapshot-rollback-` + snapshot.id + `").attr("data-snapshot-child-snapshotswithclones") > 0) { + $("#panel-storagepool-snapshot-rollback-child-snapshotswithclones-` + snapshot.id + `").removeClass("hidden"); + } else { + $("#panel-storagepool-snapshot-rollback-child-snapshotswithclones-` + snapshot.id + `").addClass("hidden"); + $("#panel-storagepool-snapshot-rollback-child-snapshotswithclones-` + snapshot.id + ` .collapse").collapse("hide"); + } + }); + + $("#btn-storagepool-snapshot-rollback-apply-` + snapshot.id + `").on("click", function () { + $("#spinner-storagepool-snapshot-rollback-` + snapshot.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let snapshot = { + force: ($("#switch-storagepool-snapshot-rollback-recursiveall-` + snapshot.id + ` input").prop("checked") ? $("#switch-storagepool-snapshot-rollback-force-` + snapshot.id + ` input").prop("checked") : false), + recursive: $("#switch-storagepool-snapshot-rollback-recursive-` + snapshot.id + ` input").prop("checked"), + recursiveall: $("#switch-storagepool-snapshot-rollback-recursiveall-` + snapshot.id + ` input").prop("checked") + }; + let samba = { + restart: $("#switch-storagepool-snapshot-rollback-samba-restart-` + snapshot.id + ` input").prop("checked") + }; + + FnSnapshotRollBack({ name: "` + pool.name + `", id: "` + pool.id + `", altroot: ` + pool.altroot + `, readonly: ` + pool.readonly + ` }, { name: "` + snapshot.name + `", id: "` + snapshot.id + `", creation: "` + snapshot.creation + `", force: snapshot.force, recursive: snapshot.recursive, recursiveall: snapshot.recursiveall }, { restart: samba.restart }); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +//#endregion + +//#region Modal Status + +function FnModalStatusDiskAttach(pool = { name, id, status: { config: { items: { index: 0 }, tier: { name, dedup: false, logs: false, special: false } } } }, virtualdevice = { id, disk: true }) { + let modal = { + tiername: (pool.status.config.tier.dedup ? "Dedup" : (pool.status.config.tier.logs ? "Log" : (pool.status.config.tier.special ? "Special" : pool.status.config.tier.name))), + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-disk-attach-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); + FnModalStatusDiskAttachContent({ name: "` + pool.name + `", id: "` + pool.id + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: "` + virtualdevice.id + `" , disk: ` + virtualdevice.disk + ` }, { id: $("#modal-storagepool-status-disk-attach-` + pool.status.config.items.index + `-` + pool.id + `"), tiername: "` + modal.tiername + `" }); + FnDisksAvailableGet({ name: "storagepool-status-disk-attach-disks", id: "` + pool.status.config.items.index + `-` + pool.id + `", default: true }); + }); + \x3C/script> + `; + + $("#modals-storagepool-status-" + pool.id).append(modal.window); +} + +function FnModalStatusDiskAttachContent(pool = { name, id, status: { config: { items: { index: 0 } } } }, virtualdevice = { id, disk: true }, modal = { id, tiername }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#switch-storagepool-status-disk-attach-disks-wwn-` + pool.status.config.items.index + `-` + pool.id + ` input").on("click", function () { + $("#btnspan-storagepool-status-disk-attach-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").text("Block Device"); + $("#dropdown-storagepool-status-disk-attach-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + ` li").siblings().removeClass("active"); + $("#dropdown-storagepool-status-disk-attach-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + ` li[value='blockdevice']").addClass("active"); + $("#helpblock-storagepool-status-disk-attach-disks-identifierwarning-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden").text(""); + ` + (zfsmanager.zfs.warnings.nvmevdev ? `$("#helpblock-storagepool-status-disk-attach-disks-identifierwarningzfs-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden");` : ``) + ` + + let disk = { + identifier: ($(this).prop("checked") ? "wwn" : "blockdevice"), + identifiertext: ($(this).prop("checked") ? "WWN" : "Block Device") + }; + + if ($(this).prop("checked")) { + $("#controllabel-storagepool-status-disk-attach-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden"); + $("#validationwrapper-storagepool-status-disk-attach-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden"); + } else { + $("#controllabel-storagepool-status-disk-attach-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + $("#validationwrapper-storagepool-status-disk-attach-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + } + + $("#listgroup-storagepool-status-disk-attach-disks-` + pool.status.config.items.index + `-` + pool.id + ` input[name='checkbox-storagepool-status-disk-attach-disks-` + pool.status.config.items.index + `-` + pool.id + `']").map(function () { + if ($(this).attr("data-disk-id-" + disk.identifier)) { + $(this).next().find(".select-ct-disk-row-id").text((disk.identifier == "blockdevice" ? "/dev/" : "") + $(this).attr("data-disk-id-" + disk.identifier)); + $(this).attr("data-disk-name", $(this).attr("data-disk-id-" + disk.identifier)); + } else { + $(this).next().find(".select-ct-disk-row-id").text("/dev/" + $(this).attr("data-disk-id-blockdevice")); + $(this).attr("data-disk-name", $(this).attr("data-disk-id-blockdevice")); + $("#helpblock-storagepool-status-disk-attach-disks-identifierwarning-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One or more disks is missing a " + disk.identifiertext + " identifier."); + } + }); + }); + + $("#btn-storagepool-status-disk-attach-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + $("#spinner-storagepool-status-disk-attach-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let disk = { + idnew: [] + }; + let modal = { + name: "", + id: "" + }; + let pool = { + force: false + }; + let validation = { + disks: false + }; + + $("#listgroup-storagepool-status-disk-attach-disks-` + pool.status.config.items.index + `-` + pool.id + ` input[name='checkbox-storagepool-status-disk-attach-disks-` + pool.status.config.items.index + `-` + pool.id + `']:checked").map(function () { + disk.idnew.push($(this).attr("data-disk-name")); + }); + + if (disk.idnew.length != 1) { + $("#helpblock-storagepool-status-disk-attach-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One disk is needed."); + + validation.disks = false; + } else { + $("#validationwrapper-storagepool-status-disk-attach-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("has-error"); + $("#helpblock-storagepool-status-disk-attach-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text(""); + + validation.disks = true; + } + + if (!validation.disks) { + $("#validationwrapper-storagepool-status-disk-attach-disks-` + pool.status.config.items.index + `-` + pool.id + `").addClass("has-error"); + + $("#spinner-storagepool-status-disk-attach-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden"); + $(this).prop("disabled", false); + } + + if (validation.disks) { + modal.name = "storagepool-status-disk-attach"; + modal.id = "` + pool.status.config.items.index + `-` + pool.id + `"; + + pool.force = $("#switch-storagepool-status-disk-attach-force-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked"); + + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolDiskAttach({ name: "` + pool.name + `", id: "` + pool.id + `", force: pool.force }, { id: "` + virtualdevice.id + `", disk: ` + virtualdevice.disk + ` }, { idnew: disk.idnew }, { name: modal.name, id: modal.id }); + } + }); + + $("#dropdown-storagepool-status-disk-attach-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-status-disk-attach-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + + $("#helpblock-storagepool-status-disk-attach-disks-identifierwarning-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden").text(""); + ` + (zfsmanager.zfs.warnings.nvmevdev ? `$("#helpblock-storagepool-status-disk-attach-disks-identifierwarningzfs-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden");` : ``) + ` + + let disk = { + identifier: $(this).parent().attr("value"), + identifiertext: $(this).parent().text() + }; + + $("#listgroup-storagepool-status-disk-attach-disks-` + pool.status.config.items.index + `-` + pool.id + ` input[name='checkbox-storagepool-status-disk-attach-disks-` + pool.status.config.items.index + `-` + pool.id + `']").map(function () { + if ($(this).attr("data-disk-id-" + disk.identifier)) { + $(this).next().find(".select-ct-disk-row-id").text((disk.identifier == "blockdevice" ? "/dev/" : "") + $(this).attr("data-disk-id-" + disk.identifier)); + $(this).attr("data-disk-name", $(this).attr("data-disk-id-" + disk.identifier)); + } else { + $(this).next().find(".select-ct-disk-row-id").text("/dev/" + $(this).attr("data-disk-id-blockdevice")); + $(this).attr("data-disk-name", $(this).attr("data-disk-id-blockdevice")); + $("#helpblock-storagepool-status-disk-attach-disks-identifierwarning-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One or more disks is missing a " + disk.identifiertext + " identifier."); + ` + (zfsmanager.zfs.warnings.nvmevdev ? ` if (disk.identifier == "vdev" && /^nvme/gi.test($(this).attr("data-disk-id-blockdevice"))) { $("#helpblock-storagepool-status-disk-attach-disks-identifierwarningzfs-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); } - ` : ``) + ` - } - }); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalStatusDiskClear(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-disk-clear-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); - FnModalStatusDiskClearContent({ name: "` + pool.name + `", id: "` + pool.id + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: "` + disk.id + `" }, { id: $("#modal-storagepool-status-disk-clear-` + pool.status.config.items.index + `-` + pool.id + `") }); - }); - \x3C/script> - `; - - $("#modals-storagepool-status-" + pool.id).append(modal.window); -} - -function FnModalStatusDiskClearContent(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-disk-clear-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - $("#spinner-storagepool-status-disk-clear-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let modal = { - name: "storagepool-status-disk-clear", - id: "` + pool.status.config.items.index + `-` + pool.id + `" - }; - - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolDiskClear({ name: "` + pool.name + `", id: "` + pool.id + `" }, { id: "` + disk.id + `" }, { name: modal.name, id: modal.id }); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalStatusDiskDetach(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-disk-detach-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); - FnModalStatusDiskDetachContent({ name: "` + pool.name + `", id: "` + pool.id + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: "` + disk.id + `" }, { id: $("#modal-storagepool-status-disk-detach-` + pool.status.config.items.index + `-` + pool.id + `") }); - }); - \x3C/script> - `; - - $("#modals-storagepool-status-" + pool.id).append(modal.window); -} - -function FnModalStatusDiskDetachContent(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-disk-detach-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - $("#spinner-storagepool-status-disk-detach-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let disk = { - labelclear: $("#switch-storagepool-status-disk-detach-labelclear-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked") - }; - let modal = { - name: "storagepool-status-disk-detach", - id: "` + pool.status.config.items.index + `-` + pool.id + `" - }; - - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolDiskDetach({ name: "` + pool.name + `", id: "` + pool.id + `"}, { id: "` + disk.id + `", labelclear: disk.labelclear }, { name: modal.name, id: modal.id }); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalStatusDiskOffline(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-disk-offline-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); - FnModalStatusDiskOfflineContent({ name: "` + pool.name + `", id: "` + pool.id + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: "` + disk.id + `" }, { id: $("#modal-storagepool-status-disk-offline-` + pool.status.config.items.index + `-` + pool.id + `") }); - }); - \x3C/script> - `; - - $("#modals-storagepool-status-" + pool.id).append(modal.window); -} - -function FnModalStatusDiskOfflineContent(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-disk-offline-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - $("#spinner-storagepool-status-disk-offline-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let disk = { - force: $("#switch-storagepool-status-disk-offline-force-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked"), - temporary: $("#switch-storagepool-status-disk-offline-temporary-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked") - }; - let modal = { - name: "storagepool-status-disk-offline", - id: "` + pool.status.config.items.index + `-` + pool.id + `" - }; - - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolDiskOffline({ name: "` + pool.name + `", id: "` + pool.id + `" }, { id: "` + disk.id + `", force: disk.force, temporary: disk.temporary }, { name: modal.name, id: modal.id }); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalStatusDiskOnline(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-disk-online-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); - FnModalStatusDiskOnlineContent({ name: "` + pool.name + `", id: "` + pool.id + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: "` + disk.id + `" }, { id: $("#modal-storagepool-status-disk-online-` + pool.status.config.items.index + `-` + pool.id + `") }); - }); - \x3C/script> - `; - - $("#modals-storagepool-status-" + pool.id).append(modal.window); - -} - -function FnModalStatusDiskOnlineContent(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-disk-online-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - $("#spinner-storagepool-status-disk-online-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let disk = { - expand: $("#switch-storagepool-status-disk-online-expand-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked") - }; - let modal = { - name: "storagepool-status-disk-online", - id: "` + pool.status.config.items.index + `-` + pool.id + `" - }; - let pool = { - scrub: $("#switch-storagepool-status-disk-online-scrub-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked") - }; - - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolDiskOnline({ name: "` + pool.name + `", id: "` + pool.id + `", scrub: pool.scrub }, { id: "` + disk.id + `", expand: disk.expand }, { name: modal.name, id: modal.id }); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalStatusDiskReplace(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-disk-replace-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); - FnModalStatusDiskReplaceContent({ name: "` + pool.name + `", id: "` + pool.id + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: "` + disk.id + `" }, { id: $("#modal-storagepool-status-disk-replace-` + pool.status.config.items.index + `-` + pool.id + `") }); - FnDisksAvailableGet({ name: "storagepool-status-disk-replace-disks", id: "` + pool.status.config.items.index + `-` + pool.id + `", default: true }); - }); - \x3C/script> - `; - - $("#modals-storagepool-status-" + pool.id).append(modal.window); -} - -function FnModalStatusDiskReplaceContent(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#switch-storagepool-status-disk-replace-disks-wwn-` + pool.status.config.items.index + `-` + pool.id + ` input").on("click", function () { - $("#btnspan-storagepool-status-disk-replace-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").text("Block Device"); - $("#dropdown-storagepool-status-disk-replace-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + ` li").siblings().removeClass("active"); - $("#dropdown-storagepool-status-disk-replace-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + ` li[value='blockdevice']").addClass("active"); - $("#helpblock-storagepool-status-disk-replace-disks-identifierwarning-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden").text(""); - ` + (zfsmanager.zfs.warnings.nvmevdev ? `$("#helpblock-storagepool-status-disk-replace-disks-identifierwarningzfs-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden");` : ``) + ` - - let disk = { - identifier: ($(this).prop("checked") ? "wwn" : "blockdevice"), - identifiertext: ($(this).prop("checked") ? "WWN" : "Block Device") - }; - - if ($(this).prop("checked")) { - $("#controllabel-storagepool-status-disk-replace-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden"); - $("#validationwrapper-storagepool-status-disk-replace-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden"); - } else { - $("#controllabel-storagepool-status-disk-replace-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - $("#validationwrapper-storagepool-status-disk-replace-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - } - - $("#listgroup-storagepool-status-disk-replace-disks-` + pool.status.config.items.index + `-` + pool.id + ` input[name='checkbox-storagepool-status-disk-replace-disks-` + pool.status.config.items.index + `-` + pool.id + `']").map(function () { - if ($(this).attr("data-disk-id-" + disk.identifier)) { - $(this).next().find(".select-ct-disk-row-id").text((disk.identifier == "blockdevice" ? "/dev/" : "") + $(this).attr("data-disk-id-" + disk.identifier)); - $(this).attr("data-disk-name", $(this).attr("data-disk-id-" + disk.identifier)); - } else { - $(this).next().find(".select-ct-disk-row-id").text("/dev/" + $(this).attr("data-disk-id-blockdevice")); - $(this).attr("data-disk-name", $(this).attr("data-disk-id-blockdevice")); - $("#helpblock-storagepool-status-disk-replace-disks-identifierwarning-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One or more disks is missing a " + disk.identifiertext + " identifier."); - } - }); - }); - - $("#btn-storagepool-status-disk-replace-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - $("#spinner-storagepool-status-disk-replace-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let disk = { - idnew: [] - }; - let modal = { - name: "", - id: "" - }; - let pool = { - force: false - }; - let validation = { - disks: false - }; - - $("#listgroup-storagepool-status-disk-replace-disks-` + pool.status.config.items.index + `-` + pool.id + ` input[name='checkbox-storagepool-status-disk-replace-disks-` + pool.status.config.items.index + `-` + pool.id + `']:checked").map(function () { - disk.idnew.push($(this).attr("data-disk-name")); - }); - - if (disk.idnew.length != 1) { - $("#helpblock-storagepool-status-disk-replace-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One disk is needed."); - - validation.disks = false; - } else { - $("#validationwrapper-storagepool-status-disk-replace-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("has-error"); - $("#helpblock-storagepool-status-disk-replace-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text(""); - - validation.disks = true; - } - - if (!validation.disks) { - $("#validationwrapper-storagepool-status-disk-replace-disks-` + pool.status.config.items.index + `-` + pool.id + `").addClass("has-error"); - - $("#spinner-storagepool-status-disk-replace-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden"); - $(this).prop("disabled", false); - } - - if (validation.disks) { - modal.name = "storagepool-status-disk-replace"; - modal.id = "` + pool.status.config.items.index + `-` + pool.id + `"; - - pool.force = $("#switch-storagepool-status-disk-replace-force-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked"); - - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolDiskReplace({ name: "` + pool.name + `", id: "` + pool.id + `", force: pool.force }, { id: "` + disk.id + `", idnew: disk.idnew }, { name: modal.name, id: modal.id }); - } - }); - - $("#dropdown-storagepool-status-disk-replace-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-status-disk-replace-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - - $("#helpblock-storagepool-status-disk-replace-disks-identifierwarning-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden").text(""); - ` + (zfsmanager.zfs.warnings.nvmevdev ? `$("#helpblock-storagepool-status-disk-replace-disks-identifierwarningzfs-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden");` : ``) + ` - - let disk = { - identifier: $(this).parent().attr("value"), - identifiertext: $(this).parent().text() - }; - - $("#listgroup-storagepool-status-disk-replace-disks-` + pool.status.config.items.index + `-` + pool.id + ` input[name='checkbox-storagepool-status-disk-replace-disks-` + pool.status.config.items.index + `-` + pool.id + `']").map(function () { - if ($(this).attr("data-disk-id-" + disk.identifier)) { - $(this).next().find(".select-ct-disk-row-id").text((disk.identifier == "blockdevice" ? "/dev/" : "") + $(this).attr("data-disk-id-" + disk.identifier)); - $(this).attr("data-disk-name", $(this).attr("data-disk-id-" + disk.identifier)); - } else { - $(this).next().find(".select-ct-disk-row-id").text("/dev/" + $(this).attr("data-disk-id-blockdevice")); - $(this).attr("data-disk-name", $(this).attr("data-disk-id-blockdevice")); - $("#helpblock-storagepool-status-disk-replace-disks-identifierwarning-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One or more disks is missing a " + disk.identifiertext + " identifier."); - + ` : ``) + ` + } + }); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalStatusDiskClear(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-disk-clear-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); + FnModalStatusDiskClearContent({ name: "` + pool.name + `", id: "` + pool.id + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: "` + disk.id + `" }, { id: $("#modal-storagepool-status-disk-clear-` + pool.status.config.items.index + `-` + pool.id + `") }); + }); + \x3C/script> + `; + + $("#modals-storagepool-status-" + pool.id).append(modal.window); +} + +function FnModalStatusDiskClearContent(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-disk-clear-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + $("#spinner-storagepool-status-disk-clear-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let modal = { + name: "storagepool-status-disk-clear", + id: "` + pool.status.config.items.index + `-` + pool.id + `" + }; + + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolDiskClear({ name: "` + pool.name + `", id: "` + pool.id + `" }, { id: "` + disk.id + `" }, { name: modal.name, id: modal.id }); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalStatusDiskDetach(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-disk-detach-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); + FnModalStatusDiskDetachContent({ name: "` + pool.name + `", id: "` + pool.id + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: "` + disk.id + `" }, { id: $("#modal-storagepool-status-disk-detach-` + pool.status.config.items.index + `-` + pool.id + `") }); + }); + \x3C/script> + `; + + $("#modals-storagepool-status-" + pool.id).append(modal.window); +} + +function FnModalStatusDiskDetachContent(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-disk-detach-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + $("#spinner-storagepool-status-disk-detach-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let disk = { + labelclear: $("#switch-storagepool-status-disk-detach-labelclear-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked") + }; + let modal = { + name: "storagepool-status-disk-detach", + id: "` + pool.status.config.items.index + `-` + pool.id + `" + }; + + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolDiskDetach({ name: "` + pool.name + `", id: "` + pool.id + `"}, { id: "` + disk.id + `", labelclear: disk.labelclear }, { name: modal.name, id: modal.id }); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalStatusDiskOffline(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-disk-offline-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); + FnModalStatusDiskOfflineContent({ name: "` + pool.name + `", id: "` + pool.id + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: "` + disk.id + `" }, { id: $("#modal-storagepool-status-disk-offline-` + pool.status.config.items.index + `-` + pool.id + `") }); + }); + \x3C/script> + `; + + $("#modals-storagepool-status-" + pool.id).append(modal.window); +} + +function FnModalStatusDiskOfflineContent(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-disk-offline-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + $("#spinner-storagepool-status-disk-offline-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let disk = { + force: $("#switch-storagepool-status-disk-offline-force-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked"), + temporary: $("#switch-storagepool-status-disk-offline-temporary-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked") + }; + let modal = { + name: "storagepool-status-disk-offline", + id: "` + pool.status.config.items.index + `-` + pool.id + `" + }; + + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolDiskOffline({ name: "` + pool.name + `", id: "` + pool.id + `" }, { id: "` + disk.id + `", force: disk.force, temporary: disk.temporary }, { name: modal.name, id: modal.id }); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalStatusDiskOnline(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-disk-online-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); + FnModalStatusDiskOnlineContent({ name: "` + pool.name + `", id: "` + pool.id + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: "` + disk.id + `" }, { id: $("#modal-storagepool-status-disk-online-` + pool.status.config.items.index + `-` + pool.id + `") }); + }); + \x3C/script> + `; + + $("#modals-storagepool-status-" + pool.id).append(modal.window); + +} + +function FnModalStatusDiskOnlineContent(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-disk-online-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + $("#spinner-storagepool-status-disk-online-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let disk = { + expand: $("#switch-storagepool-status-disk-online-expand-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked") + }; + let modal = { + name: "storagepool-status-disk-online", + id: "` + pool.status.config.items.index + `-` + pool.id + `" + }; + let pool = { + scrub: $("#switch-storagepool-status-disk-online-scrub-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked") + }; + + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolDiskOnline({ name: "` + pool.name + `", id: "` + pool.id + `", scrub: pool.scrub }, { id: "` + disk.id + `", expand: disk.expand }, { name: modal.name, id: modal.id }); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalStatusDiskReplace(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-disk-replace-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); + FnModalStatusDiskReplaceContent({ name: "` + pool.name + `", id: "` + pool.id + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: "` + disk.id + `" }, { id: $("#modal-storagepool-status-disk-replace-` + pool.status.config.items.index + `-` + pool.id + `") }); + FnDisksAvailableGet({ name: "storagepool-status-disk-replace-disks", id: "` + pool.status.config.items.index + `-` + pool.id + `", default: true }); + }); + \x3C/script> + `; + + $("#modals-storagepool-status-" + pool.id).append(modal.window); +} + +function FnModalStatusDiskReplaceContent(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#switch-storagepool-status-disk-replace-disks-wwn-` + pool.status.config.items.index + `-` + pool.id + ` input").on("click", function () { + $("#btnspan-storagepool-status-disk-replace-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").text("Block Device"); + $("#dropdown-storagepool-status-disk-replace-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + ` li").siblings().removeClass("active"); + $("#dropdown-storagepool-status-disk-replace-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + ` li[value='blockdevice']").addClass("active"); + $("#helpblock-storagepool-status-disk-replace-disks-identifierwarning-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden").text(""); + ` + (zfsmanager.zfs.warnings.nvmevdev ? `$("#helpblock-storagepool-status-disk-replace-disks-identifierwarningzfs-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden");` : ``) + ` + + let disk = { + identifier: ($(this).prop("checked") ? "wwn" : "blockdevice"), + identifiertext: ($(this).prop("checked") ? "WWN" : "Block Device") + }; + + if ($(this).prop("checked")) { + $("#controllabel-storagepool-status-disk-replace-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden"); + $("#validationwrapper-storagepool-status-disk-replace-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden"); + } else { + $("#controllabel-storagepool-status-disk-replace-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + $("#validationwrapper-storagepool-status-disk-replace-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + } + + $("#listgroup-storagepool-status-disk-replace-disks-` + pool.status.config.items.index + `-` + pool.id + ` input[name='checkbox-storagepool-status-disk-replace-disks-` + pool.status.config.items.index + `-` + pool.id + `']").map(function () { + if ($(this).attr("data-disk-id-" + disk.identifier)) { + $(this).next().find(".select-ct-disk-row-id").text((disk.identifier == "blockdevice" ? "/dev/" : "") + $(this).attr("data-disk-id-" + disk.identifier)); + $(this).attr("data-disk-name", $(this).attr("data-disk-id-" + disk.identifier)); + } else { + $(this).next().find(".select-ct-disk-row-id").text("/dev/" + $(this).attr("data-disk-id-blockdevice")); + $(this).attr("data-disk-name", $(this).attr("data-disk-id-blockdevice")); + $("#helpblock-storagepool-status-disk-replace-disks-identifierwarning-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One or more disks is missing a " + disk.identifiertext + " identifier."); + } + }); + }); + + $("#btn-storagepool-status-disk-replace-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + $("#spinner-storagepool-status-disk-replace-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let disk = { + idnew: [] + }; + let modal = { + name: "", + id: "" + }; + let pool = { + force: false + }; + let validation = { + disks: false + }; + + $("#listgroup-storagepool-status-disk-replace-disks-` + pool.status.config.items.index + `-` + pool.id + ` input[name='checkbox-storagepool-status-disk-replace-disks-` + pool.status.config.items.index + `-` + pool.id + `']:checked").map(function () { + disk.idnew.push($(this).attr("data-disk-name")); + }); + + if (disk.idnew.length != 1) { + $("#helpblock-storagepool-status-disk-replace-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One disk is needed."); + + validation.disks = false; + } else { + $("#validationwrapper-storagepool-status-disk-replace-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("has-error"); + $("#helpblock-storagepool-status-disk-replace-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text(""); + + validation.disks = true; + } + + if (!validation.disks) { + $("#validationwrapper-storagepool-status-disk-replace-disks-` + pool.status.config.items.index + `-` + pool.id + `").addClass("has-error"); + + $("#spinner-storagepool-status-disk-replace-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden"); + $(this).prop("disabled", false); + } + + if (validation.disks) { + modal.name = "storagepool-status-disk-replace"; + modal.id = "` + pool.status.config.items.index + `-` + pool.id + `"; + + pool.force = $("#switch-storagepool-status-disk-replace-force-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked"); + + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolDiskReplace({ name: "` + pool.name + `", id: "` + pool.id + `", force: pool.force }, { id: "` + disk.id + `", idnew: disk.idnew }, { name: modal.name, id: modal.id }); + } + }); + + $("#dropdown-storagepool-status-disk-replace-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-status-disk-replace-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + + $("#helpblock-storagepool-status-disk-replace-disks-identifierwarning-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden").text(""); + ` + (zfsmanager.zfs.warnings.nvmevdev ? `$("#helpblock-storagepool-status-disk-replace-disks-identifierwarningzfs-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden");` : ``) + ` + + let disk = { + identifier: $(this).parent().attr("value"), + identifiertext: $(this).parent().text() + }; + + $("#listgroup-storagepool-status-disk-replace-disks-` + pool.status.config.items.index + `-` + pool.id + ` input[name='checkbox-storagepool-status-disk-replace-disks-` + pool.status.config.items.index + `-` + pool.id + `']").map(function () { + if ($(this).attr("data-disk-id-" + disk.identifier)) { + $(this).next().find(".select-ct-disk-row-id").text((disk.identifier == "blockdevice" ? "/dev/" : "") + $(this).attr("data-disk-id-" + disk.identifier)); + $(this).attr("data-disk-name", $(this).attr("data-disk-id-" + disk.identifier)); + } else { + $(this).next().find(".select-ct-disk-row-id").text("/dev/" + $(this).attr("data-disk-id-blockdevice")); + $(this).attr("data-disk-name", $(this).attr("data-disk-id-blockdevice")); + $("#helpblock-storagepool-status-disk-replace-disks-identifierwarning-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One or more disks is missing a " + disk.identifiertext + " identifier."); + ` + (zfsmanager.zfs.warnings.nvmevdev ? ` if (disk.identifier == "vdev" && /^nvme/gi.test($(this).attr("data-disk-id-blockdevice"))) { $("#helpblock-storagepool-status-disk-replace-disks-identifierwarningzfs-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); } - ` : ``) + ` - } - }); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalStatusDiskTrimStart(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-disk-trim-start-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); - FnModalStatusDiskTrimStartContent({ name: "` + pool.name + `", id: "` + pool.id + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: "` + disk.id + `" }, { id: $("#modal-storagepool-status-disk-trim-start-` + pool.status.config.items.index + `-` + pool.id + `") }); - }); - \x3C/script> - `; - - $("#modals-storagepool-status-" + pool.id).append(modal.window); -} - -function FnModalStatusDiskTrimStartContent(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-disk-trim-start-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - $("#spinner-storagepool-status-disk-trim-start-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let modal = { - name: "storagepool-status-disk-trim-start", - id: "` + pool.status.config.items.index + `-` + pool.id + `" - }; - let trim = { - secure: $("#switch-storagepool-status-disk-trim-start-secure-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked") - }; - - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolTrimStart({ name: "` + pool.name + `", id: "` + pool.id + `" }, { id: "` + disk.id + `" }, { resume: false, secure: trim.secure }, { name: modal.name, id: modal.id }); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalStatusStoragePoolClear(pool = { name, id, status: { config: { items: { index: 0 } } } }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-clear-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); - FnModalStatusStoragePoolClearContent({ name: "` + pool.name + `", id: "` + pool.id + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: $("#modal-storagepool-status-clear-` + pool.status.config.items.index + `-` + pool.id + `") }); - }); - \x3C/script> - `; - - $("#modals-storagepool-status-" + pool.id).append(modal.window); -} - -function FnModalStatusStoragePoolClearContent(pool = { name, id, status: { config: { items: { index: 0 } } } }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-clear-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - $("#spinner-storagepool-status-clear-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let modal = { - name: "storagepool-status-clear", - id: "` + pool.status.config.items.index + `-` + pool.id + `" - }; - - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolClear({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: modal.name, id: modal.id }); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalStatusStoragePoolRegenerateGuid(pool = { name, id, guid, status: { config: { items: { index: 0 } } } }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-regenerateguid-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); - FnModalStatusStoragePoolRegenerateGuidContent({ name: "` + pool.name + `", id: "` + pool.id + `", guid: "` + pool.guid + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: $("#modal-storagepool-status-regenerateguid-` + pool.status.config.items.index + `-` + pool.id + `") }); - }); - \x3C/script> - `; - - $("#modals-storagepool-status-" + pool.id).append(modal.window); -} - -function FnModalStatusStoragePoolRegenerateGuidContent(pool = { name, id, guid, status: { config: { items: { index: 0 } } } }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-regenerateguid-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - $("#spinner-storagepool-status-regenerateguid-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let modal = { - name: "storagepool-status-regenerateguid", - id: "` + pool.status.config.items.index + `-` + pool.id + `" - }; - - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolRegenerateGuid({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: modal.name, id: modal.id }); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalStatusStoragePoolResilver(pool = { name, id, status: { config: { items: { index: 0 } }, resilver: { started: false } } }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-resilver-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); - FnModalStatusStoragePoolResilverContent({ name: "` + pool.name + `", id: "` + pool.id + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } }, resilver: { started: ` + pool.status.resilver.started + ` } } }, { id: $("#modal-storagepool-status-resilver-` + pool.status.config.items.index + `-` + pool.id + `") }); - }); - \x3C/script> - `; - - $("#modals-storagepool-status-" + pool.id).append(modal.window); -} - -function FnModalStatusStoragePoolResilverContent(pool = { name, id, status: { config: { items: { index: 0 } }, resilver: { started: false } } }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-resilver-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - $("#spinner-storagepool-status-resilver-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let modal = { - name: "storagepool-status-resilver", - id: "` + pool.status.config.items.index + `-` + pool.id + `" - }; - - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolResilver({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: modal.name, id: modal.id }); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalStatusStoragePoolTrimStart(pool = { name, id, autotrim: false, status: { config: { items: { index: 0 } } } }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-trim-start-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); - FnModalStatusStoragePoolTrimStartContent({ name: "` + pool.name + `", id: "` + pool.id + `", autotrim: ` + pool.autotrim + `, status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: $("#modal-storagepool-status-trim-start-` + pool.status.config.items.index + `-` + pool.id + `") }); - }); - \x3C/script> - `; - - $("#modals-storagepool-status-" + pool.id).append(modal.window); -} - -function FnModalStatusStoragePoolTrimStartContent(pool = { name, id, autotrim: false, status: { config: { items: { index: 0 } } } }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-trim-start-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - $("#spinner-storagepool-status-trim-start-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let modal = { - name: "storagepool-status-trim-start", - id: "` + pool.status.config.items.index + `-` + pool.id + `" - }; - let trim = { - secure: $("#switch-storagepool-status-trim-start-secure-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked") - }; - - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolTrimStart({ name: "` + pool.name + `", id: "` + pool.id + `" }, { id: null }, { resume: false, secure: trim.secure }, { name: modal.name, id: modal.id }); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalStatusStoragePoolUpgrade(pool = { name, id, status: { config: { items: { index: 0 } } }, version }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-upgrade-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); - FnModalStatusStoragePoolUpgradeContent({ name: "` + pool.name + `", id: "` + pool.id + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } } }, version: "` + pool.version + `" }, { id: $("#modal-storagepool-status-upgrade-` + pool.status.config.items.index + `-` + pool.id + `") }); - FnStoragePoolConfigurationFeaturesDisabledGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "storagepool-status-upgrade", id: "` + pool.status.config.items.index + `-` + pool.id + `" }); - }); - \x3C/script> - `; - - $("#modals-storagepool-status-" + pool.id).append(modal.window); -} - -function FnModalStatusStoragePoolUpgradeContent(pool = { name, id, status: { config: { items: { index: 0 } } }, version }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-upgrade-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - $("#spinner-storagepool-status-upgrade-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let modal = { - name: "storagepool-status-upgrade", - id: "` + pool.status.config.items.index + `-` + pool.id + `" - }; - - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolUpgrade({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: modal.name, id: modal.id }); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalStatusVirtualDeviceAdd(pool = { name, id, feature: { allocation_classes: true }, status: { config: { items: { index: 0 } } } }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-virtualdevice-add-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); - FnModalStatusVirtualDeviceAddContent({ name: "` + pool.name + `", id: "` + pool.id + `", feature: { allocation_classes: ` + pool.feature.allocation_classes + ` }, status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: $("#modal-storagepool-status-virtualdevice-add-` + pool.status.config.items.index + `-` + pool.id + `") }); - FnDisksAvailableGet({ name: "storagepool-status-virtualdevice-add-disks", id: "` + pool.status.config.items.index + `-` + pool.id + `", default: true }); - }); - \x3C/script> - `; - - $("#modals-storagepool-status-" + pool.id).append(modal.window); -} - -function FnModalStatusVirtualDeviceAddContent(pool = { name, id, feature: { allocation_classes: true }, status: { config: { items: { index: 0 } } } }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#switch-storagepool-status-virtualdevice-add-disks-wwn-` + pool.status.config.items.index + `-` + pool.id + ` input").on("click", function () { - $("#btnspan-storagepool-status-virtualdevice-add-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").text("Block Device"); - $("#dropdown-storagepool-status-virtualdevice-add-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + ` li").siblings().removeClass("active"); - $("#dropdown-storagepool-status-virtualdevice-add-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + ` li[value='blockdevice']").addClass("active"); - $("#helpblock-storagepool-status-virtualdevice-add-disks-identifierwarning-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden").text(""); - ` + (zfsmanager.zfs.warnings.nvmevdev ? `$("#helpblock-storagepool-status-virtualdevice-add-disks-identifierwarningzfs-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden");` : ``) + ` - - let disk = { - identifier: ($(this).prop("checked") ? "wwn" : "blockdevice"), - identifiertext: ($(this).prop("checked") ? "WWN" : "Block Device") - }; - - if ($(this).prop("checked")) { - $("#controllabel-storagepool-status-virtualdevice-add-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden"); - $("#validationwrapper-storagepool-status-virtualdevice-add-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden"); - } else { - $("#controllabel-storagepool-status-virtualdevice-add-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - $("#validationwrapper-storagepool-status-virtualdevice-add-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - } - - $("#listgroup-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + ` input[name='checkbox-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `']").map(function () { - if ($(this).attr("data-disk-id-" + disk.identifier)) { - $(this).next().find(".select-ct-disk-row-id").text((disk.identifier == "blockdevice" ? "/dev/" : "") + $(this).attr("data-disk-id-" + disk.identifier)); - $(this).attr("data-disk-name", $(this).attr("data-disk-id-" + disk.identifier)); - } else { - $(this).next().find(".select-ct-disk-row-id").text("/dev/" + $(this).attr("data-disk-id-blockdevice")); - $(this).attr("data-disk-name", $(this).attr("data-disk-id-blockdevice")); - $("#helpblock-storagepool-status-virtualdevice-add-disks-identifierwarning-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One or more disks is missing a " + disk.identifiertext + " identifier."); - } - }); - }); - - $("#btn-storagepool-status-virtualdevice-add-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - $("#spinner-storagepool-status-virtualdevice-add-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let disks = { - id: [] - }; - let pool = { - force: false, - virtualdevice: "" - }; - let modal = { - name: "", - id: "" - }; - let validation = { - disks: false - }; - - $("#listgroup-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + ` input[name='checkbox-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `']:checked").map(function () { - disks.id.push($(this).attr("data-disk-name")); - }); - - if (disks.id.length < 1 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "cache") { - $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One or more disks is needed for Cache."); - - validation.disks = false; - } else if (disks.id.length < 1 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "dedup" && !$("#switch-storagepool-status-virtualdevice-add-dedup-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")) { - $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One or more disks is needed for Dedup."); - - validation.disks = false; - } else if (disks.id.length < 2 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "dedup" && $("#switch-storagepool-status-virtualdevice-add-dedup-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")) { - $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("Two or more disks is needed for Dedup (Mirror)."); - - validation.disks = false; - } else if (disks.id.length < 1 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "disk") { - $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One or more disks is needed for Disk."); - - validation.disks = false; - } else if (disks.id.length < 1 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "log" && !$("#switch-storagepool-status-virtualdevice-add-log-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")) { - $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One or more disks is needed for Log."); - - validation.disks = false; - } else if (disks.id.length < 2 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "log" && $("#switch-storagepool-status-virtualdevice-add-log-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")) { - $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("Two or more disks is needed for Log (Mirror)."); - - validation.disks = false; - } else if (disks.id.length < 2 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "mirror") { - $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("Two or more disks is needed for Mirror."); - - validation.disks = false; - } else if (disks.id.length < 2 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "raidz1") { - $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("Two or more disks is needed for RaidZ1."); - - validation.disks = false; - } else if (disks.id.length < 3 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "raidz2") { - $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("Three or more disks is needed for RaidZ2."); - - validation.disks = false; - } else if (disks.id.length < 4 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "raidz3") { - $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("Four or more disks is needed for RaidZ3."); - - validation.disks = false; - } else if (disks.id.length < 1 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "spare") { - $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One or more disks is needed for Spare."); - - validation.disks = false; - } else if (disks.id.length < 1 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "special" && !$("#switch-storagepool-status-virtualdevice-add-special-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")) { - $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One or more disks is needed for Special."); - - validation.disks = false; - } else if (disks.id.length < 2 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "special" && $("#switch-storagepool-status-virtualdevice-add-special-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")) { - $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("Two or more disks is needed for Special (Mirror)."); - - validation.disks = false; - } else { - $("#validationwrapper-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("has-error"); - $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text(""); - - validation.disks = true; - } - - if (!validation.disks) { - $("#validationwrapper-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").addClass("has-error"); - - $("#spinner-storagepool-status-virtualdevice-add-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden"); - $(this).prop("disabled", false); - } - - if (validation.disks) { - modal.name = "storagepool-status-virtualdevice-add"; - modal.id = "` + pool.status.config.items.index + `-` + pool.id + `"; - - pool.force = $("#switch-storagepool-status-virtualdevice-add-force-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked"); - pool.virtualdevice = ($("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") != "disk" ? $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") : ""); - - if ($("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "dedup" && $("#switch-storagepool-status-virtualdevice-add-dedup-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")) { - pool.virtualdevice = "dedup mirror"; - } else if ($("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "log" && $("#switch-storagepool-status-virtualdevice-add-log-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")) { - pool.virtualdevice = "log mirror"; - } else if ($("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "special" && $("#switch-storagepool-status-virtualdevice-add-special-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")) { - pool.virtualdevice = "special mirror"; - } - - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolVirtualDeviceAdd({ name: "` + pool.name + `", id: "` + pool.id + `", force: pool.force, virtualdevice: pool.virtualdevice }, { id: disks.id }, { name: modal.name, id: modal.id }); - } - }); - - $("#dropdown-storagepool-status-virtualdevice-add-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-status-virtualdevice-add-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - - $("#helpblock-storagepool-status-virtualdevice-add-disks-identifierwarning-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden").text(""); - ` + (zfsmanager.zfs.warnings.nvmevdev ? `$("#helpblock-storagepool-status-virtualdevice-add-disks-identifierwarningzfs-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden");` : ``) + ` - - let disk = { - identifier: $(this).parent().attr("value"), - identifiertext: $(this).parent().text() - }; - - $("#listgroup-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + ` input[name='checkbox-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `']").map(function () { - if ($(this).attr("data-disk-id-" + disk.identifier)) { - $(this).next().find(".select-ct-disk-row-id").text((disk.identifier == "blockdevice" ? "/dev/" : "") + $(this).attr("data-disk-id-" + disk.identifier)); - $(this).attr("data-disk-name", $(this).attr("data-disk-id-" + disk.identifier)); - } else { - $(this).next().find(".select-ct-disk-row-id").text("/dev/" + $(this).attr("data-disk-id-blockdevice")); - $(this).attr("data-disk-name", $(this).attr("data-disk-id-blockdevice")); - $("#helpblock-storagepool-status-virtualdevice-add-disks-identifierwarning-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One or more disks is missing a " + disk.identifiertext + " identifier."); - + ` : ``) + ` + } + }); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalStatusDiskTrimStart(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-disk-trim-start-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); + FnModalStatusDiskTrimStartContent({ name: "` + pool.name + `", id: "` + pool.id + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: "` + disk.id + `" }, { id: $("#modal-storagepool-status-disk-trim-start-` + pool.status.config.items.index + `-` + pool.id + `") }); + }); + \x3C/script> + `; + + $("#modals-storagepool-status-" + pool.id).append(modal.window); +} + +function FnModalStatusDiskTrimStartContent(pool = { name, id, status: { config: { items: { index: 0 } } } }, disk = { id }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-disk-trim-start-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + $("#spinner-storagepool-status-disk-trim-start-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let modal = { + name: "storagepool-status-disk-trim-start", + id: "` + pool.status.config.items.index + `-` + pool.id + `" + }; + let trim = { + secure: $("#switch-storagepool-status-disk-trim-start-secure-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked") + }; + + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolTrimStart({ name: "` + pool.name + `", id: "` + pool.id + `" }, { id: "` + disk.id + `" }, { resume: false, secure: trim.secure }, { name: modal.name, id: modal.id }); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalStatusStoragePoolClear(pool = { name, id, status: { config: { items: { index: 0 } } } }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-clear-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); + FnModalStatusStoragePoolClearContent({ name: "` + pool.name + `", id: "` + pool.id + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: $("#modal-storagepool-status-clear-` + pool.status.config.items.index + `-` + pool.id + `") }); + }); + \x3C/script> + `; + + $("#modals-storagepool-status-" + pool.id).append(modal.window); +} + +function FnModalStatusStoragePoolClearContent(pool = { name, id, status: { config: { items: { index: 0 } } } }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-clear-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + $("#spinner-storagepool-status-clear-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let modal = { + name: "storagepool-status-clear", + id: "` + pool.status.config.items.index + `-` + pool.id + `" + }; + + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolClear({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: modal.name, id: modal.id }); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalStatusStoragePoolRegenerateGuid(pool = { name, id, guid, status: { config: { items: { index: 0 } } } }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-regenerateguid-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); + FnModalStatusStoragePoolRegenerateGuidContent({ name: "` + pool.name + `", id: "` + pool.id + `", guid: "` + pool.guid + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: $("#modal-storagepool-status-regenerateguid-` + pool.status.config.items.index + `-` + pool.id + `") }); + }); + \x3C/script> + `; + + $("#modals-storagepool-status-" + pool.id).append(modal.window); +} + +function FnModalStatusStoragePoolRegenerateGuidContent(pool = { name, id, guid, status: { config: { items: { index: 0 } } } }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-regenerateguid-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + $("#spinner-storagepool-status-regenerateguid-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let modal = { + name: "storagepool-status-regenerateguid", + id: "` + pool.status.config.items.index + `-` + pool.id + `" + }; + + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolRegenerateGuid({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: modal.name, id: modal.id }); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalStatusStoragePoolResilver(pool = { name, id, status: { config: { items: { index: 0 } }, resilver: { started: false } } }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-resilver-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); + FnModalStatusStoragePoolResilverContent({ name: "` + pool.name + `", id: "` + pool.id + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } }, resilver: { started: ` + pool.status.resilver.started + ` } } }, { id: $("#modal-storagepool-status-resilver-` + pool.status.config.items.index + `-` + pool.id + `") }); + }); + \x3C/script> + `; + + $("#modals-storagepool-status-" + pool.id).append(modal.window); +} + +function FnModalStatusStoragePoolResilverContent(pool = { name, id, status: { config: { items: { index: 0 } }, resilver: { started: false } } }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-resilver-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + $("#spinner-storagepool-status-resilver-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let modal = { + name: "storagepool-status-resilver", + id: "` + pool.status.config.items.index + `-` + pool.id + `" + }; + + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolResilver({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: modal.name, id: modal.id }); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalStatusStoragePoolTrimStart(pool = { name, id, autotrim: false, status: { config: { items: { index: 0 } } } }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-trim-start-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); + FnModalStatusStoragePoolTrimStartContent({ name: "` + pool.name + `", id: "` + pool.id + `", autotrim: ` + pool.autotrim + `, status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: $("#modal-storagepool-status-trim-start-` + pool.status.config.items.index + `-` + pool.id + `") }); + }); + \x3C/script> + `; + + $("#modals-storagepool-status-" + pool.id).append(modal.window); +} + +function FnModalStatusStoragePoolTrimStartContent(pool = { name, id, autotrim: false, status: { config: { items: { index: 0 } } } }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-trim-start-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + $("#spinner-storagepool-status-trim-start-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let modal = { + name: "storagepool-status-trim-start", + id: "` + pool.status.config.items.index + `-` + pool.id + `" + }; + let trim = { + secure: $("#switch-storagepool-status-trim-start-secure-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked") + }; + + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolTrimStart({ name: "` + pool.name + `", id: "` + pool.id + `" }, { id: null }, { resume: false, secure: trim.secure }, { name: modal.name, id: modal.id }); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalStatusStoragePoolUpgrade(pool = { name, id, status: { config: { items: { index: 0 } } }, version }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-upgrade-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); + FnModalStatusStoragePoolUpgradeContent({ name: "` + pool.name + `", id: "` + pool.id + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } } }, version: "` + pool.version + `" }, { id: $("#modal-storagepool-status-upgrade-` + pool.status.config.items.index + `-` + pool.id + `") }); + FnStoragePoolConfigurationFeaturesDisabledGet({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: "storagepool-status-upgrade", id: "` + pool.status.config.items.index + `-` + pool.id + `" }); + }); + \x3C/script> + `; + + $("#modals-storagepool-status-" + pool.id).append(modal.window); +} + +function FnModalStatusStoragePoolUpgradeContent(pool = { name, id, status: { config: { items: { index: 0 } } }, version }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-upgrade-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + $("#spinner-storagepool-status-upgrade-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let modal = { + name: "storagepool-status-upgrade", + id: "` + pool.status.config.items.index + `-` + pool.id + `" + }; + + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolUpgrade({ name: "` + pool.name + `", id: "` + pool.id + `" }, { name: modal.name, id: modal.id }); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalStatusVirtualDeviceAdd(pool = { name, id, feature: { allocation_classes: true }, status: { config: { items: { index: 0 } } } }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-virtualdevice-add-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); + FnModalStatusVirtualDeviceAddContent({ name: "` + pool.name + `", id: "` + pool.id + `", feature: { allocation_classes: ` + pool.feature.allocation_classes + ` }, status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: $("#modal-storagepool-status-virtualdevice-add-` + pool.status.config.items.index + `-` + pool.id + `") }); + FnDisksAvailableGet({ name: "storagepool-status-virtualdevice-add-disks", id: "` + pool.status.config.items.index + `-` + pool.id + `", default: true }); + }); + \x3C/script> + `; + + $("#modals-storagepool-status-" + pool.id).append(modal.window); +} + +function FnModalStatusVirtualDeviceAddContent(pool = { name, id, feature: { allocation_classes: true }, status: { config: { items: { index: 0 } } } }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#switch-storagepool-status-virtualdevice-add-disks-wwn-` + pool.status.config.items.index + `-` + pool.id + ` input").on("click", function () { + $("#btnspan-storagepool-status-virtualdevice-add-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").text("Block Device"); + $("#dropdown-storagepool-status-virtualdevice-add-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + ` li").siblings().removeClass("active"); + $("#dropdown-storagepool-status-virtualdevice-add-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + ` li[value='blockdevice']").addClass("active"); + $("#helpblock-storagepool-status-virtualdevice-add-disks-identifierwarning-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden").text(""); + ` + (zfsmanager.zfs.warnings.nvmevdev ? `$("#helpblock-storagepool-status-virtualdevice-add-disks-identifierwarningzfs-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden");` : ``) + ` + + let disk = { + identifier: ($(this).prop("checked") ? "wwn" : "blockdevice"), + identifiertext: ($(this).prop("checked") ? "WWN" : "Block Device") + }; + + if ($(this).prop("checked")) { + $("#controllabel-storagepool-status-virtualdevice-add-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden"); + $("#validationwrapper-storagepool-status-virtualdevice-add-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden"); + } else { + $("#controllabel-storagepool-status-virtualdevice-add-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + $("#validationwrapper-storagepool-status-virtualdevice-add-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + } + + $("#listgroup-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + ` input[name='checkbox-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `']").map(function () { + if ($(this).attr("data-disk-id-" + disk.identifier)) { + $(this).next().find(".select-ct-disk-row-id").text((disk.identifier == "blockdevice" ? "/dev/" : "") + $(this).attr("data-disk-id-" + disk.identifier)); + $(this).attr("data-disk-name", $(this).attr("data-disk-id-" + disk.identifier)); + } else { + $(this).next().find(".select-ct-disk-row-id").text("/dev/" + $(this).attr("data-disk-id-blockdevice")); + $(this).attr("data-disk-name", $(this).attr("data-disk-id-blockdevice")); + $("#helpblock-storagepool-status-virtualdevice-add-disks-identifierwarning-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One or more disks is missing a " + disk.identifiertext + " identifier."); + } + }); + }); + + $("#btn-storagepool-status-virtualdevice-add-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + $("#spinner-storagepool-status-virtualdevice-add-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let disks = { + id: [] + }; + let pool = { + force: false, + virtualdevice: "" + }; + let modal = { + name: "", + id: "" + }; + let validation = { + disks: false + }; + + $("#listgroup-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + ` input[name='checkbox-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `']:checked").map(function () { + disks.id.push($(this).attr("data-disk-name")); + }); + + if (disks.id.length < 1 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "cache") { + $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One or more disks is needed for Cache."); + + validation.disks = false; + } else if (disks.id.length < 1 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "dedup" && !$("#switch-storagepool-status-virtualdevice-add-dedup-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")) { + $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One or more disks is needed for Dedup."); + + validation.disks = false; + } else if (disks.id.length < 2 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "dedup" && $("#switch-storagepool-status-virtualdevice-add-dedup-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")) { + $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("Two or more disks is needed for Dedup (Mirror)."); + + validation.disks = false; + } else if (disks.id.length < 1 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "disk") { + $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One or more disks is needed for Disk."); + + validation.disks = false; + } else if (disks.id.length < 1 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "log" && !$("#switch-storagepool-status-virtualdevice-add-log-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")) { + $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One or more disks is needed for Log."); + + validation.disks = false; + } else if (disks.id.length < 2 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "log" && $("#switch-storagepool-status-virtualdevice-add-log-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")) { + $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("Two or more disks is needed for Log (Mirror)."); + + validation.disks = false; + } else if (disks.id.length < 2 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "mirror") { + $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("Two or more disks is needed for Mirror."); + + validation.disks = false; + } else if (disks.id.length < 2 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "raidz1") { + $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("Two or more disks is needed for RaidZ1."); + + validation.disks = false; + } else if (disks.id.length < 3 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "raidz2") { + $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("Three or more disks is needed for RaidZ2."); + + validation.disks = false; + } else if (disks.id.length < 4 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "raidz3") { + $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("Four or more disks is needed for RaidZ3."); + + validation.disks = false; + } else if (disks.id.length < 1 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "spare") { + $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One or more disks is needed for Spare."); + + validation.disks = false; + } else if (disks.id.length < 1 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "special" && !$("#switch-storagepool-status-virtualdevice-add-special-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")) { + $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One or more disks is needed for Special."); + + validation.disks = false; + } else if (disks.id.length < 2 && $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "special" && $("#switch-storagepool-status-virtualdevice-add-special-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")) { + $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("Two or more disks is needed for Special (Mirror)."); + + validation.disks = false; + } else { + $("#validationwrapper-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("has-error"); + $("#helpblock-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text(""); + + validation.disks = true; + } + + if (!validation.disks) { + $("#validationwrapper-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `").addClass("has-error"); + + $("#spinner-storagepool-status-virtualdevice-add-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden"); + $(this).prop("disabled", false); + } + + if (validation.disks) { + modal.name = "storagepool-status-virtualdevice-add"; + modal.id = "` + pool.status.config.items.index + `-` + pool.id + `"; + + pool.force = $("#switch-storagepool-status-virtualdevice-add-force-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked"); + pool.virtualdevice = ($("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") != "disk" ? $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") : ""); + + if ($("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "dedup" && $("#switch-storagepool-status-virtualdevice-add-dedup-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")) { + pool.virtualdevice = "dedup mirror"; + } else if ($("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "log" && $("#switch-storagepool-status-virtualdevice-add-log-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")) { + pool.virtualdevice = "log mirror"; + } else if ($("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").attr("data-field-value") == "special" && $("#switch-storagepool-status-virtualdevice-add-special-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")) { + pool.virtualdevice = "special mirror"; + } + + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolVirtualDeviceAdd({ name: "` + pool.name + `", id: "` + pool.id + `", force: pool.force, virtualdevice: pool.virtualdevice }, { id: disks.id }, { name: modal.name, id: modal.id }); + } + }); + + $("#dropdown-storagepool-status-virtualdevice-add-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-status-virtualdevice-add-disks-identifier-` + pool.status.config.items.index + `-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + + $("#helpblock-storagepool-status-virtualdevice-add-disks-identifierwarning-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden").text(""); + ` + (zfsmanager.zfs.warnings.nvmevdev ? `$("#helpblock-storagepool-status-virtualdevice-add-disks-identifierwarningzfs-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden");` : ``) + ` + + let disk = { + identifier: $(this).parent().attr("value"), + identifiertext: $(this).parent().text() + }; + + $("#listgroup-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + ` input[name='checkbox-storagepool-status-virtualdevice-add-disks-` + pool.status.config.items.index + `-` + pool.id + `']").map(function () { + if ($(this).attr("data-disk-id-" + disk.identifier)) { + $(this).next().find(".select-ct-disk-row-id").text((disk.identifier == "blockdevice" ? "/dev/" : "") + $(this).attr("data-disk-id-" + disk.identifier)); + $(this).attr("data-disk-name", $(this).attr("data-disk-id-" + disk.identifier)); + } else { + $(this).next().find(".select-ct-disk-row-id").text("/dev/" + $(this).attr("data-disk-id-blockdevice")); + $(this).attr("data-disk-name", $(this).attr("data-disk-id-blockdevice")); + $("#helpblock-storagepool-status-virtualdevice-add-disks-identifierwarning-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden").text("One or more disks is missing a " + disk.identifiertext + " identifier."); + ` + (zfsmanager.zfs.warnings.nvmevdev ? ` if (disk.identifier == "vdev" && /^nvme/gi.test($(this).attr("data-disk-id-blockdevice"))) { $("#helpblock-storagepool-status-virtualdevice-add-disks-identifierwarningzfs-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); } - ` : ``) + ` - } - }); - }); - - $("#dropdown-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").on("click", "li a", function () { - $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); - $(this).parent().siblings().removeClass("active"); - $(this).parent().addClass("active"); - - if ($(this).text() == "Dedup") { - $("#controllabel-storagepool-status-virtualdevice-add-dedup-mirror-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - $("#switch-storagepool-status-virtualdevice-add-dedup-mirror-` + pool.status.config.items.index + `-` + pool.id + `").parent().removeClass("hidden"); - } else { - $("#controllabel-storagepool-status-virtualdevice-add-dedup-mirror-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden"); - $("#switch-storagepool-status-virtualdevice-add-dedup-mirror-` + pool.status.config.items.index + `-` + pool.id + `").parent().addClass("hidden"); - if ($("#switch-storagepool-status-virtualdevice-add-dedup-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")) { - $("#switch-storagepool-status-virtualdevice-add-dedup-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").click(); - } - } - - if ($(this).text() == "Log") { - $("#controllabel-storagepool-status-virtualdevice-add-log-mirror-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - $("#switch-storagepool-status-virtualdevice-add-log-mirror-` + pool.status.config.items.index + `-` + pool.id + `").parent().removeClass("hidden"); - } else { - $("#controllabel-storagepool-status-virtualdevice-add-log-mirror-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden"); - $("#switch-storagepool-status-virtualdevice-add-log-mirror-` + pool.status.config.items.index + `-` + pool.id + `").parent().addClass("hidden"); - if ($("#switch-storagepool-status-virtualdevice-add-log-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")) { - $("#switch-storagepool-status-virtualdevice-add-log-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").click(); - } - } - - if ($(this).text() == "Special") { - $("#controllabel-storagepool-status-virtualdevice-add-special-mirror-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - $("#switch-storagepool-status-virtualdevice-add-special-mirror-` + pool.status.config.items.index + `-` + pool.id + `").parent().removeClass("hidden"); - } else { - $("#controllabel-storagepool-status-virtualdevice-add-special-mirror-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden"); - $("#switch-storagepool-status-virtualdevice-add-special-mirror-` + pool.status.config.items.index + `-` + pool.id + `").parent().addClass("hidden"); - if ($("#switch-storagepool-status-virtualdevice-add-special-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")) { - $("#switch-storagepool-status-virtualdevice-add-special-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").click(); - } - } - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalStatusVirtualDeviceClear(pool = { name, id, status: { config: { items: { index: 0 } } } }, virtualdevice = { id }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-virtualdevice-clear-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); - FnModalStatusVirtualDeviceClearContent({ name: "` + pool.name + `", id: "` + pool.id + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: "` + virtualdevice.id + `" }, { id: $("#modal-storagepool-status-virtualdevice-clear-` + pool.status.config.items.index + `-` + pool.id + `") }); - }); - \x3C/script> - `; - - $("#modals-storagepool-status-" + pool.id).append(modal.window); -} - -function FnModalStatusVirtualDeviceClearContent(pool = { name, id, status: { config: { items: { index: 0 } } } }, virtualdevice = { id }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-virtualdevice-clear-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - $("#spinner-storagepool-status-virtualdevice-clear-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let modal = { - name: "storagepool-status-virtualdevice-clear", - id: "` + pool.status.config.items.index + `-` + pool.id + `" - }; - - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolVirtualDeviceClear({ name: "` + pool.name + `", id: "` + pool.id + `" }, { id: "` + virtualdevice.id + `" }, { name: modal.name, id: modal.id }); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - -function FnModalStatusVirtualDeviceRemove(pool = { name, id, status: { config: { items: { index: 0 } } } }, virtualdevice = { id, disk: false }) { - let modal = { - window: "" - }; - - modal.window = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-virtualdevice-remove-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); - FnModalStatusVirtualDeviceRemoveContent({ name: "` + pool.name + `", id: "` + pool.id + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: "` + virtualdevice.id + `", disk: ` + virtualdevice.disk + ` }, { id: $("#modal-storagepool-status-virtualdevice-remove-` + pool.status.config.items.index + `-` + pool.id + `") }); - }); - \x3C/script> - `; - - $("#modals-storagepool-status-" + pool.id).append(modal.window); -} - -function FnModalStatusVirtualDeviceRemoveContent(pool = { name, id, status: { config: { items: { index: 0 } } } }, virtualdevice = { id, disk: false }, modal = { id }) { - modal.content = ` - - - \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> - $("#btn-storagepool-status-virtualdevice-remove-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { - $("#spinner-storagepool-status-virtualdevice-remove-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - $(this).prop("disabled", true); - - let virtualdevice = { - labelclear: ` + (virtualdevice.disk ? `$("#switch-storagepool-status-virtualdevice-remove-labelclear-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")` : false) + ` - }; - let modal = { - name: "storagepool-status-virtualdevice-remove", - id: "` + pool.status.config.items.index + `-` + pool.id + `" - }; - - $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); - $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); - - FnStoragePoolVirtualDeviceRemove({ name: "` + pool.name + `", id: "` + pool.id + `"} , { id: "` + virtualdevice.id + `", labelclear: virtualdevice.labelclear }, { name: modal.name, id: modal.id }); - }); - \x3C/script> - `; - - modal.id.empty().append(modal.content); -} - + ` : ``) + ` + } + }); + }); + + $("#dropdown-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").on("click", "li a", function () { + $("#btnspan-storagepool-status-virtualdevice-add-virtualdevice-` + pool.status.config.items.index + `-` + pool.id + `").text($(this).text()).attr("data-field-value", $(this).parent().attr("value")); + $(this).parent().siblings().removeClass("active"); + $(this).parent().addClass("active"); + + if ($(this).text() == "Dedup") { + $("#controllabel-storagepool-status-virtualdevice-add-dedup-mirror-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + $("#switch-storagepool-status-virtualdevice-add-dedup-mirror-` + pool.status.config.items.index + `-` + pool.id + `").parent().removeClass("hidden"); + } else { + $("#controllabel-storagepool-status-virtualdevice-add-dedup-mirror-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden"); + $("#switch-storagepool-status-virtualdevice-add-dedup-mirror-` + pool.status.config.items.index + `-` + pool.id + `").parent().addClass("hidden"); + if ($("#switch-storagepool-status-virtualdevice-add-dedup-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")) { + $("#switch-storagepool-status-virtualdevice-add-dedup-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").click(); + } + } + + if ($(this).text() == "Log") { + $("#controllabel-storagepool-status-virtualdevice-add-log-mirror-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + $("#switch-storagepool-status-virtualdevice-add-log-mirror-` + pool.status.config.items.index + `-` + pool.id + `").parent().removeClass("hidden"); + } else { + $("#controllabel-storagepool-status-virtualdevice-add-log-mirror-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden"); + $("#switch-storagepool-status-virtualdevice-add-log-mirror-` + pool.status.config.items.index + `-` + pool.id + `").parent().addClass("hidden"); + if ($("#switch-storagepool-status-virtualdevice-add-log-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")) { + $("#switch-storagepool-status-virtualdevice-add-log-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").click(); + } + } + + if ($(this).text() == "Special") { + $("#controllabel-storagepool-status-virtualdevice-add-special-mirror-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + $("#switch-storagepool-status-virtualdevice-add-special-mirror-` + pool.status.config.items.index + `-` + pool.id + `").parent().removeClass("hidden"); + } else { + $("#controllabel-storagepool-status-virtualdevice-add-special-mirror-` + pool.status.config.items.index + `-` + pool.id + `").addClass("hidden"); + $("#switch-storagepool-status-virtualdevice-add-special-mirror-` + pool.status.config.items.index + `-` + pool.id + `").parent().addClass("hidden"); + if ($("#switch-storagepool-status-virtualdevice-add-special-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")) { + $("#switch-storagepool-status-virtualdevice-add-special-mirror-` + pool.status.config.items.index + `-` + pool.id + ` input").click(); + } + } + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalStatusVirtualDeviceClear(pool = { name, id, status: { config: { items: { index: 0 } } } }, virtualdevice = { id }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-virtualdevice-clear-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); + FnModalStatusVirtualDeviceClearContent({ name: "` + pool.name + `", id: "` + pool.id + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: "` + virtualdevice.id + `" }, { id: $("#modal-storagepool-status-virtualdevice-clear-` + pool.status.config.items.index + `-` + pool.id + `") }); + }); + \x3C/script> + `; + + $("#modals-storagepool-status-" + pool.id).append(modal.window); +} + +function FnModalStatusVirtualDeviceClearContent(pool = { name, id, status: { config: { items: { index: 0 } } } }, virtualdevice = { id }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-virtualdevice-clear-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + $("#spinner-storagepool-status-virtualdevice-clear-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let modal = { + name: "storagepool-status-virtualdevice-clear", + id: "` + pool.status.config.items.index + `-` + pool.id + `" + }; + + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolVirtualDeviceClear({ name: "` + pool.name + `", id: "` + pool.id + `" }, { id: "` + virtualdevice.id + `" }, { name: modal.name, id: modal.id }); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + +function FnModalStatusVirtualDeviceRemove(pool = { name, id, status: { config: { items: { index: 0 } } } }, virtualdevice = { id, disk: false }) { + let modal = { + window: "" + }; + + modal.window = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-virtualdevice-remove-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + FnStoragePoolRefreshAutoDisable({ name: "` + pool.name + `", id: "` + pool.id + `" }); + FnModalStatusVirtualDeviceRemoveContent({ name: "` + pool.name + `", id: "` + pool.id + `", status: { config: { items: { index: ` + pool.status.config.items.index + ` } } } }, { id: "` + virtualdevice.id + `", disk: ` + virtualdevice.disk + ` }, { id: $("#modal-storagepool-status-virtualdevice-remove-` + pool.status.config.items.index + `-` + pool.id + `") }); + }); + \x3C/script> + `; + + $("#modals-storagepool-status-" + pool.id).append(modal.window); +} + +function FnModalStatusVirtualDeviceRemoveContent(pool = { name, id, status: { config: { items: { index: 0 } } } }, virtualdevice = { id, disk: false }, modal = { id }) { + modal.content = ` + + + \x3Cscript nonce="1t55lZ7tzuKTreHVNwE66Ox32Mc="> + $("#btn-storagepool-status-virtualdevice-remove-apply-` + pool.status.config.items.index + `-` + pool.id + `").on("click", function () { + $("#spinner-storagepool-status-virtualdevice-remove-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + $(this).prop("disabled", true); + + let virtualdevice = { + labelclear: ` + (virtualdevice.disk ? `$("#switch-storagepool-status-virtualdevice-remove-labelclear-` + pool.status.config.items.index + `-` + pool.id + ` input").prop("checked")` : false) + ` + }; + let modal = { + name: "storagepool-status-virtualdevice-remove", + id: "` + pool.status.config.items.index + `-` + pool.id + `" + }; + + $("[id^=btn-storagepool-status-dropdown-][id$=` + pool.id + `]").addClass("disabled"); + $("#spinner-storagepool-status-` + pool.status.config.items.index + `-` + pool.id + `").removeClass("hidden"); + + FnStoragePoolVirtualDeviceRemove({ name: "` + pool.name + `", id: "` + pool.id + `"} , { id: "` + virtualdevice.id + `", labelclear: virtualdevice.labelclear }, { name: modal.name, id: modal.id }); + }); + \x3C/script> + `; + + modal.id.empty().append(modal.content); +} + //#endregion \ No newline at end of file