feat(community): add ktn-enclosure-manager app - #5679

Open
MechanicalCoderX wants to merge 1 commit into
truenas:masterfrom
MechanicalCoderX:add-ktn-enclosure-manager
Open

feat(community): add ktn-enclosure-manager app#5679
MechanicalCoderX wants to merge 1 commit into
truenas:masterfrom
MechanicalCoderX:add-ktn-enclosure-manager

Conversation

@MechanicalCoderX

@MechanicalCoderXMechanicalCoderX commented Aug 27, 2026

Copy link
Copy Markdown

App Addition

  • I have opened an issue to discuss this app addition before submitting this pull request.

AI

  • Part or All of this PR was generated by an LLM.

Description

Adds KTN Enclosure Manager to the community train.

KTN Enclosure Manager gives TrueNAS SCALE users a physical drive-bay map, chassis telemetry (temperatures, fans, PSUs) and IDENT LED control for SES-capable SAS disk shelves (JBODs).

TrueNAS gates its built-in enclosure UI behind iX hardware, so View Enclosure reports "Enclosure Unavailable" on a community system with a third-party shelf. This app fills that gap without patching middleware or spoofing hardware identity. It answers "which physical bay is this failing disk actually in?" With an optional TrueNAS API key it adds pool, vdev, ZFS error and SMART context per bay.

Updated 2026-08-30: the branch was rebased onto current master and squashed to a single commit. The previous history carried version bumps (1.3.2 through 1.5.5) for an app that has never been in the catalog, which was noise. I also went back through the package against merged community apps and fixed a set of conformance gaps; the notable ones are listed under Special Notes.

App Information

Testing

Tested locally with:

  • basic-values.yaml (ix_volume storage, authentication required)
  • hostpath-anon-values.yaml (host_path storage, open dashboard, Identify still gated)

Both render and install to a healthy container via .github/scripts/ci.py against the published 1.5.5 image, exit 0. Also run clean: port_validation.py (exit 0) and generate_metadata.py (exit 0, and byte-idempotent - the tree is unchanged after a full cycle).

apps_dev_charts_validate I could not run here: the validation image imports middleware, which needs libzfs, and my build host is not a ZFS system. Leaving that one to repo CI rather than claiming it.

Icons and Screenshots

app.yaml/item.yaml already reference the canonical CDN paths (apps/ktn-enclosure-manager/icons/icon.svg, apps/ktn-enclosure-manager/screenshots/screenshot1-3.png). Please upload these sources to them:

Special Notes

  • Device access (/dev/sg*), and how it compares. For scale: scrutiny is merged in this train and does closely related work; it is set_privileged(true), declares 14 capabilities, and bind-mounts all of /dev plus /run/udev. This app is not privileged, declares 2 capabilities (SETUID, SETGID), has host_mounts: [], and passes through only the SCSI generic nodes the user names, with an rw cgroup grant rather than rwm. Every telemetry read works on a read-only device open (sg_ses --readonly), so granting :r is a supported monitoring-only deployment where Identify returns a permission error and nothing else changes. The w exists solely for the IDENT LED SEND DIAGNOSTIC, which addresses the enclosure processor, never disk data. No code path powers a drive off, resets a PHY, or touches a fault LED. SECURITY.md documents the boundary.
  • Privilege model. The container starts as root so a ~200-line helper can bind a unix socket and open the enclosure device; the entrypoint drops the web process to uid/gid 1000 with setpriv. That is why SETUID/SETGID are added back over cap_drop: ALL, and they are the only two. The helper accepts three operations (identify_on, identify_off, read-only SES page read) and cannot be passed a path or a command. Default AppArmor profile, no /sys mount.
  • Conformance fixes in this update. The storage group was missing $ref: normalize/ix_volume and the ACL block, which every other app in the train carries; that is fixed and the canonical block is now used. The healthcheck used use_built_in(), which effectively nothing in the community train does; it is now set_test("tcp", ...), which needs no curl in the image. The device is now a host/container pair list like other device-passthrough apps rather than a single required string, so CI can pass devices: [] instead of a placeholder node. The standard permissions container replaces a manual chown instruction. Port default moved into the catalog band (30842). Group names and descriptions now follow the house convention.
  • First-time setup. No default credentials; the first visit to the Web UI creates the administrator account (surfaced as an x-notes warning).
  • No shelf attached. The app degrades cleanly (renders, starts, reports no enclosure), which is what CI exercises since runners have no SAS hardware.
  • Hardware honesty. This version runs on my own 15-bay SES shelf under TrueNAS SCALE 25.10, but that is N=1 hardware with a single maintainer, and a pinned issue on the app repo collects reports for other enclosures. Where a shelf reports element/slot numbering the app cannot map unambiguously it refuses to act rather than guess, so an Identify request either addresses the right bay or returns an error naming what the enclosure reported.
  • Packaged path vs. deployed path. I run this via Install-via-YAML rather than through the catalog package, so the packaged path is render- and install-verified (ci.py, both test files, published image) rather than deploy-verified on an appliance.

Checklist

  • App runs successfully locally
  • Only modified files under /ix-dev/ or /library/
  • README.md included
  • Multiple test scenarios tested
  • questions.yaml has clear descriptions and follows structure of existing apps
  • All automated CI checks pass

@MechanicalCoderX

Copy link
Copy Markdown
Author

Saw this went to draft. What do you want changed first? Or name an app you think does it right and I'll go through mine against that.

I'd expect the /dev/sg* access to be the part you want to look hardest at. I'm doing the changes myself, so short is fine.

KTN Enclosure Manager is a drive-bay map, chassis telemetry and IDENT LED
control panel for SES disk shelves attached to TrueNAS SCALE. TrueNAS gates
its built-in enclosure UI behind iX hardware, so a third-party shelf reports
Enclosure Unavailable; this fills that gap without patching middleware.
Telemetry runs entirely on read-only device opens. The only write the app can
perform is lighting a drive bay Identify LED, issued by a small root helper
over a unix socket. The container is not privileged, drops ALL capabilities
and adds back only SETUID and SETGID for the setpriv drop to uid 1000, keeps
the default AppArmor profile, and mounts no host path other than its own data
directory.
App version 1.5.5, catalog version 1.0.0.
@MechanicalCoderX
MechanicalCoderXforce-pushed the add-ktn-enclosure-manager branch from 109037f to a61d190CompareAugust 31, 2026 03:36
@MechanicalCoderX
MechanicalCoderX marked this pull request as ready for review September 1, 2026 00:12
@MechanicalCoderX

Copy link
Copy Markdown
Author

I read the merged community apps and fixed this one to match. Worst thing I found was mine. The storage group had no normalize/ix_volume ref. On a default ixVolume install ix_volumes comes back empty, so no dataset. Confirmed against middleware on 25.10.6, before and after.

Squashed to one commit on current master and force-pushed. Old history's gone. It's ready to look at.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@MechanicalCoderX@stavros-k
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(community): add ktn-enclosure-manager app - #5679

