Skip to content

Ensure programs that link Xapi_version honor the configured version - #7319

Open
shindere wants to merge 10 commits into
xapi-project:masterfrom
shindere:honor-configured-xapi-version
Open

shindere wants to merge 10 commits into
xapi-project:masterfrom
shindere:honor-configured-xapi-version

Conversation

@shindere

@shindere shindere commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

The problem

./configure --xapi_version=v1912.6.23 # Turing's birth date
make
make install DESTDIR=/tmp/xapi
/tmp/xapi/usr/sbin/xenopsd-xc --version

When git describe finds a tag, the last command prints its output instead of the configured version:

26.20.0-29-g0af2b37-dirty

When it finds none, git describe returns a bare commit hash. Xapi_version.parse_xapi_version cannot parse it, and since this function is called when the Xapi_version module is initialised, xenopsd-xc aborts at startup, whatever its arguments:

Fatal error: exception Failure("Couldn't determine xapi version from string: '0af2b37-dirty'")

This happened in XCP-ng builds, for instance: xcp-ng-rpms/xapi#145

Eight other programs take their version from git describe in the same way, among them xcp-networkd, xcp-rrdd and squeezed. More generally, of the 19 installed programs that link Xapi_version, the module that holds the configured version, only one reports 1912.6.23 when invoked with --version.

Its causes

There are three causes, and they overlap: one cause can hide another. A program that aborts at startup because it gets its version from git describe (1) never gets a chance to show that it has no --version option (2), or that it reports a hard-coded version (3). Once they get the configured version instead, squeezed, varstored-guard and pvs-proxy-ovs-setup turn out to have no --version option (2), and sm-cli turns out to report a hard-coded version (3).

  1. dune-build-info chooses the version it writes into a program as follows:

    • if the program belongs to a package that has a version, it writes that version, which here is the configured one;
    • otherwise, it writes the output of git describe when the program is installed, ignoring the version of the project.

    The nine programs mentioned above belong to no package: they are installed through an (install) stanza, and their (executable) stanza names none.

  2. Many programs have no --version option: xapi, squeezed, varstored-guard, pvs-proxy-ovs-setup, mpathalert, event_listen, vncproxy, quicktestbin, gen_lifecycle, alert-certificate-check and daily-license-check. Some of them, xapi for instance, already use the configured version internally, but cannot show it.

  3. Some programs report a hard-coded version: rrd2csv reports 0.1.3, and sm-cli, xapi-nbd and xenops-cli report 1.0.0.

What this PR does

This situation went unnoticed because nothing checked the version that installed programs report. The PR has two parts: it first adds the missing check, then removes the three causes described above.

The first part (commits 1 to 3) sets up the check. The script check-versions.sh lists every installed program that links Xapi_version, together with what the program does when invoked with --version, and checks that it does exactly that. The CI runs it after make install. The check has three goals:

  1. Document how each program behaves before any change.
  2. Track the progress made by the fixes (commits 4 to 10). Since the causes overlap, fixing one of them sometimes changes how a program fails instead of making it succeed: once commit 4 removes the first cause, squeezed, varstored-guard and pvs-proxy-ovs-setup stop aborting and turn out not to recognise --version, and sm-cli turns out to report 1.0.0. The script makes such changes visible: a program that does not behave as listed makes the check fail, even when it does better, so each fix updates the script, and each commit message shows how the summary of check-versions.sh changes.
  3. Keep the problem from coming back, as far as possible. An installed program that links Xapi_version but is not listed in the script makes the check fail. A program that does not link Xapi_version, however, goes unnoticed, although it may still need the configured version: xapi-nbd and xenops-cli, fixed by commit 10, were such programs. For such programs, it is up to the programmer to use Xapi_version.

