|
| 1 | +# CloudLinux Packaging — Design Specification |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +This fork is shipped as the `cl-node-exporter` RPM (for CloudLinux OS 7/8/9, |
| 6 | +AlmaLinux) and `cl-node-exporter` `.deb` (for Ubuntu 20.04 / 22.04 servers |
| 7 | +running CloudLinux components). Packages are built from this repository's |
| 8 | +`node_exporter.spec` and `debian/` tree. The binary is installed into the |
| 9 | +CloudLinux-private tree (`/usr/share/cloudlinux/cl_plus/`) rather than onto |
| 10 | +`$PATH`, because it is an internal component of the `cl_plus` telemetry |
| 11 | +stack, not a general-purpose system service. This spec covers only |
| 12 | +packaging-level invariants — runtime flags are covered in other specs. |
| 13 | + |
| 14 | +## Package Layout |
| 15 | + |
| 16 | +### Binary package `cl-node-exporter` |
| 17 | + |
| 18 | +| Path | Source | Purpose | |
| 19 | +|------|--------|---------| |
| 20 | +| `/usr/share/cloudlinux/cl_plus/node_exporter` | `node_exporter` binary, built from source during packaging | The exporter binary. Executed by the external `cl_plus` service; not intended to be invoked by operators directly. | |
| 21 | +| `/usr/share/cloudlinux/cl-node-exporter` | Generated during `%install` / `override_dh_auto_install` | Plain-text file containing `<version>-<release>`. Consumed by Sentry for package-version tagging of crash reports. | |
| 22 | + |
| 23 | +The package deliberately omits: a systemd unit, a default config file, a |
| 24 | +`/usr/bin/` symlink, any `sysusers.d` entry, and any firewall or SELinux |
| 25 | +policy. All lifecycle and configuration concerns are owned by the consumer |
| 26 | +package (`cl_plus`). |
| 27 | + |
| 28 | +### Tests subpackage `cl-node-exporter-tests` |
| 29 | + |
| 30 | +| Path | Purpose | |
| 31 | +|------|---------| |
| 32 | +| `/opt/node_exporter_tests/node_exporter` | Second copy of the built binary, used by the e2e harness. | |
| 33 | +| `/opt/node_exporter_tests/end-to-end-test.sh` | E2E harness script. | |
| 34 | +| `/opt/node_exporter_tests/collector/` | Fixture data (procfs/sysfs/udev snapshots). Broken symlinks under `fixtures/` are stripped during `%install` because dh on Ubuntu rejects them. | |
| 35 | +| `/opt/node_exporter_tests/tools/tools` | Build-tag matcher helper used by the e2e script. | |
| 36 | + |
| 37 | +This subpackage exists so the QA pipeline can run the upstream e2e suite on |
| 38 | +the exact binary that ships, including the CloudLinux unix-socket mode (see |
| 39 | +`unix-socket-listener.md`). |
| 40 | + |
| 41 | +## Build Mechanism |
| 42 | + |
| 43 | +Both packages download and use a pinned upstream Go toolchain at build time |
| 44 | +rather than relying on the distro's `golang` package: |
| 45 | + |
| 46 | +- **Pinned version: `go1.24.0`.** Hard-coded in both `node_exporter.spec` |
| 47 | + (`%build` section) and `debian/rules` (`override_dh_auto_build`). |
| 48 | +- **Source:** `https://dl.google.com/go/go1.24.0.linux-<arch>.tar.gz`. |
| 49 | +- **Location:** extracted to `%{_tmppath}/go` (RPM) or `/tmp/go` (deb). |
| 50 | +- The pinned toolchain is prepended to `PATH` for the duration of the build. |
| 51 | + |
| 52 | +RPM spec also runs 32-bit cross-testing (`make test-32bit`) on x86_64/amd64 |
| 53 | +builds. The deb rules do not. |
| 54 | + |
| 55 | +### RPM-only conventions (`node_exporter.spec`) |
| 56 | + |
| 57 | +- `Autoreq: 0` and `%define debug_package %{nil}` — auto-dependency scanning |
| 58 | + and debuginfo generation are disabled because the binary is a statically |
| 59 | + linked Go artifact. |
| 60 | +- Version file path is derived from macros: `%{cl_dir}%{name}` resolves to |
| 61 | + `/usr/share/cloudlinux/cl-node-exporter`. The file's content is |
| 62 | + `%{version}-%{release}` as a single line. |
| 63 | + |
| 64 | +### Debian-only conventions (`debian/rules`) |
| 65 | + |
| 66 | +- After install, `find $buildroot/opt/node_exporter_tests/collector/fixtures |
| 67 | + -xtype l -delete` removes broken symlinks produced by the procfs fixture |
| 68 | + ttar archive. Without this, `dh_*` fails the build on Ubuntu. |
| 69 | +- `override_dh_auto_clean` only removes `debian/tmp` — it does not invoke |
| 70 | + `make clean`, so the vendored Go toolchain in `/tmp/go` may persist |
| 71 | + between builds on a long-lived worker. |
| 72 | +- Release string is hard-coded as `.ubuntu.cloudlinux` (parsed from the |
| 73 | + `debian/changelog` version by `dpkg-parsechangelog`). |
| 74 | + |
| 75 | +## Invariants |
| 76 | + |
| 77 | +- **Install path is stable.** `/usr/share/cloudlinux/cl_plus/node_exporter` |
| 78 | + is a contract with the consumer package. Moving the binary requires a |
| 79 | + coordinated change in `cl_plus`. |
| 80 | +- **Version file is stable.** `/usr/share/cloudlinux/cl-node-exporter` |
| 81 | + contains exactly `<rpm-or-deb-version>-<release>` and is consumed by |
| 82 | + Sentry tagging. Format change requires coordinating with the reporter. |
| 83 | +- **Go toolchain is pinned in the recipe, not the CI image.** The pinned |
| 84 | + version lives in `node_exporter.spec` and `debian/rules`. Bumping Go |
| 85 | + means editing both files in the same commit. |
| 86 | +- **The binary package does not own any runtime config, user, or unit.** |
| 87 | + All CloudLinux-specific runtime wiring (socket path, user, scraping |
| 88 | + group, startup ordering) is owned by the consumer. |
| 89 | +- **Tests subpackage is optional.** The binary package must function |
| 90 | + without `cl-node-exporter-tests` installed; the test subpackage is a |
| 91 | + QA-only artifact. |
| 92 | +- **Both architectures are amd64-only today.** Both `node_exporter.spec` |
| 93 | + (via the `%ifarch` x86_64/amd64/ia32e branches being the only curl'd Go |
| 94 | + archives) and `debian/control` (`Architecture: amd64`) restrict the |
| 95 | + package to x86_64. Adding another arch requires touching both recipes. |
| 96 | + |
| 97 | +## Test Coverage |
| 98 | + |
| 99 | +| Aspect | Test | Type | Covers | |
| 100 | +|--------|------|------|--------| |
| 101 | +| Binary builds and e2e passes on RPM build workers | `%build` section of `node_exporter.spec` runs `make build`, `make test`, `make test-32bit` | RPM build-time | Compilation + unit tests + 32-bit cross-compile + e2e socket/TCP tests (`make test-e2e`) on RPM workers. Failure aborts the build. | |
| 102 | +| Binary builds on Ubuntu build workers | `override_dh_auto_build` in `debian/rules` runs `make build`, `make tools`, `make test` | deb build-time | Compilation + unit tests on Ubuntu. (No `test-e2e` is wired in deb.) | |
| 103 | +| Fixture ttar archive is extractable | `make test-e2e` depends on `collector/fixtures/sys/.unpacked` and `collector/fixtures/udev/.unpacked` | Build | If the ttar archives are corrupt or missing, the build fails at extraction time. | |
| 104 | + |
| 105 | +### Known gaps |
| 106 | + |
| 107 | +- **No packaging-smoke test.** Nothing verifies post-install that |
| 108 | + `/usr/share/cloudlinux/cl_plus/node_exporter --version` returns the |
| 109 | + expected version string, or that the version file content matches the |
| 110 | + package version. A trivial `%posttrans` or `debian/postinst` smoke check |
| 111 | + would close this. |
| 112 | +- **Version-file format is not asserted.** If a future change to the spec |
| 113 | + accidentally drops the newline, quotes the string, or appends the |
| 114 | + architecture, Sentry tagging will silently degrade. |
| 115 | +- **Tests subpackage is not smoke-tested after install.** No CI job |
| 116 | + installs `cl-node-exporter-tests` on a fresh VM and runs |
| 117 | + `/opt/node_exporter_tests/end-to-end-test.sh` against the shipped |
| 118 | + binary. |
| 119 | +- **No coverage for non-amd64 targets.** Non-x86_64 arches are not built |
| 120 | + and therefore not exercised at all for the RPM or deb paths, even |
| 121 | + though upstream supports them. |
| 122 | +- **Deb does not run e2e.** `override_dh_auto_build` intentionally skips |
| 123 | + `make test-e2e`, so the unix-socket listener is not exercised on Ubuntu |
| 124 | + build workers. |
0 commit comments