Open
MechanicalCoderX wants to merge 1 commit into
truenas:masterfrom
MechanicalCoderX:add-ktn-enclosure-manager
Open

feat(community): add ktn-enclosure-manager app#5679
MechanicalCoderX wants to merge 1 commit into
truenas:masterfrom
MechanicalCoderX:add-ktn-enclosure-manager

Conversation

@MechanicalCoderX

@MechanicalCoderXMechanicalCoderX commented Aug 27, 2026

Copy link
Copy Markdown

App Addition

  • I have opened an issue to discuss this app addition before submitting this pull request.

AI

  • Part or All of this PR was generated by an LLM.

Description

Adds KTN Enclosure Manager to the community train.

KTN Enclosure Manager gives TrueNAS SCALE users a physical drive-bay map, chassis telemetry (temperatures, fans, PSUs) and IDENT LED control for SES-capable SAS disk shelves (JBODs).

TrueNAS gates its built-in enclosure UI behind iX hardware, so View Enclosure reports "Enclosure Unavailable" on a community system with a third-party shelf. This app fills that gap without patching middleware or spoofing hardware identity. It answers "which physical bay is this failing disk actually in?" With an optional TrueNAS API key it adds pool, vdev, ZFS error and SMART context per bay.

Updated 2026-08-30: the branch was rebased onto current master and squashed to a single commit. The previous history carried version bumps (1.3.2 through 1.5.5) for an app that has never been in the catalog, which was noise. I also went back through the package against merged community apps and fixed a set of conformance gaps; the notable ones are listed under Special Notes.

App Information

Testing

Tested locally with:

  • basic-values.yaml (ix_volume storage, authentication required)
  • hostpath-anon-values.yaml (host_path storage, open dashboard, Identify still gated)

Both render and install to a healthy container via .github/scripts/ci.py against the published 1.5.5 image, exit 0. Also run clean: port_validation.py (exit 0) and generate_metadata.py (exit 0, and byte-idempotent - the tree is unchanged after a full cycle).

apps_dev_charts_validate I could not run here: the validation image imports middleware, which needs libzfs, and my build host is not a ZFS system. Leaving that one to repo CI rather than claiming it.

Icons and Screenshots

app.yaml/item.yaml already reference the canonical CDN paths (apps/ktn-enclosure-manager/icons/icon.svg, apps/ktn-enclosure-manager/screenshots/screenshot1-3.png). Please upload these sources to them:

Special Notes

  • Device access (/dev/sg*), and how it compares. For scale: scrutiny is merged in this train and does closely related work; it is set_privileged(true), declares 14 capabilities, and bind-mounts all of /dev plus /run/udev. This app is not privileged, declares 2 capabilities (SETUID, SETGID), has host_mounts: [], and passes through only the SCSI generic nodes the user names, with an rw cgroup grant rather than rwm. Every telemetry read works on a read-only device open (sg_ses --readonly), so granting :r is a supported monitoring-only deployment where Identify returns a permission error and nothing else changes. The w exists solely for the IDENT LED SEND DIAGNOSTIC, which addresses the enclosure processor, never disk data. No code path powers a drive off, resets a PHY, or touches a fault LED. SECURITY.md documents the boundary.
  • Privilege model. The container starts as root so a ~200-line helper can bind a unix socket and open the enclosure device; the entrypoint drops the web process to uid/gid 1000 with setpriv. That is why SETUID/SETGID are added back over cap_drop: ALL, and they are the only two. The helper accepts three operations (identify_on, identify_off, read-only SES page read) and cannot be passed a path or a command. Default AppArmor profile, no /sys mount.
  • Conformance fixes in this update. The storage group was missing $ref: normalize/ix_volume and the ACL block, which every other app in the train carries; that is fixed and the canonical block is now used. The healthcheck used use_built_in(), which effectively nothing in the community train does; it is now set_test("tcp", ...), which needs no curl in the image. The device is now a host/container pair list like other device-passthrough apps rather than a single required string, so CI can pass devices: [] instead of a placeholder node. The standard permissions container replaces a manual chown instruction. Port default moved into the catalog band (30842). Group names and descriptions now follow the house convention.
  • First-time setup. No default credentials; the first visit to the Web UI creates the administrator account (surfaced as an x-notes warning).
  • No shelf attached. The app degrades cleanly (renders, starts, reports no enclosure), which is what CI exercises since runners have no SAS hardware.
  • Hardware honesty. This version runs on my own 15-bay SES shelf under TrueNAS SCALE 25.10, but that is N=1 hardware with a single maintainer, and a pinned issue on the app repo collects reports for other enclosures. Where a shelf reports element/slot numbering the app cannot map unambiguously it refuses to act rather than guess, so an Identify request either addresses the right bay or returns an error naming what the enclosure reported.
  • Packaged path vs. deployed path. I run this via Install-via-YAML rather than through the catalog package, so the packaged path is render- and install-verified (ci.py, both test files, published image) rather than deploy-verified on an appliance.

Checklist

  • App runs successfully locally
  • Only modified files under /ix-dev/ or /library/
  • README.md included
  • Multiple test scenarios tested
  • questions.yaml has clear descriptions and follows structure of existing apps
  • All automated CI checks pass

@MechanicalCoderX

Copy link
Copy Markdown
Author

Saw this went to draft. What do you want changed first? Or name an app you think does it right and I'll go through mine against that.

I'd expect the /dev/sg* access to be the part you want to look hardest at. I'm doing the changes myself, so short is fine.

KTN Enclosure Manager is a drive-bay map, chassis telemetry and IDENT LED
control panel for SES disk shelves attached to TrueNAS SCALE. TrueNAS gates
its built-in enclosure UI behind iX hardware, so a third-party shelf reports
Enclosure Unavailable; this fills that gap without patching middleware.
Telemetry runs entirely on read-only device opens. The only write the app can
perform is lighting a drive bay Identify LED, issued by a small root helper
over a unix socket. The container is not privileged, drops ALL capabilities
and adds back only SETUID and SETGID for the setpriv drop to uid 1000, keeps
the default AppArmor profile, and mounts no host path other than its own data
directory.
App version 1.5.5, catalog version 1.0.0.
@MechanicalCoderX
MechanicalCoderXforce-pushed the add-ktn-enclosure-manager branch from 109037f to a61d190CompareAugust 31, 2026 03:36
@MechanicalCoderX
MechanicalCoderX marked this pull request as ready for review September 1, 2026 00:12
@MechanicalCoderX

Copy link
Copy Markdown
Author

I read the merged community apps and fixed this one to match. Worst thing I found was mine. The storage group had no normalize/ix_volume ref. On a default ixVolume install ix_volumes comes back empty, so no dataset. Confirmed against middleware on 25.10.6, before and after.

Squashed to one commit on current master and force-pushed. Old history's gone. It's ready to look at.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@MechanicalCoderX@stavros-k
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(community): add ktn-enclosure-manager app - #5679