Commit 3 changes the version the CI configures from 0.0.0 to 1912.6.23 (Alan Turing's birth date). 0.0.0 is the default of Xapi_version.platform_version, so a program could report it because it is a default, not because it was configured, and still pass the check. Nobody would type 1912.6.23 by accident: a program that reports it can only have got it from the configuration. The value is also easy to spot in a log. The check itself, however, does not depend on the configured version, which it reads from the configuration: it passes both before commit 3, with 0.0.0, and after, with 1912.6.23.

The second part (commits 4 to 10) removes the causes one at a time. Commit 4 attaches the installed programs to their package, which removes cause (1). Commits 5, 6, 8 and 9 add a --version option where it was missing (2). Commits 6, 8 and 10 replace hard-coded versions with the configured one (3). Commit 7 prepares commit 8: it makes sure quicktestbin does nothing before parsing its arguments. Commits 4 to 9 deal with programs that already link Xapi_version. Commit 10 deals with xapi-nbd and xenops-cli: they do not link Xapi_version and report a hard-coded 1.0.0, but since they are part of the toolstack, it seemed relevant to have them report the configured version too.

Commit 4 attaches an executable to its package without installing it with (public_name -) and (package ...). The documentation of the executable stanza is ambiguous about this combination, but it matches what it documents for the executables stanza, where - in public_names marks an executable that is not installed, and dune does attach the executable to the package. If that changed, check-versions.sh would detect it.

The series is meant to be reviewed commit by commit. Each commit builds and passes the CI on its own. The message of commit 1 shows the summary of check-versions.sh before any fix, and the message of each later commit says how that summary changes.

Visible changes

  • All 21 programs that now link Xapi_version report the configured version when invoked with --version.
  • rrd2csv used to print "rrd2csv version 0.1.3" followed by "(C) Citrix 2012" for both --version and -v. Both now print the configured version only. The copyright notice is no longer printed, but remains in the header of the source file. Is that acceptable?
  • quicktestbin no longer prints a qcheck seed, nor runs tput, before parsing its arguments. As a consequence, the message "tput: No value for $TERM", which appeared in the logs of the CI, is gone.
  • The opam packages xapi-tools, xapi-storage-cli, varstored-guard, xapi-debug and xapi-nbd now declare their dependency on xapi-consts, which provides Xapi_version. They already depended on it indirectly, so this changes nothing in what gets installed: the dependency is only made explicit. I will update xs-opam accordingly once this PR is merged.

What this PR does not do

  • vhd-tool, message-cli and qcow-stream-tool still report a hard-coded version, 1.0.0. They are standalone tools that do not link Xapi_version, and the packages of message-cli and qcow-stream-tool do not even depend on xapi-consts. Should they report the configured version too?
  • This PR makes sure that programs honor a configured version. What happens when no version is configured is out of its scope, but deserves to be addressed separately: dune-build-info then gives every program the output of git describe. When that output is a bare commit hash, Xapi_version.parse_xapi_version fails to parse it while the Xapi_version module is initialised, so every program that links this module aborts before its main module even runs: such a program cannot do anything, not even report its version.

check-versions.sh runs the installed programs that link the
Xapi_version module with --version and compares what each of them does
with the check listed for it in the script. It reads DESTDIR from the
environment and is run after `make install DESTDIR=<dir>`. With -v, it
also reports the successful checks; with -s, it prints a summary.
`make check-versions DESTDIR=<dir>` runs it with -s, and V=1 adds -v.

The script lists every installed program that links Xapi_version, found
with nm, with one check describing its behaviour, and fails when a
program behaves otherwise, is missing from its listed path, is installed
without being listed, or is listed without linking Xapi_version.

configure now also writes config.sh, which defines the variables of
config.mk for shell scripts. check-versions.sh reads its
configuration from it.

Summary, with ./configure --xapi_version=v1912.6.23:

19 programs linking Xapi_version found under DESTDIR
19 checks requested:
  1 program reports the correct version (1912.6.23)
  1 program reports the hard-coded version 0.1.3
  5 programs do not recognise --version
  1 program does not recognise --version but prints a qcheck seed
  9 programs get their version from git describe
  2 programs could only be checked to be installed
  0 programs failed their check

Signed-off-by: Seb Hinderer <sebastien.hinderer@vates.tech>
The OCaml tests job installed into a temporary directory and did
nothing more with it. It now picks the installation directory in a step
of its own, installs there, and runs make check-versions, which prints
the summary of the checks. make install and make check-versions both
get DESTDIR from the environment.

This also quotes the $(mktemp -d) that the former install step left
unquoted, about which actionlint, through shellcheck (SC2046), used to
warn.

Signed-off-by: Seb Hinderer <sebastien.hinderer@vates.tech>
The OCaml tests job now gives --xapi_version=v1912.6.23 to ./configure,
and the SDK builds job builds the SDKs with that version, both instead
of v0.0.0.

0.0.0 is the default of Xapi_version.platform_version, so a program
could report it because it is a default, not because it was configured.
1912.6.23 is not a default value anywhere in the code: a program that
reports it can only have got it from the configuration.

In the summary that make check-versions prints in the OCaml tests job,
only the version shown on the correct version line changes.

Signed-off-by: Seb Hinderer <sebastien.hinderer@vates.tech>
Declare (public_name -) and (package ...) on each executable installed
through an (install) stanza, using the package of that stanza. A public
name of `-` attaches the executable to the package without installing
anything in bin, so the installed tree does not change.

dune-build-info now gives these executables the version of their
package, which is the version given to ./configure --xapi_version,
instead of the output of git describe.

squeezed, varstored-guard, pvs-proxy-ovs-setup and sm-cli were among
the programs that got their version from git describe, and used to
abort when starting in a clone without tags. They now get the configured
version and start: the first three turn out not to recognise --version,
and sm-cli reports its hard-coded version 1.0.0.

check-versions.sh is updated accordingly. The check for the programs
that got their version from git describe, which no program uses any
more, is removed, and a check for the hard-coded version of sm-cli is
added.

Changes in the summary of check-versions.sh:
  programs reporting the correct version: 1 -> 6
  programs reporting the hard-coded version 1.0.0: 0 -> 1
  programs not recognising --version: 5 -> 8
  programs getting their version from git describe: 9 -> 0

Summary, with ./configure --xapi_version=v1912.6.23:

19 programs linking Xapi_version found under DESTDIR
19 checks requested:
  6 programs report the correct version (1912.6.23)
  1 program reports the hard-coded version 0.1.3
  1 program reports the hard-coded version 1.0.0
  8 programs do not recognise --version
  1 program does not recognise --version but prints a qcheck seed
  2 programs could only be checked to be installed
  0 programs failed their check

Signed-off-by: Seb Hinderer <sebastien.hinderer@vates.tech>
Xcp_service.configure takes an optional ~version argument. When it is
given, configure accepts a --version option, which prints the version
and exits. Without it, configure behaves as before.

xapi and squeezed pass Xapi_version.version, and now report the
correct version with --version. squeezed belongs to the xapi-tools
package, which now declares its dependency on xapi-consts.

check-versions.sh is updated accordingly.

Changes in the summary of check-versions.sh:
  programs reporting the correct version: 6 -> 8
  programs not recognising --version: 8 -> 6

Signed-off-by: Seb Hinderer <sebastien.hinderer@vates.tech>
These programs build their command line with Cmdliner. varstored-guard
and pvs-proxy-ovs-setup now give Xapi_version.version to Cmd.info as
their version, which adds a --version option to them. sm-cli gives
Xapi_version.version instead of the hard-coded "1.0.0", and now depends
on xapi-consts.xapi_version.

sm-cli belongs to the xapi-storage-cli package and varstored-guard to
the varstored-guard package, which now declare their dependency on
xapi-consts.

check-versions.sh is updated accordingly. The check for the hard-coded
version of sm-cli, which no program uses any more, is removed.

Changes in the summary of check-versions.sh:
  programs reporting the correct version: 8 -> 11
  programs reporting the hard-coded version 1.0.0: 1 -> 0
  programs not recognising --version: 6 -> 4

Summary, with ./configure --xapi_version=v1912.6.23:

19 programs linking Xapi_version found under DESTDIR
19 checks requested:
  11 programs report the correct version (1912.6.23)
  1 program reports the hard-coded version 0.1.3
  4 programs do not recognise --version
  1 program does not recognise --version but prints a qcheck seed
  2 programs could only be checked to be installed
  0 programs failed their check

Signed-off-by: Seb Hinderer <sebastien.hinderer@vates.tech>
…r --version

The qcheck tests of quicktest were turned into Alcotest tests by a
toplevel definition, evaluated when the program starts. Doing so draws
the qcheck seed and prints it, so quicktestbin printed a seed before
parsing its arguments, for instance with --help. qchecks is now a
function, called only when the test suites are built, after the
arguments are parsed. The seed is still printed when the tests run.

The console backend of the quicktest traces also ran tput, to set the
margin of the pretty printers to the width of the terminal, when its
module was initialised. Without TERM in the environment, tput printed an
error on stderr, for instance with --help. The margin is now set by a
lazy value forced when a console backend is created, that is when the
tests run, and tput is only run when stdout is a terminal and TERM is
set: otherwise there is no terminal width to ask for.

check-versions.sh is updated accordingly: quicktestbin no longer prints
a seed before rejecting --version. The check for that behaviour, which
no program uses any more, is removed.

Changes in the summary of check-versions.sh:
  programs not recognising --version: 4 -> 5
  programs not recognising --version but printing a qcheck seed: 1 -> 0

Summary, with ./configure --xapi_version=v1912.6.23:

19 programs linking Xapi_version found under DESTDIR
19 checks requested:
  11 programs report the correct version (1912.6.23)
  1 program reports the hard-coded version 0.1.3
  5 programs do not recognise --version
  2 programs could only be checked to be installed
  0 programs failed their check

Signed-off-by: Seb Hinderer <sebastien.hinderer@vates.tech>
…stbin, gen_lifecycle and rrd2csv

These programs parse their command line with the Arg module.
Xapi_version.arg_spec is a --version option for Arg, which prints
Xapi_version.version and exits; each of these programs adds it to its
options and now depends on xapi-consts.xapi_version.

rrd2csv had a --version option and a -v option, both printing a
hard-coded "rrd2csv version 0.1.3" followed by "(C) Citrix 2012". Its
--version is now Xapi_version.arg_spec, and its -v prints
Xapi_version.version too.

event_listen, vncproxy and quicktestbin belong to the xapi-debug package,
which now declares its dependency on xapi-consts.

check-versions.sh is updated accordingly. The checks for programs not
recognising --version and for the hard-coded version of rrd2csv, which
no program uses any more, are removed, together with the paragraph of
the header about messages that are not ours.

Changes in the summary of check-versions.sh:
  programs reporting the correct version: 11 -> 17
  programs reporting the hard-coded version 0.1.3: 1 -> 0
  programs not recognising --version: 5 -> 0

Summary, with ./configure --xapi_version=v1912.6.23:

19 programs linking Xapi_version found under DESTDIR
19 checks requested:
  17 programs report the correct version (1912.6.23)
  2 programs could only be checked to be installed
  0 programs failed their check

Signed-off-by: Seb Hinderer <sebastien.hinderer@vates.tech>
…heck

These programs parsed no argument and started doing their work at once.
When --version is their only argument, they now print
Xapi_version.version and exit. Otherwise, they behave as before.

check-versions.sh is updated accordingly. The check for the programs
that were only checked to be installed, which no program uses any more,
is removed.

Changes in the summary of check-versions.sh:
  programs reporting the correct version: 17 -> 19
  programs only checked to be installed: 2 -> 0

Summary, with ./configure --xapi_version=v1912.6.23:

19 programs linking Xapi_version found under DESTDIR
19 checks requested:
  19 programs report the correct version (1912.6.23)
  0 programs failed their check

Signed-off-by: Seb Hinderer <sebastien.hinderer@vates.tech>
These programs build their command line with Cmdliner and gave Cmd.info
a hard-coded version "1.0.0". They now give it Xapi_version.version and
depend on xapi-consts.xapi_version. xapi-nbd belongs to the xapi-nbd
package, which now declares its dependency on xapi-consts; xenops-cli
belongs to the xapi-tools package, which already does.

check-versions.sh is updated accordingly: the two programs now link
Xapi_version, and are listed with the check for the correct version.

Changes in the summary of check-versions.sh:
  programs linking Xapi_version found under DESTDIR: 19 -> 21
  programs reporting the correct version: 19 -> 21

Summary, with ./configure --xapi_version=v1912.6.23:

21 programs linking Xapi_version found under DESTDIR
21 checks requested:
  21 programs report the correct version (1912.6.23)
  0 programs failed their check

Signed-off-by: Seb Hinderer <sebastien.hinderer@vates.tech>

@psafont psafont left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vhd-tool, message-cli and qcow-stream-tool still report a hard-coded version, 1.0.0. They are standalone tools that do not link Xapi_version, and the packages of message-cli and qcow-stream-tool do not even depend on xapi-consts. Should they report the configured version too?

I think so, yes. The hardcoded versions come from a time when all executables where stored in a different repo and no automated tooling for branding existed in the ocaml ecosystem.

This PR makes sure that programs honor a configured version. What happens when no version is configured is out of its scope, but deserves to be addressed separately: dune-build-info then gives every program the output of git describe. When that output is a bare commit hash, Xapi_version.parse_xapi_version fails to parse it while the Xapi_version module is initialised, so every program that links this module aborts before its main module even runs: such a program cannot do anything, not even report its version.

The versioning system was meant to interrupt the startup of the processes when neither of their 2 configuration methods were available, or contained a good version scheme. This makes it so the issue is detected at test time by producing a catastrophic error.

I would say it's working as intended. For reference the two configuration methods are git describe while running make and ./configure --xapi_version=... before running make.

Comment thread ocaml/gencert/dune
Comment on lines 47 to 51
(install
(files (gencert.exe as gencert))
(section libexec_root)
(package xapi)
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have thought that the installs belonging to the package would have done the promotion. It would be interesting to know whether dune maintainers would be interested in adding the behaviour

Sys.set_signal Sys.sigpipe Sys.Signal_ignore

let configure ?(argv = Sys.argv) ?(options = []) ?(resources = []) () =
let configure ?(argv = Sys.argv) ?(options = []) ?(resources = []) ?version () =

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The configure function is quite crappy and all the daemons should be made to use configure2.
This makes all daemons to use cmdliners which has several benefits, like adding --version, automagic man creation and bash completion.

The changes added by the branch can be found at master...psafont:xen-api:dev/pau/tweaks

I had another commit to change configure2 to normalise printing names for tools: fb64c0b

Unfortunately I didn't have time to test the, so I didn't end up submitting them. Hopefully they can give a few pointers on how to make this part betterin other ways

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants