{"id":501,"date":"2026-05-18T23:59:58","date_gmt":"2026-05-18T15:59:58","guid":{"rendered":"https:\/\/cliffordjuan.com\/?p=501"},"modified":"2026-05-22T23:11:53","modified_gmt":"2026-05-22T15:11:53","slug":"adding-a-zfs-management-module-to-cockpit-on-rhel-9-pitfalls-and-fixes","status":"publish","type":"post","link":"https:\/\/cliffordjuan.com\/index.php\/2026\/05\/18\/adding-a-zfs-management-module-to-cockpit-on-rhel-9-pitfalls-and-fixes\/","title":{"rendered":"Adding a ZFS Management Module to Cockpit on RHEL 9: Pitfalls and Fixes"},"content":{"rendered":"\n<p>Building a robust storage web interface requires tying together multiple infrastructure layers. Recently, I set out to integrate the&nbsp;<a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/45Drives\/cockpit-zfs\" target=\"_blank\">45Drives cockpit-zfs<\/a>&nbsp;module into Red Hat Enterprise Linux (RHEL) 9. While the Cockpit platform makes UI extensions straightforward, RHEL 9\u2019s strict enterprise packaging boundaries threw a few roadblocks my way. Here is a breakdown of the challenges I encountered during the dependency and build phases, and exactly how I resolved them.<\/p>\n\n\n\n<hr class=\"wp-block-separator is-style-default\"\/>\n\n\n\n<p class=\"has-medium-font-size\">Challenge 1: The Invisible Perl Dependency (<code>perl(IPC::Run)<\/code>)<\/p>\n\n\n\n<p><span style=\"text-decoration: underline;\">The Symptom<\/span><\/p>\n\n\n\n<p>While pulling down build tools like&nbsp;<code><strong>moreutils<\/strong><\/code>&nbsp;from the EPEL (Extra Packages for Enterprise Linux) repository, the installation halted with a frustrating error:<\/p>\n\n\n\n<pre class=\"wp-block-code has-cyan-bluish-gray-background-color has-background\"><code>Error: Problem: cannot install the best candidate for the job\n  - nothing provides perl(IPC::Run) needed by moreutils-0.68-1.el9.x86_64<\/code><\/pre>\n\n\n\n<p><span style=\"text-decoration: underline;\">The Root Cause<\/span><\/p>\n\n\n\n<p>Red Hat splits packages into different functional repositories to keep the core OS lean. The&nbsp;<code><strong>perl-IPC-Run<\/strong><\/code>&nbsp;library is designated as a development utility. Therefore, it is isolated inside Red Hat\u2019s&nbsp;<strong>CodeReady Linux Builder (CRB)<\/strong>&nbsp;repository. EPEL assumes CRB is enabled, but on standard RHEL 9 installations, CRB is turned off by default.Furthermore, even after activating the subscription repository, local&nbsp;<code>dnf<\/code>&nbsp;metadata caching can cause the system to ignore the newly opened pipeline.<\/p>\n\n\n\n<p><span style=\"text-decoration: underline;\">The Fix<\/span><\/p>\n\n\n\n<p>To bypass the broken cache and force DNF to recognize the development channel, I explicitly invoked the CRB repository flag directly during the package installation:<\/p>\n\n\n\n<pre class=\"wp-block-code has-cyan-bluish-gray-background-color has-background\"><code>dnf install moreutils --enablerepo=codeready-builder-for-rhel-9-x86_64-rpms<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image\"><img src=\"https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image.png\" alt=\"\"\/><\/figure>\n\n\n\n<hr class=\"wp-block-separator is-style-default\"\/>\n\n\n\n<p class=\"has-medium-font-size\">Challenge 2: Provisioning the Yarn Build Tool Engine<\/p>\n\n\n\n<p><span style=\"text-decoration: underline;\">The Symptom<\/span><\/p>\n\n\n\n<p>The&nbsp;<code>co<strong>ckpit-zfs<\/strong><\/code>&nbsp;project requires&nbsp;<code>yarn<\/code>&nbsp;to compile its frontend assets. However, running a standard&nbsp;<code><strong>dnf install yarn<\/strong><\/code>&nbsp;returns no matching packages on a fresh RHEL 9 deployment.<\/p>\n\n\n\n<p><span style=\"text-decoration: underline;\">The Root Cause<\/span><\/p>\n\n\n\n<p>Yarn is not included in the standard RHEL 9 core runtime or application streams.The FixInstead of cluttering the system with external, third-party package repositories that might break during future OS minor-version upgrades, I leveraged RHEL 9\u2019s native Node.js ecosystem.By pulling Node.js from the standard AppStream, I used the Node Package Manager (<code><strong>npm<\/strong><\/code>) to safely anchor Yarn globally:<\/p>\n\n\n\n<pre class=\"wp-block-code has-cyan-bluish-gray-background-color has-background\"><code># 1. Install Node.js and npm from the default AppStream\ndnf install nodejs npm -y\n\n# 2. Deploy Yarn globally via npm\nnpm install -g yarn\n\n# 3. Grab jq from EPEL to satisfy the remaining build scripts\ndnf install jq -y<\/code><\/pre>\n\n\n\n<p><span style=\"text-decoration: underline;\">The Home Stretch<\/span><\/p>\n\n\n\n<p>With the backend packaging dependencies unlocked and the frontend JavaScript engines correctly injected, the&nbsp;<code><strong>cockpit-zfs<\/strong><\/code>&nbsp;source code compiled seamlessly.Navigating into the repository and executing the build automation now completes without a hitch:<\/p>\n\n\n\n<pre class=\"wp-block-code has-cyan-bluish-gray-background-color has-background\"><code>make &amp;&amp; make install<\/code><\/pre>\n\n\n\n<p><span style=\"text-decoration: underline;\">Key Takeaway<\/span><\/p>\n\n\n\n<p>When working with cutting-edge or community-maintained web UIs on enterprise distributions like RHEL 9,&nbsp;<strong>never assume all dependencies live in the standard repositories<\/strong>. Always look to the CodeReady Linux Builder channel for missing libraries, and utilize language-native package managers (<strong><code>npm<\/code>\/<code>yarn<\/code><\/strong>) to bridge gaps without breaking system stability.<\/p>\n\n\n\n<hr class=\"wp-block-separator is-style-default\"\/>\n\n\n\n<p class=\"has-medium-font-size\">The Final Step: Activating the Module<\/p>\n\n\n\n<p>After the installation completes successfully, Cockpit needs a quick refresh to register and display the new ZFS management tab. Run the following command to restart the Cockpit service:<\/p>\n\n\n\n<pre class=\"wp-block-code has-cyan-bluish-gray-background-color has-background\"><code>systemctl restart cockpit.socket<\/code><\/pre>\n\n\n\n<p>Once restarted, log back into your Cockpit web console (usually at&nbsp;<code>https:\/\/your-server-ip:9090<\/code>), and you will see the brand-new ZFS storage section ready for action!<\/p>\n\n\n\n<p><span style=\"text-decoration: underline;\">ZFS section screenshoots.<\/span><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" width=\"1024\" height=\"547\" src=\"https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-1-1024x547-1.png\" alt=\"\" class=\"wp-image-508\" srcset=\"https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-1-1024x547-1.png 1024w, https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-1-1024x547-1-300x160.png 300w, https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-1-1024x547-1-768x410.png 768w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><figcaption>Dashboard<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" width=\"1024\" height=\"547\" src=\"https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-2-1024x547-1.png\" alt=\"\" class=\"wp-image-509\" srcset=\"https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-2-1024x547-1.png 1024w, https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-2-1024x547-1-300x160.png 300w, https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-2-1024x547-1-768x410.png 768w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><figcaption>Pools<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" width=\"1024\" height=\"547\" src=\"https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-3-1024x547-1.png\" alt=\"\" class=\"wp-image-510\" srcset=\"https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-3-1024x547-1.png 1024w, https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-3-1024x547-1-300x160.png 300w, https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-3-1024x547-1-768x410.png 768w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><figcaption>Datasets<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Building a robust storage web interface requires tying together multiple infrastructure layers. Recently, I set out to integrate the&nbsp;45Drives cockpit-zfs&nbsp;module into Red Hat Enterprise Linux (RHEL) 9. While the Cockpit platform makes UI extensions straightforward, RHEL 9\u2019s strict enterprise packaging boundaries threw a few roadblocks my way. Here is a breakdown of the challenges I &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/cliffordjuan.com\/index.php\/2026\/05\/18\/adding-a-zfs-management-module-to-cockpit-on-rhel-9-pitfalls-and-fixes\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Adding a ZFS Management Module to Cockpit on RHEL 9: Pitfalls and Fixes&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[57,32,27,26],"tags":[56,54,52,53,55],"_links":{"self":[{"href":"https:\/\/cliffordjuan.com\/index.php\/wp-json\/wp\/v2\/posts\/501"}],"collection":[{"href":"https:\/\/cliffordjuan.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cliffordjuan.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cliffordjuan.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/cliffordjuan.com\/index.php\/wp-json\/wp\/v2\/comments?post=501"}],"version-history":[{"count":5,"href":"https:\/\/cliffordjuan.com\/index.php\/wp-json\/wp\/v2\/posts\/501\/revisions"}],"predecessor-version":[{"id":511,"href":"https:\/\/cliffordjuan.com\/index.php\/wp-json\/wp\/v2\/posts\/501\/revisions\/511"}],"wp:attachment":[{"href":"https:\/\/cliffordjuan.com\/index.php\/wp-json\/wp\/v2\/media?parent=501"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cliffordjuan.com\/index.php\/wp-json\/wp\/v2\/categories?post=501"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cliffordjuan.com\/index.php\/wp-json\/wp\/v2\/tags?post=501"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}