Open
MechanicalCoderX wants to merge 1 commit into
truenas:masterfrom
MechanicalCoderX:add-ktn-enclosure-manager
Open

feat(community): add ktn-enclosure-manager app#5679
MechanicalCoderX wants to merge 1 commit into
truenas:masterfrom
MechanicalCoderX:add-ktn-enclosure-manager

Conversation

@MechanicalCoderX

@MechanicalCoderXMechanicalCoderX commented Aug 27, 2026

Copy link
Copy Markdown

App Addition

  • I have opened an issue to discuss this app addition before submitting this pull request.

AI

  • Part or All of this PR was generated by an LLM.

Description

Adds KTN Enclosure Manager to the community train.

KTN Enclosure Manager gives TrueNAS SCALE users a physical drive-bay map, chassis telemetry (temperatures, fans, PSUs) and IDENT LED control for SES-capable SAS disk shelves (JBODs).

TrueNAS gates its built-in enclosure UI behind iX hardware, so View Enclosure reports "Enclosure Unavailable" on a community system with a third-party shelf. This app fills that gap without patching middleware or spoofing hardware identity. It answers "which physical bay is this failing disk actually in?" With an optional TrueNAS API key it adds pool, vdev, ZFS error and SMART context per bay.

Updated 2026-08-30: the branch was rebased onto current master and squashed to a single commit. The previous history carried version bumps (1.3.2 through 1.5.5) for an app that has never been in the catalog, which was noise. I also went back through the package against merged community apps and fixed a set of conformance gaps; the notable ones are listed under Special Notes.

App Information

Testing

Tested locally with:

  • basic-values.yaml (ix_volume storage, authentication required)
  • hostpath-anon-values.yaml (host_path storage, open dashboard, Identify still gated)

Both render and install to a healthy container via .github/scripts/ci.py against the published 1.5.5 image, exit 0. Also run clean: port_validation.py (exit 0) and generate_metadata.py (exit 0, and byte-idempotent - the tree is unchanged after a full cycle).

apps_dev_charts_validate I could not run here: the validation image imports middleware, which needs libzfs, and my build host is not a ZFS system. Leaving that one to repo CI rather than claiming it.

Icons and Screenshots

app.yaml/item.yaml already reference the canonical CDN paths (apps/ktn-enclosure-manager/icons/icon.svg, apps/ktn-enclosure-manager/screenshots/screenshot1-3.png). Please upload these sources to them:

Special Notes

  • Device access (/dev/sg*), and how it compares. For scale: scrutiny is merged in this train and does closely related work; it is set_privileged(true), declares 14 capabilities, and bind-mounts all of /dev plus /run/udev. This app is not privileged, declares 2 capabilities (SETUID, SETGID), has host_mounts: [], and passes through only the SCSI generic nodes the user names, with an rw cgroup grant rather than rwm. Every telemetry read works on a read-only device open (sg_ses --readonly), so granting :r is a supported monitoring-only deployment where Identify returns a permission error and nothing else changes. The w exists solely for the IDENT LED SEND DIAGNOSTIC, which addresses the enclosure processor, never disk data. No code path powers a drive off, resets a PHY, or touches a fault LED. SECURITY.md documents the boundary.
  • Privilege model. The container starts as root so a ~200-line helper can bind a unix socket and open the enclosure device; the entrypoint drops the web process to uid/gid 1000 with setpriv. That is why SETUID/SETGID are added back over cap_drop: ALL, and they are the only two. The helper accepts three operations (identify_on, identify_off, read-only SES page read) and cannot be passed a path or a command. Default AppArmor profile, no /sys mount.
  • Conformance fixes in this update. The storage group was missing $ref: normalize/ix_volume and the ACL block, which every other app in the train carries; that is fixed and the canonical block is now used. The healthcheck used use_built_in(), which effectively nothing in the community train does; it is now set_test("tcp", ...), which needs no curl in the image. The device is now a host/container pair list like other device-passthrough apps rather than a single required string, so CI can pass devices: [] instead of a placeholder node. The standard permissions container replaces a manual chown instruction. Port default moved into the catalog band (30842). Group names and descriptions now follow the house convention.
  • First-time setup. No default credentials; the first visit to the Web UI creates the administrator account (surfaced as an x-notes warning).
  • No shelf attached. The app degrades cleanly (renders, starts, reports no enclosure), which is what CI exercises since runners have no SAS hardware.
  • Hardware honesty. This version runs on my own 15-bay SES shelf under TrueNAS SCALE 25.10, but that is N=1 hardware with a single maintainer, and a pinned issue on the app repo collects reports for other enclosures. Where a shelf reports element/slot numbering the app cannot map unambiguously it refuses to act rather than guess, so an Identify request either addresses the right bay or returns an error naming what the enclosure reported.
  • Packaged path vs. deployed path. I run this via Install-via-YAML rather than through the catalog package, so the packaged path is render- and install-verified (ci.py, both test files, published image) rather than deploy-verified on an appliance.

Checklist

  • App runs successfully locally
  • Only modified files under /ix-dev/ or /library/
  • README.md included
  • Multiple test scenarios tested
  • questions.yaml has clear descriptions and follows structure of existing apps
  • All automated CI checks pass

@MechanicalCoderX

Copy link
Copy Markdown
Author

Saw this went to draft. What do you want changed first? Or name an app you think does it right and I'll go through mine against that.

I'd expect the /dev/sg* access to be the part you want to look hardest at. I'm doing the changes myself, so short is fine.

KTN Enclosure Manager is a drive-bay map, chassis telemetry and IDENT LED
control panel for SES disk shelves attached to TrueNAS SCALE. TrueNAS gates
its built-in enclosure UI behind iX hardware, so a third-party shelf reports
Enclosure Unavailable; this fills that gap without patching middleware.
Telemetry runs entirely on read-only device opens. The only write the app can
perform is lighting a drive bay Identify LED, issued by a small root helper
over a unix socket. The container is not privileged, drops ALL capabilities
and adds back only SETUID and SETGID for the setpriv drop to uid 1000, keeps
the default AppArmor profile, and mounts no host path other than its own data
directory.
App version 1.5.5, catalog version 1.0.0.
@MechanicalCoderX
MechanicalCoderXforce-pushed the add-ktn-enclosure-manager branch from 109037f to a61d190CompareAugust 31, 2026 03:36
@MechanicalCoderX
MechanicalCoderX marked this pull request as ready for review September 1, 2026 00:12
@MechanicalCoderX

Copy link
Copy Markdown
Author

I read the merged community apps and fixed this one to match. Worst thing I found was mine. The storage group had no normalize/ix_volume ref. On a default ixVolume install ix_volumes comes back empty, so no dataset. Confirmed against middleware on 25.10.6, before and after.

Squashed to one commit on current master and force-pushed. Old history's gone. It's ready to look at.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@MechanicalCoderX@stavros-k
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(community): add ktn-enclosure-manager app - #5679

