# https://github.com/webzfs/webzfs # # Upstream does not tag releases. The only version it records is the CAPTION # in .env.example ("webzfs 0.85.5 BETA3"; pyproject.toml is stale), so per # the Fedora versioning guidelines that becomes 0.85.5~BETA3 (the space # replaced by the pre-release separator "~"), followed by "^" and the # snapshot information: commit date and abbreviated commit hash. %global commit d1ab57a66c19a5fbd64b7c08927d90eb0c87f14e %global shortcommit %(c=%{commit}; echo ${c:0:7}) %global commitdate 20261018 %global upstream_version 0.85.5~BETA3 Name: webzfs Version: %{upstream_version}^%{commitdate}git%{shortcommit} Release: 1%{?dist} Summary: Web interface for managing OpenZFS # webzfs: MIT # bundled xterm, addon-fit and Tailwind CSS preflight styles: MIT License: MIT URL: https://github.com/webzfs/webzfs Source0: %{url}/archive/%{commit}/%{name}-%{shortcommit}.tar.gz # npm dependencies pinned by upstream's package-lock.json: the Tailwind # CSS build tooling plus the browser libraries upstream copies out of # node_modules. See create-node-modules-tarball.sh in this distgit repo. Source1: %{name}-%{shortcommit}-node_modules.tar.xz Source2: webzfs.service Source3: webzfs.sysusers Source4: webzfs.tmpfiles Source5: README.Fedora # The alpinejs npm package does not include its license text Source6: https://raw.githubusercontent.com/alpinejs/alpine/v3.13.3/LICENSE.md#/alpinejs-LICENSE.md Source99: create-node-modules-tarball.sh # python-jose is not packaged in Fedora; switch to PyJWT (to be sent upstream) Patch: 0001-Use-PyJWT-instead-of-python-jose.patch # Let the code live outside the service account's home (to be sent upstream) Patch: 0002-Resolve-per-user-state-from-HOME-instead-of-opt-webz.patch # Fedora-specific: in-app help text names /etc/webzfs and /var/lib/webzfs Patch: 0003-Point-user-facing-paths-at-the-Fedora-package-locati.patch BuildArch: noarch BuildRequires: nodejs BuildRequires: nodejs-npm BuildRequires: python3-devel BuildRequires: systemd-rpm-macros # %%check: upstream tests and an import of the application BuildRequires: python3dist(pytest) BuildRequires: python3dist(croniter) BuildRequires: python3dist(cryptography) BuildRequires: python3dist(fastapi) BuildRequires: python3dist(gunicorn) BuildRequires: python3dist(humanize) BuildRequires: python3dist(jinja2) BuildRequires: python3dist(paramiko) BuildRequires: python3dist(psutil) BuildRequires: python3dist(pydantic) BuildRequires: python3dist(pydantic-settings) BuildRequires: python3dist(pyjwt) BuildRequires: python3dist(python-dotenv) BuildRequires: python3dist(python-multipart) BuildRequires: python3dist(python-pam) BuildRequires: python3dist(starlette) BuildRequires: python3dist(uvicorn) BuildRequires: python3dist(wsproto) # The application is not installed as a Python distribution, so nothing # generates these; keep them in sync with the imports in the source. Requires: python(abi) = %{python3_version} Requires: python3dist(croniter) Requires: python3dist(cryptography) Requires: python3dist(fastapi) Requires: python3dist(gunicorn) Requires: python3dist(humanize) Requires: python3dist(jinja2) Requires: python3dist(paramiko) Requires: python3dist(psutil) Requires: python3dist(pydantic) Requires: python3dist(pydantic-settings) Requires: python3dist(pyjwt) Requires: python3dist(python-dotenv) Requires: python3dist(python-multipart) Requires: python3dist(python-pam) Requires: python3dist(starlette) Requires: python3dist(uvicorn) # WebSocket implementation for the terminal, as pinned upstream Requires: python3dist(wsproto) # Commands run directly or through sudo Requires: lsof Requires: openssh-clients Requires: smartmontools Requires: sudo Requires: systemd Requires: util-linux Requires(post): coreutils Requires(post): grep Requires(post): sed # OpenZFS (and its zfs package) is not part of Fedora Recommends: zfs Recommends: nvme-cli # Replication and snapshot policies; not currently packaged in Fedora Suggests: sanoid # Copied from node_modules into static/vendor/xterm by upstream's build. # These are the prebuilt files published to npm; rebuilding them needs # upstream's TypeScript/esbuild toolchain, which is not in Fedora. Provides: bundled(npm(@xterm/xterm)) = 6.0.0 Provides: bundled(npm(@xterm/addon-fit)) = 0.11.0 %description WebZFS is a web interface for managing OpenZFS on Linux. It covers pools, datasets, snapshots, replication with syncoid and sanoid, SMART disk health, ZED and scheduled tasks, and an optional browser terminal. %package cockpit Summary: Cockpit integration for WebZFS # cockpit plugin: MIT # bundled Alpine.js, @vue/reactivity, @vue/shared, Chart.js, @kurkle/color: MIT # bundled htmx: BSD-2-Clause License: MIT AND BSD-2-Clause Requires: %{name} = %{version}-%{release} Requires: cockpit-bridge # Prebuilt dist files from npm, as upstream's Cockpit installer ships them; # rebuilding them needs each project's own bundler toolchain. Provides: bundled(npm(alpinejs)) = 3.13.3 Provides: bundled(npm(@vue/reactivity)) = 3.1.5 Provides: bundled(npm(@vue/shared)) = 3.1.5 Provides: bundled(npm(chart.js)) = 4.4.0 Provides: bundled(npm(@kurkle/color)) = 0.3.2 Provides: bundled(npm(htmx.org)) = 1.9.10 %description cockpit Adds WebZFS to the Cockpit sidebar. The plugin relays requests to the local WebZFS service through the Cockpit bridge, so WebZFS is used from inside a Cockpit session. %prep %autosetup -p1 -n %{name}-%{commit} -a 1 cp -p %{SOURCE5} . # Collect the license texts of everything shipped from node_modules mkdir bundled-licenses bundled-licenses-cockpit cp -p node_modules/@xterm/xterm/LICENSE bundled-licenses/LICENSE.xterm cp -p node_modules/@xterm/addon-fit/LICENSE bundled-licenses/LICENSE.xterm-addon-fit cp -p node_modules/tailwindcss/LICENSE bundled-licenses/LICENSE.tailwindcss cp -p %{SOURCE6} bundled-licenses-cockpit/LICENSE.alpinejs # @vue/reactivity and @vue/shared ship the same Vue license text cp -p node_modules/@vue/reactivity/LICENSE bundled-licenses-cockpit/LICENSE.vue cp -p node_modules/chart.js/LICENSE.md bundled-licenses-cockpit/LICENSE.chart.js cp -p node_modules/@kurkle/color/LICENSE.md bundled-licenses-cockpit/LICENSE.kurkle-color cp -p node_modules/htmx.org/LICENSE bundled-licenses-cockpit/LICENSE.htmx %build # Generates static/css/styles.css with Tailwind and copies the xterm # assets into static/vendor/xterm, as upstream's installer does. npm run build:css %install # Application install -d -m 0755 %{buildroot}%{_datadir}/%{name} cp -a auth config core services views templates static \ %{buildroot}%{_datadir}/%{name}/ # Pristine settings template; %%post reads CAPTION from it install -p -m 0644 .env.example %{buildroot}%{_datadir}/%{name}/webzfs.env.example # The application and gunicorn read .env from the application directory ln -s %{_sysconfdir}/%{name}/webzfs.env %{buildroot}%{_datadir}/%{name}/.env %py_byte_compile %{python3} %{buildroot}%{_datadir}/%{name} # Configuration install -D -p -m 0640 .env.example %{buildroot}%{_sysconfdir}/%{name}/webzfs.env install -D -p -m 0440 sudoers.d/webzfs.linux %{buildroot}%{_sysconfdir}/sudoers.d/%{name} # Service, account and state install -D -p -m 0644 %{SOURCE2} %{buildroot}%{_unitdir}/%{name}.service install -D -p -m 0644 %{SOURCE3} %{buildroot}%{_sysusersdir}/%{name}.conf install -D -p -m 0644 %{SOURCE4} %{buildroot}%{_tmpfilesdir}/%{name}.conf install -d -m 0750 %{buildroot}%{_sharedstatedir}/%{name}/.config/webzfs/{logs,progress} install -d -m 0755 %{buildroot}%{_sharedstatedir}/%{name}/.config/webzfs/generated/systemd # Cockpit plugin, laid out as integrations/cockpit/install.sh does cockpitdir=%{buildroot}%{_datadir}/cockpit/%{name} install -d -m 0755 $cockpitdir/static/{css/themes,img,js,vendor} for f in manifest.json index.html asset-monitor.js cockpit-webzfs.js \ transport.js navigation.js session.js asset-rewrite.js \ cockpit-webzfs.css; do install -p -m 0644 integrations/cockpit/$f $cockpitdir/$f done # Cockpit's content security policy blocks remote fonts sed '/fonts\.googleapis\.com/d' static/css/styles.css > $cockpitdir/static/css/styles.css install -p -m 0644 static/css/corner_styles.css $cockpitdir/static/css/ install -p -m 0644 static/css/themes/*.css $cockpitdir/static/css/themes/ install -p -m 0644 static/img/* $cockpitdir/static/img/ install -p -m 0644 static/js/*.js $cockpitdir/static/js/ install -p -m 0644 node_modules/htmx.org/dist/htmx.min.js $cockpitdir/static/vendor/htmx.min.js install -p -m 0644 node_modules/alpinejs/dist/cdn.min.js $cockpitdir/static/vendor/alpine.min.js install -p -m 0644 node_modules/chart.js/dist/chart.umd.js $cockpitdir/static/vendor/chart.umd.min.js # Unminified sources alongside the minified files install -p -m 0644 node_modules/htmx.org/dist/htmx.js $cockpitdir/static/vendor/htmx.js install -p -m 0644 node_modules/alpinejs/dist/cdn.js $cockpitdir/static/vendor/alpine.js %check # Test the installed copy of the application export PYTHONPATH=%{buildroot}%{_datadir}/%{name} %pytest -v tests # The application must import and assemble with the libraries in Fedora pushd %{buildroot}%{_datadir}/%{name} CAPTION=check SECRET_KEY=check HOME="$(mktemp -d)" PYTHONDONTWRITEBYTECODE=1 \ %{python3} -c 'from config.app import create_app; create_app()' popd # Upstream's template audit wants every