{"id":506,"date":"2026-05-18T20:59:52","date_gmt":"2026-05-18T12:59:52","guid":{"rendered":"https:\/\/cliffordjuan.com\/?p=506"},"modified":"2026-05-18T21:06:36","modified_gmt":"2026-05-18T13:06:36","slug":"a-zfs-manaddingagement-module-to-cockpit-on-rhel-9-pitfalls-and-fixes","status":"publish","type":"post","link":"https:\/\/cliffordjuan.com\/index.php\/2026\/05\/18\/a-zfs-manaddingagement-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 <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/45Drives\/cockpit-zfs\" target=\"_blank\">45Drives cockpit-zfs<\/a> 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\"\/>\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>The Symptom<\/p>\n\n\n\n<p>While pulling down build tools like <code><strong>moreutils<\/strong><\/code> 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\n<\/code><\/pre>\n\n\n\n<p>The Root Cause<\/p>\n\n\n\n<p>Red Hat splits packages into different functional repositories to keep the core OS lean. The <code><strong>perl-IPC-Run<\/strong><\/code> library is designated as a development utility. Therefore, it is isolated inside Red Hat&#8217;s <strong>CodeReady Linux Builder (CRB)<\/strong> 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 <code>dnf<\/code> metadata caching can cause the system to ignore the newly opened pipeline.<\/p>\n\n\n\n<p>The Fix<\/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\n<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" width=\"979\" height=\"622\" src=\"https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image.png\" alt=\"\" class=\"wp-image-517\" srcset=\"https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image.png 979w, https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-300x191.png 300w, https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-768x488.png 768w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p class=\"has-medium-font-size\">Challenge 2: Provisioning the Yarn Build Tool Engine<\/p>\n\n\n\n<p>The Symptom<\/p>\n\n\n\n<p>The <code>co<strong>ckpit-zfs<\/strong><\/code> project requires <code>yarn<\/code> to compile its frontend assets. However, running a standard <code><strong>dnf install yarn<\/strong><\/code> returns no matching packages on a fresh RHEL 9 deployment.<\/p>\n\n\n\n<p>The Root Cause<\/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\n<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p>The Home Stretch<\/p>\n\n\n\n<p>With the backend packaging dependencies unlocked and the frontend JavaScript engines correctly injected, the <code><strong>cockpit-zfs<\/strong><\/code> 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\n<\/code><\/pre>\n\n\n\n<p>Key Takeaway<\/p>\n\n\n\n<p>When working with cutting-edge or community-maintained web UIs on enterprise distributions like RHEL 9, <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\"\/>\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\n<\/code><\/pre>\n\n\n\n<p>Use code with caution.Once restarted, log back into your Cockpit web console (usually at <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<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"1024\" height=\"547\" src=\"https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-1-1024x547.png\" alt=\"\" class=\"wp-image-522\" srcset=\"https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-1-1024x547.png 1024w, https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-1-300x160.png 300w, https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-1-768x410.png 768w, https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-1-1536x821.png 1536w, https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-1-2048x1094.png 2048w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"1024\" height=\"547\" src=\"https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-2-1024x547.png\" alt=\"\" class=\"wp-image-523\" srcset=\"https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-2-1024x547.png 1024w, https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-2-300x160.png 300w, https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-2-768x410.png 768w, https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-2-1536x821.png 1536w, https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-2-2048x1094.png 2048w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"1024\" height=\"547\" src=\"https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-3-1024x547.png\" alt=\"\" class=\"wp-image-524\" srcset=\"https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-3-1024x547.png 1024w, https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-3-300x160.png 300w, https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-3-768x410.png 768w, https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-3-1536x821.png 1536w, https:\/\/cliffordjuan.com\/wp-content\/uploads\/2026\/05\/image-3-2048x1094.png 2048w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\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 45Drives cockpit-zfs 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 &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/cliffordjuan.com\/index.php\/2026\/05\/18\/a-zfs-manaddingagement-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":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[59,32,27,26],"tags":[53,55,56,58,52,57,54],"_links":{"self":[{"href":"https:\/\/cliffordjuan.com\/index.php\/wp-json\/wp\/v2\/posts\/506"}],"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=506"}],"version-history":[{"count":16,"href":"https:\/\/cliffordjuan.com\/index.php\/wp-json\/wp\/v2\/posts\/506\/revisions"}],"predecessor-version":[{"id":527,"href":"https:\/\/cliffordjuan.com\/index.php\/wp-json\/wp\/v2\/posts\/506\/revisions\/527"}],"wp:attachment":[{"href":"https:\/\/cliffordjuan.com\/index.php\/wp-json\/wp\/v2\/media?parent=506"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cliffordjuan.com\/index.php\/wp-json\/wp\/v2\/categories?post=506"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cliffordjuan.com\/index.php\/wp-json\/wp\/v2\/tags?post=506"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}