Open
MechanicalCoderX wants to merge 1 commit into
truenas:masterfrom
MechanicalCoderX:add-ktn-enclosure-manager
Open

feat(community): add ktn-enclosure-manager app#5679
MechanicalCoderX wants to merge 1 commit into
truenas:masterfrom
MechanicalCoderX:add-ktn-enclosure-manager

Conversation

@MechanicalCoderX

@MechanicalCoderXMechanicalCoderX commented Aug 27, 2026

Copy link
Copy Markdown

App Addition

  • I have opened an issue to discuss this app addition before submitting this pull request.

AI

  • Part or All of this PR was generated by an LLM.

Description

Adds KTN Enclosure Manager to the community train.

KTN Enclosure Manager gives TrueNAS SCALE users a physical drive-bay map, chassis telemetry (temperatures, fans, PSUs) and IDENT LED control for SES-capable SAS disk shelves (JBODs).

TrueNAS gates its built-in enclosure UI behind iX hardware, so View Enclosure reports "Enclosure Unavailable" on a community system with a third-party shelf. This app fills that gap without patching middleware or spoofing hardware identity. It answers "which physical bay is this failing disk actually in?" With an optional TrueNAS API key it adds pool, vdev, ZFS error and SMART context per bay.

Updated 2026-08-30: the branch was rebased onto current master and squashed to a single commit. The previous history carried version bumps (1.3.2 through 1.5.5) for an app that has never been in the catalog, which was noise. I also went back through the package against merged community apps and fixed a set of conformance gaps; the notable ones are listed under Special Notes.

App Information

Testing

Tested locally with:

  • basic-values.yaml (ix_volume storage, authentication required)
  • hostpath-anon-values.yaml (host_path storage, open dashboard, Identify still gated)

Both render and install to a healthy container via .github/scripts/ci.py against the published 1.5.5 image, exit 0. Also run clean: port_validation.py (exit 0) and generate_metadata.py (exit 0, and byte-idempotent - the tree is unchanged after a full cycle).

apps_dev_charts_validate I could not run here: the validation image imports middleware, which needs libzfs, and my build host is not a ZFS system. Leaving that one to repo CI rather than claiming it.

Icons and Screenshots

app.yaml/item.yaml already reference the canonical CDN paths (apps/ktn-enclosure-manager/icons/icon.svg, apps/ktn-enclosure-manager/screenshots/screenshot1-3.png). Please upload these sources to them:

Special Notes

  • Device access (/dev/sg*), and how it compares. For scale: scrutiny is merged in this train and does closely related work; it is set_privileged(true), declares 14 capabilities, and bind-mounts all of /dev plus /run/udev. This app is not privileged, declares 2 capabilities (SETUID, SETGID), has host_mounts: [], and passes through only the SCSI generic nodes the user names, with an rw cgroup grant rather than rwm. Every telemetry read works on a read-only device open (sg_ses --readonly), so granting :r is a supported monitoring-only deployment where Identify returns a permission error and nothing else changes. The w exists solely for the IDENT LED SEND DIAGNOSTIC, which addresses the enclosure processor, never disk data. No code path powers a drive off, resets a PHY, or touches a fault LED. SECURITY.md documents the boundary.
  • Privilege model. The container starts as root so a ~200-line helper can bind a unix socket and open the enclosure device; the entrypoint drops the web process to uid/gid 1000 with setpriv. That is why SETUID/SETGID are added back over cap_drop: ALL, and they are the only two. The helper accepts three operations (identify_on, identify_off, read-only SES page read) and cannot be passed a path or a command. Default AppArmor profile, no /sys mount.
  • Conformance fixes in this update. The storage group was missing $ref: normalize/ix_volume and the ACL block, which every other app in the train carries; that is fixed and the canonical block is now used. The healthcheck used use_built_in(), which effectively nothing in the community train does; it is now set_test("tcp", ...), which needs no curl in the image. The device is now a host/container pair list like other device-passthrough apps rather than a single required string, so CI can pass devices: [] instead of a placeholder node. The standard permissions container replaces a manual chown instruction. Port default moved into the catalog band (30842). Group names and descriptions now follow the house convention.
  • First-time setup. No default credentials; the first visit to the Web UI creates the administrator account (surfaced as an x-notes warning).
  • No shelf attached. The app degrades cleanly (renders, starts, reports no enclosure), which is what CI exercises since runners have no SAS hardware.
  • Hardware honesty. This version runs on my own 15-bay SES shelf under TrueNAS SCALE 25.10, but that is N=1 hardware with a single maintainer, and a pinned issue on the app repo collects reports for other enclosures. Where a shelf reports element/slot numbering the app cannot map unambiguously it refuses to act rather than guess, so an Identify request either addresses the right bay or returns an error naming what the enclosure reported.
  • Packaged path vs. deployed path. I run this via Install-via-YAML rather than through the catalog package, so the packaged path is render- and install-verified (ci.py, both test files, published image) rather than deploy-verified on an appliance.

Checklist

  • App runs successfully locally
  • Only modified files under /ix-dev/ or /library/
  • README.md included
  • Multiple test scenarios tested
  • questions.yaml has clear descriptions and follows structure of existing apps
  • All automated CI checks pass

@MechanicalCoderX

Copy link
Copy Markdown
Author

Saw this went to draft. What do you want changed first? Or name an app you think does it right and I'll go through mine against that.

I'd expect the /dev/sg* access to be the part you want to look hardest at. I'm doing the changes myself, so short is fine.

KTN Enclosure Manager is a drive-bay map, chassis telemetry and IDENT LED
control panel for SES disk shelves attached to TrueNAS SCALE. TrueNAS gates
its built-in enclosure UI behind iX hardware, so a third-party shelf reports
Enclosure Unavailable; this fills that gap without patching middleware.
Telemetry runs entirely on read-only device opens. The only write the app can
perform is lighting a drive bay Identify LED, issued by a small root helper
over a unix socket. The container is not privileged, drops ALL capabilities
and adds back only SETUID and SETGID for the setpriv drop to uid 1000, keeps
the default AppArmor profile, and mounts no host path other than its own data
directory.
App version 1.5.5, catalog version 1.0.0.
@MechanicalCoderX
MechanicalCoderXforce-pushed the add-ktn-enclosure-manager branch from 109037f to a61d190CompareAugust 31, 2026 03:36
@MechanicalCoderX
MechanicalCoderX marked this pull request as ready for review September 1, 2026 00:12
@MechanicalCoderX

Copy link
Copy Markdown
Author

I read the merged community apps and fixed this one to match. Worst thing I found was mine. The storage group had no normalize/ix_volume ref. On a default ixVolume install ix_volumes comes back empty, so no dataset. Confirmed against middleware on 25.10.6, before and after.

Squashed to one commit on current master and force-pushed. Old history's gone. It's ready to look at.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@MechanicalCoderX@stavros-k
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(community): add ktn-enclosure-manager app - #5679

Open
MechanicalCoderX wants to merge 1 commit into
truenas:masterfrom
MechanicalCoderX:add-ktn-enclosure-manager
Open

feat(community): add ktn-enclosure-manager app#5679
MechanicalCoderX wants to merge 1 commit into
truenas:masterfrom
MechanicalCoderX:add-ktn-enclosure-manager

Conversation

@MechanicalCoderX

@MechanicalCoderXMechanicalCoderX commented Aug 27, 2026

Copy link
Copy Markdown

App Addition

  • I have opened an issue to discuss this app addition before submitting this pull request.

AI

  • Part or All of this PR was generated by an LLM.

Description

Adds KTN Enclosure Manager to the community train.

KTN Enclosure Manager gives TrueNAS SCALE users a physical drive-bay map, chassis telemetry (temperatures, fans, PSUs) and IDENT LED control for SES-capable SAS disk shelves (JBODs).

TrueNAS gates its built-in enclosure UI behind iX hardware, so View Enclosure reports "Enclosure Unavailable" on a community system with a third-party shelf. This app fills that gap without patching middleware or spoofing hardware identity. It answers "which physical bay is this failing disk actually in?" With an optional TrueNAS API key it adds pool, vdev, ZFS error and SMART context per bay.

Updated 2026-08-30: the branch was rebased onto current master and squashed to a single commit. The previous history carried version bumps (1.3.2 through 1.5.5) for an app that has never been in the catalog, which was noise. I also went back through the package against merged community apps and fixed a set of conformance gaps; the notable ones are listed under Special Notes.

App Information

Testing

Tested locally with:

  • basic-values.yaml (ix_volume storage, authentication required)
  • hostpath-anon-values.yaml (host_path storage, open dashboard, Identify still gated)

Both render and install to a healthy container via .github/scripts/ci.py against the published 1.5.5 image, exit 0. Also run clean: port_validation.py (exit 0) and generate_metadata.py (exit 0, and byte-idempotent - the tree is unchanged after a full cycle).

apps_dev_charts_validate I could not run here: the validation image imports middleware, which needs libzfs, and my build host is not a ZFS system. Leaving that one to repo CI rather than claiming it.

Icons and Screenshots

app.yaml/item.yaml already reference the canonical CDN paths (apps/ktn-enclosure-manager/icons/icon.svg, apps/ktn-enclosure-manager/screenshots/screenshot1-3.png). Please upload these sources to them:

Special Notes

  • Device access (/dev/sg*), and how it compares. For scale: scrutiny is merged in this train and does closely related work; it is set_privileged(true), declares 14 capabilities, and bind-mounts all of /dev plus /run/udev. This app is not privileged, declares 2 capabilities (SETUID, SETGID), has host_mounts: [], and passes through only the SCSI generic nodes the user names, with an rw cgroup grant rather than rwm. Every telemetry read works on a read-only device open (sg_ses --readonly), so granting :r is a supported monitoring-only deployment where Identify returns a permission error and nothing else changes. The w exists solely for the IDENT LED SEND DIAGNOSTIC, which addresses the enclosure processor, never disk data. No code path powers a drive off, resets a PHY, or touches a fault LED. SECURITY.md documents the boundary.
  • Privilege model. The container starts as root so a ~200-line helper can bind a unix socket and open the enclosure device; the entrypoint drops the web process to uid/gid 1000 with setpriv. That is why SETUID/SETGID are added back over cap_drop: ALL, and they are the only two. The helper accepts three operations (identify_on, identify_off, read-only SES page read) and cannot be passed a path or a command. Default AppArmor profile, no /sys mount.
  • Conformance fixes in this update. The storage group was missing $ref: normalize/ix_volume and the ACL block, which every other app in the train carries; that is fixed and the canonical block is now used. The healthcheck used use_built_in(), which effectively nothing in the community train does; it is now set_test("tcp", ...), which needs no curl in the image. The device is now a host/container pair list like other device-passthrough apps rather than a single required string, so CI can pass devices: [] instead of a placeholder node. The standard permissions container replaces a manual chown instruction. Port default moved into the catalog band (30842). Group names and descriptions now follow the house convention.
  • First-time setup. No default credentials; the first visit to the Web UI creates the administrator account (surfaced as an x-notes warning).
  • No shelf attached. The app degrades cleanly (renders, starts, reports no enclosure), which is what CI exercises since runners have no SAS hardware.
  • Hardware honesty. This version runs on my own 15-bay SES shelf under TrueNAS SCALE 25.10, but that is N=1 hardware with a single maintainer, and a pinned issue on the app repo collects reports for other enclosures. Where a shelf reports element/slot numbering the app cannot map unambiguously it refuses to act rather than guess, so an Identify request either addresses the right bay or returns an error naming what the enclosure reported.
  • Packaged path vs. deployed path. I run this via Install-via-YAML rather than through the catalog package, so the packaged path is render- and install-verified (ci.py, both test files, published image) rather than deploy-verified on an appliance.

Checklist

  • App runs successfully locally
  • Only modified files under /ix-dev/ or /library/
  • README.md included
  • Multiple test scenarios tested
  • questions.yaml has clear descriptions and follows structure of existing apps
  • All automated CI checks pass

@MechanicalCoderX

Copy link
Copy Markdown
Author

Saw this went to draft. What do you want changed first? Or name an app you think does it right and I'll go through mine against that.

I'd expect the /dev/sg* access to be the part you want to look hardest at. I'm doing the changes myself, so short is fine.

KTN Enclosure Manager is a drive-bay map, chassis telemetry and IDENT LED
control panel for SES disk shelves attached to TrueNAS SCALE. TrueNAS gates
its built-in enclosure UI behind iX hardware, so a third-party shelf reports
Enclosure Unavailable; this fills that gap without patching middleware.
Telemetry runs entirely on read-only device opens. The only write the app can
perform is lighting a drive bay Identify LED, issued by a small root helper
over a unix socket. The container is not privileged, drops ALL capabilities
and adds back only SETUID and SETGID for the setpriv drop to uid 1000, keeps
the default AppArmor profile, and mounts no host path other than its own data
directory.
App version 1.5.5, catalog version 1.0.0.
@MechanicalCoderX
MechanicalCoderXforce-pushed the add-ktn-enclosure-manager branch from 109037f to a61d190CompareAugust 31, 2026 03:36
@MechanicalCoderX
MechanicalCoderX marked this pull request as ready for review September 1, 2026 00:12
@MechanicalCoderX

Copy link
Copy Markdown
Author

I read the merged community apps and fixed this one to match. Worst thing I found was mine. The storage group had no normalize/ix_volume ref. On a default ixVolume install ix_volumes comes back empty, so no dataset. Confirmed against middleware on 25.10.6, before and after.

Squashed to one commit on current master and force-pushed. Old history's gone. It's ready to look at.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@MechanicalCoderX@stavros-k
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(community): add ktn-enclosure-manager app - #5679

Open
MechanicalCoderX wants to merge 1 commit into
truenas:masterfrom
MechanicalCoderX:add-ktn-enclosure-manager
Open

feat(community): add ktn-enclosure-manager app#5679
MechanicalCoderX wants to merge 1 commit into
truenas:masterfrom
MechanicalCoderX:add-ktn-enclosure-manager

Conversation

@MechanicalCoderX

@MechanicalCoderXMechanicalCoderX commented Aug 27, 2026

Copy link
Copy Markdown

App Addition

  • I have opened an issue to discuss this app addition before submitting this pull request.

AI

  • Part or All of this PR was generated by an LLM.

Description

Adds KTN Enclosure Manager to the community train.

KTN Enclosure Manager gives TrueNAS SCALE users a physical drive-bay map, chassis telemetry (temperatures, fans, PSUs) and IDENT LED control for SES-capable SAS disk shelves (JBODs).

TrueNAS gates its built-in enclosure UI behind iX hardware, so View Enclosure reports "Enclosure Unavailable" on a community system with a third-party shelf. This app fills that gap without patching middleware or spoofing hardware identity. It answers "which physical bay is this failing disk actually in?" With an optional TrueNAS API key it adds pool, vdev, ZFS error and SMART context per bay.

Updated 2026-08-30: the branch was rebased onto current master and squashed to a single commit. The previous history carried version bumps (1.3.2 through 1.5.5) for an app that has never been in the catalog, which was noise. I also went back through the package against merged community apps and fixed a set of conformance gaps; the notable ones are listed under Special Notes.

App Information

Testing

Tested locally with:

  • basic-values.yaml (ix_volume storage, authentication required)
  • hostpath-anon-values.yaml (host_path storage, open dashboard, Identify still gated)

Both render and install to a healthy container via .github/scripts/ci.py against the published 1.5.5 image, exit 0. Also run clean: port_validation.py (exit 0) and generate_metadata.py (exit 0, and byte-idempotent - the tree is unchanged after a full cycle).

apps_dev_charts_validate I could not run here: the validation image imports middleware, which needs libzfs, and my build host is not a ZFS system. Leaving that one to repo CI rather than claiming it.

Icons and Screenshots

app.yaml/item.yaml already reference the canonical CDN paths (apps/ktn-enclosure-manager/icons/icon.svg, apps/ktn-enclosure-manager/screenshots/screenshot1-3.png). Please upload these sources to them:

Special Notes

  • Device access (/dev/sg*), and how it compares. For scale: scrutiny is merged in this train and does closely related work; it is set_privileged(true), declares 14 capabilities, and bind-mounts all of /dev plus /run/udev. This app is not privileged, declares 2 capabilities (SETUID, SETGID), has host_mounts: [], and passes through only the SCSI generic nodes the user names, with an rw cgroup grant rather than rwm. Every telemetry read works on a read-only device open (sg_ses --readonly), so granting :r is a supported monitoring-only deployment where Identify returns a permission error and nothing else changes. The w exists solely for the IDENT LED SEND DIAGNOSTIC, which addresses the enclosure processor, never disk data. No code path powers a drive off, resets a PHY, or touches a fault LED. SECURITY.md documents the boundary.
  • Privilege model. The container starts as root so a ~200-line helper can bind a unix socket and open the enclosure device; the entrypoint drops the web process to uid/gid 1000 with setpriv. That is why SETUID/SETGID are added back over cap_drop: ALL, and they are the only two. The helper accepts three operations (identify_on, identify_off, read-only SES page read) and cannot be passed a path or a command. Default AppArmor profile, no /sys mount.
  • Conformance fixes in this update. The storage group was missing $ref: normalize/ix_volume and the ACL block, which every other app in the train carries; that is fixed and the canonical block is now used. The healthcheck used use_built_in(), which effectively nothing in the community train does; it is now set_test("tcp", ...), which needs no curl in the image. The device is now a host/container pair list like other device-passthrough apps rather than a single required string, so CI can pass devices: [] instead of a placeholder node. The standard permissions container replaces a manual chown instruction. Port default moved into the catalog band (30842). Group names and descriptions now follow the house convention.
  • First-time setup. No default credentials; the first visit to the Web UI creates the administrator account (surfaced as an x-notes warning).
  • No shelf attached. The app degrades cleanly (renders, starts, reports no enclosure), which is what CI exercises since runners have no SAS hardware.
  • Hardware honesty. This version runs on my own 15-bay SES shelf under TrueNAS SCALE 25.10, but that is N=1 hardware with a single maintainer, and a pinned issue on the app repo collects reports for other enclosures. Where a shelf reports element/slot numbering the app cannot map unambiguously it refuses to act rather than guess, so an Identify request either addresses the right bay or returns an error naming what the enclosure reported.
  • Packaged path vs. deployed path. I run this via Install-via-YAML rather than through the catalog package, so the packaged path is render- and install-verified (ci.py, both test files, published image) rather than deploy-verified on an appliance.

Checklist

  • App runs successfully locally
  • Only modified files under /ix-dev/ or /library/
  • README.md included
  • Multiple test scenarios tested
  • questions.yaml has clear descriptions and follows structure of existing apps
  • All automated CI checks pass

@MechanicalCoderX

Copy link
Copy Markdown
Author

Saw this went to draft. What do you want changed first? Or name an app you think does it right and I'll go through mine against that.

I'd expect the /dev/sg* access to be the part you want to look hardest at. I'm doing the changes myself, so short is fine.

KTN Enclosure Manager is a drive-bay map, chassis telemetry and IDENT LED
control panel for SES disk shelves attached to TrueNAS SCALE. TrueNAS gates
its built-in enclosure UI behind iX hardware, so a third-party shelf reports
Enclosure Unavailable; this fills that gap without patching middleware.
Telemetry runs entirely on read-only device opens. The only write the app can
perform is lighting a drive bay Identify LED, issued by a small root helper
over a unix socket. The container is not privileged, drops ALL capabilities
and adds back only SETUID and SETGID for the setpriv drop to uid 1000, keeps
the default AppArmor profile, and mounts no host path other than its own data
directory.
App version 1.5.5, catalog version 1.0.0.
@MechanicalCoderX
MechanicalCoderXforce-pushed the add-ktn-enclosure-manager branch from 109037f to a61d190CompareAugust 31, 2026 03:36
@MechanicalCoderX
MechanicalCoderX marked this pull request as ready for review September 1, 2026 00:12
@MechanicalCoderX

Copy link
Copy Markdown
Author

I read the merged community apps and fixed this one to match. Worst thing I found was mine. The storage group had no normalize/ix_volume ref. On a default ixVolume install ix_volumes comes back empty, so no dataset. Confirmed against middleware on 25.10.6, before and after.

Squashed to one commit on current master and force-pushed. Old history's gone. It's ready to look at.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@MechanicalCoderX@stavros-k
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(community): add ktn-enclosure-manager app - #5679

Open
MechanicalCoderX wants to merge 1 commit into
truenas:masterfrom
MechanicalCoderX:add-ktn-enclosure-manager
Open

feat(community): add ktn-enclosure-manager app#5679
MechanicalCoderX wants to merge 1 commit into
truenas:masterfrom
MechanicalCoderX:add-ktn-enclosure-manager

Conversation

@MechanicalCoderX

@MechanicalCoderXMechanicalCoderX commented Aug 27, 2026

Copy link
Copy Markdown

App Addition

  • I have opened an issue to discuss this app addition before submitting this pull request.

AI

  • Part or All of this PR was generated by an LLM.

Description

Adds KTN Enclosure Manager to the community train.

KTN Enclosure Manager gives TrueNAS SCALE users a physical drive-bay map, chassis telemetry (temperatures, fans, PSUs) and IDENT LED control for SES-capable SAS disk shelves (JBODs).

TrueNAS gates its built-in enclosure UI behind iX hardware, so View Enclosure reports "Enclosure Unavailable" on a community system with a third-party shelf. This app fills that gap without patching middleware or spoofing hardware identity. It answers "which physical bay is this failing disk actually in?" With an optional TrueNAS API key it adds pool, vdev, ZFS error and SMART context per bay.

Updated 2026-08-30: the branch was rebased onto current master and squashed to a single commit. The previous history carried version bumps (1.3.2 through 1.5.5) for an app that has never been in the catalog, which was noise. I also went back through the package against merged community apps and fixed a set of conformance gaps; the notable ones are listed under Special Notes.

App Information

Testing

Tested locally with:

  • basic-values.yaml (ix_volume storage, authentication required)
  • hostpath-anon-values.yaml (host_path storage, open dashboard, Identify still gated)

Both render and install to a healthy container via .github/scripts/ci.py against the published 1.5.5 image, exit 0. Also run clean: port_validation.py (exit 0) and generate_metadata.py (exit 0, and byte-idempotent - the tree is unchanged after a full cycle).

apps_dev_charts_validate I could not run here: the validation image imports middleware, which needs libzfs, and my build host is not a ZFS system. Leaving that one to repo CI rather than claiming it.

Icons and Screenshots

app.yaml/item.yaml already reference the canonical CDN paths (apps/ktn-enclosure-manager/icons/icon.svg, apps/ktn-enclosure-manager/screenshots/screenshot1-3.png). Please upload these sources to them:

Special Notes

  • Device access (/dev/sg*), and how it compares. For scale: scrutiny is merged in this train and does closely related work; it is set_privileged(true), declares 14 capabilities, and bind-mounts all of /dev plus /run/udev. This app is not privileged, declares 2 capabilities (SETUID, SETGID), has host_mounts: [], and passes through only the SCSI generic nodes the user names, with an rw cgroup grant rather than rwm. Every telemetry read works on a read-only device open (sg_ses --readonly), so granting :r is a supported monitoring-only deployment where Identify returns a permission error and nothing else changes. The w exists solely for the IDENT LED SEND DIAGNOSTIC, which addresses the enclosure processor, never disk data. No code path powers a drive off, resets a PHY, or touches a fault LED. SECURITY.md documents the boundary.
  • Privilege model. The container starts as root so a ~200-line helper can bind a unix socket and open the enclosure device; the entrypoint drops the web process to uid/gid 1000 with setpriv. That is why SETUID/SETGID are added back over cap_drop: ALL, and they are the only two. The helper accepts three operations (identify_on, identify_off, read-only SES page read) and cannot be passed a path or a command. Default AppArmor profile, no /sys mount.
  • Conformance fixes in this update. The storage group was missing $ref: normalize/ix_volume and the ACL block, which every other app in the train carries; that is fixed and the canonical block is now used. The healthcheck used use_built_in(), which effectively nothing in the community train does; it is now set_test("tcp", ...), which needs no curl in the image. The device is now a host/container pair list like other device-passthrough apps rather than a single required string, so CI can pass devices: [] instead of a placeholder node. The standard permissions container replaces a manual chown instruction. Port default moved into the catalog band (30842). Group names and descriptions now follow the house convention.
  • First-time setup. No default credentials; the first visit to the Web UI creates the administrator account (surfaced as an x-notes warning).
  • No shelf attached. The app degrades cleanly (renders, starts, reports no enclosure), which is what CI exercises since runners have no SAS hardware.
  • Hardware honesty. This version runs on my own 15-bay SES shelf under TrueNAS SCALE 25.10, but that is N=1 hardware with a single maintainer, and a pinned issue on the app repo collects reports for other enclosures. Where a shelf reports element/slot numbering the app cannot map unambiguously it refuses to act rather than guess, so an Identify request either addresses the right bay or returns an error naming what the enclosure reported.
  • Packaged path vs. deployed path. I run this via Install-via-YAML rather than through the catalog package, so the packaged path is render- and install-verified (ci.py, both test files, published image) rather than deploy-verified on an appliance.

Checklist

  • App runs successfully locally
  • Only modified files under /ix-dev/ or /library/
  • README.md included
  • Multiple test scenarios tested
  • questions.yaml has clear descriptions and follows structure of existing apps
  • All automated CI checks pass

@MechanicalCoderX

Copy link
Copy Markdown
Author

Saw this went to draft. What do you want changed first? Or name an app you think does it right and I'll go through mine against that.

I'd expect the /dev/sg* access to be the part you want to look hardest at. I'm doing the changes myself, so short is fine.

KTN Enclosure Manager is a drive-bay map, chassis telemetry and IDENT LED
control panel for SES disk shelves attached to TrueNAS SCALE. TrueNAS gates
its built-in enclosure UI behind iX hardware, so a third-party shelf reports
Enclosure Unavailable; this fills that gap without patching middleware.
Telemetry runs entirely on read-only device opens. The only write the app can
perform is lighting a drive bay Identify LED, issued by a small root helper
over a unix socket. The container is not privileged, drops ALL capabilities
and adds back only SETUID and SETGID for the setpriv drop to uid 1000, keeps
the default AppArmor profile, and mounts no host path other than its own data
directory.
App version 1.5.5, catalog version 1.0.0.
@MechanicalCoderX
MechanicalCoderXforce-pushed the add-ktn-enclosure-manager branch from 109037f to a61d190CompareAugust 31, 2026 03:36
@MechanicalCoderX
MechanicalCoderX marked this pull request as ready for review September 1, 2026 00:12
@MechanicalCoderX

Copy link
Copy Markdown
Author

I read the merged community apps and fixed this one to match. Worst thing I found was mine. The storage group had no normalize/ix_volume ref. On a default ixVolume install ix_volumes comes back empty, so no dataset. Confirmed against middleware on 25.10.6, before and after.

Squashed to one commit on current master and force-pushed. Old history's gone. It's ready to look at.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@MechanicalCoderX@stavros-k
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(community): add ktn-enclosure-manager app - #5679

Open
MechanicalCoderX wants to merge 1 commit into
truenas:masterfrom
MechanicalCoderX:add-ktn-enclosure-manager
Open

feat(community): add ktn-enclosure-manager app#5679
MechanicalCoderX wants to merge 1 commit into
truenas:masterfrom
MechanicalCoderX:add-ktn-enclosure-manager

Conversation

@MechanicalCoderX

@MechanicalCoderXMechanicalCoderX commented Aug 27, 2026

Copy link
Copy Markdown

App Addition

  • I have opened an issue to discuss this app addition before submitting this pull request.

AI

  • Part or All of this PR was generated by an LLM.

Description

Adds KTN Enclosure Manager to the community train.

KTN Enclosure Manager gives TrueNAS SCALE users a physical drive-bay map, chassis telemetry (temperatures, fans, PSUs) and IDENT LED control for SES-capable SAS disk shelves (JBODs).

TrueNAS gates its built-in enclosure UI behind iX hardware, so View Enclosure reports "Enclosure Unavailable" on a community system with a third-party shelf. This app fills that gap without patching middleware or spoofing hardware identity. It answers "which physical bay is this failing disk actually in?" With an optional TrueNAS API key it adds pool, vdev, ZFS error and SMART context per bay.

Updated 2026-08-30: the branch was rebased onto current master and squashed to a single commit. The previous history carried version bumps (1.3.2 through 1.5.5) for an app that has never been in the catalog, which was noise. I also went back through the package against merged community apps and fixed a set of conformance gaps; the notable ones are listed under Special Notes.

App Information

Testing

Tested locally with:

  • basic-values.yaml (ix_volume storage, authentication required)
  • hostpath-anon-values.yaml (host_path storage, open dashboard, Identify still gated)

Both render and install to a healthy container via .github/scripts/ci.py against the published 1.5.5 image, exit 0. Also run clean: port_validation.py (exit 0) and generate_metadata.py (exit 0, and byte-idempotent - the tree is unchanged after a full cycle).

apps_dev_charts_validate I could not run here: the validation image imports middleware, which needs libzfs, and my build host is not a ZFS system. Leaving that one to repo CI rather than claiming it.

Icons and Screenshots

app.yaml/item.yaml already reference the canonical CDN paths (apps/ktn-enclosure-manager/icons/icon.svg, apps/ktn-enclosure-manager/screenshots/screenshot1-3.png). Please upload these sources to them:

Special Notes

  • Device access (/dev/sg*), and how it compares. For scale: scrutiny is merged in this train and does closely related work; it is set_privileged(true), declares 14 capabilities, and bind-mounts all of /dev plus /run/udev. This app is not privileged, declares 2 capabilities (SETUID, SETGID), has host_mounts: [], and passes through only the SCSI generic nodes the user names, with an rw cgroup grant rather than rwm. Every telemetry read works on a read-only device open (sg_ses --readonly), so granting :r is a supported monitoring-only deployment where Identify returns a permission error and nothing else changes. The w exists solely for the IDENT LED SEND DIAGNOSTIC, which addresses the enclosure processor, never disk data. No code path powers a drive off, resets a PHY, or touches a fault LED. SECURITY.md documents the boundary.
  • Privilege model. The container starts as root so a ~200-line helper can bind a unix socket and open the enclosure device; the entrypoint drops the web process to uid/gid 1000 with setpriv. That is why SETUID/SETGID are added back over cap_drop: ALL, and they are the only two. The helper accepts three operations (identify_on, identify_off, read-only SES page read) and cannot be passed a path or a command. Default AppArmor profile, no /sys mount.
  • Conformance fixes in this update. The storage group was missing $ref: normalize/ix_volume and the ACL block, which every other app in the train carries; that is fixed and the canonical block is now used. The healthcheck used use_built_in(), which effectively nothing in the community train does; it is now set_test("tcp", ...), which needs no curl in the image. The device is now a host/container pair list like other device-passthrough apps rather than a single required string, so CI can pass devices: [] instead of a placeholder node. The standard permissions container replaces a manual chown instruction. Port default moved into the catalog band (30842). Group names and descriptions now follow the house convention.
  • First-time setup. No default credentials; the first visit to the Web UI creates the administrator account (surfaced as an x-notes warning).
  • No shelf attached. The app degrades cleanly (renders, starts, reports no enclosure), which is what CI exercises since runners have no SAS hardware.
  • Hardware honesty. This version runs on my own 15-bay SES shelf under TrueNAS SCALE 25.10, but that is N=1 hardware with a single maintainer, and a pinned issue on the app repo collects reports for other enclosures. Where a shelf reports element/slot numbering the app cannot map unambiguously it refuses to act rather than guess, so an Identify request either addresses the right bay or returns an error naming what the enclosure reported.
  • Packaged path vs. deployed path. I run this via Install-via-YAML rather than through the catalog package, so the packaged path is render- and install-verified (ci.py, both test files, published image) rather than deploy-verified on an appliance.

Checklist

  • App runs successfully locally
  • Only modified files under /ix-dev/ or /library/
  • README.md included
  • Multiple test scenarios tested
  • questions.yaml has clear descriptions and follows structure of existing apps
  • All automated CI checks pass

@MechanicalCoderX

Copy link
Copy Markdown
Author

Saw this went to draft. What do you want changed first? Or name an app you think does it right and I'll go through mine against that.

I'd expect the /dev/sg* access to be the part you want to look hardest at. I'm doing the changes myself, so short is fine.

KTN Enclosure Manager is a drive-bay map, chassis telemetry and IDENT LED
control panel for SES disk shelves attached to TrueNAS SCALE. TrueNAS gates
its built-in enclosure UI behind iX hardware, so a third-party shelf reports
Enclosure Unavailable; this fills that gap without patching middleware.
Telemetry runs entirely on read-only device opens. The only write the app can
perform is lighting a drive bay Identify LED, issued by a small root helper
over a unix socket. The container is not privileged, drops ALL capabilities
and adds back only SETUID and SETGID for the setpriv drop to uid 1000, keeps
the default AppArmor profile, and mounts no host path other than its own data
directory.
App version 1.5.5, catalog version 1.0.0.
@MechanicalCoderX
MechanicalCoderXforce-pushed the add-ktn-enclosure-manager branch from 109037f to a61d190CompareAugust 31, 2026 03:36
@MechanicalCoderX
MechanicalCoderX marked this pull request as ready for review September 1, 2026 00:12
@MechanicalCoderX

Copy link
Copy Markdown
Author

I read the merged community apps and fixed this one to match. Worst thing I found was mine. The storage group had no normalize/ix_volume ref. On a default ixVolume install ix_volumes comes back empty, so no dataset. Confirmed against middleware on 25.10.6, before and after.

Squashed to one commit on current master and force-pushed. Old history's gone. It's ready to look at.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@MechanicalCoderX@stavros-k