feat(services): MySQL, and the port allocator every service now shares (T34c) - #7
Merged
Conversation
MariaDB and MySQL name the same default and so do two instances of either, which is one problem and not two. A recipe now declares the port it would like, `service.create` allocates one at the moment the row is written, and the number is never recomputed after that. Free means free on the machine: the test is a bind, so an XAMPP or Windows' own MySQL80 holding 3306 moves the new service off it — and the program that took it is named (T38) rather than the service renumbering in silence. The table is consulted too, because a stopped MariaDB holds its port as surely as a running one. Allocating and inserting are one critical section, or two creates arriving together get one port. `services::pools::free_port` is gone into it: a pool asks for its 9000 the same way `mariadb@main` asks for 3306, and by the same rule. `service.create` answers a `ServiceCreation` — the service, plus why it is not on the port it asked for — and `ServiceSummary` carries the port so a listing can say which one a service was given.
…34c) MySQL is not a MariaDB version: its own package, its own recipe, its own rows. What the two share is the port they both want, which the allocator already answers. Bootstrapping is a table of three routes rather than a version test — `mysqld --initialize-insecure` from 5.7 on, `mysql_install_db` for 5.6 on Unix through the interpreter its own first line names, and 5.6 on Windows copying the `data/` directory upstream's zip ships built. The route is an argument rather than a `cfg!`, so all three are exercised wherever the tests run. Three things measured against 8.4.10 and 5.6.51 rather than assumed. There is no `--bootstrap` after 5.7.6, so the statement that sets the root password goes into a file the daemon writes and removes around one step — `Step::secret_file`, never an argument list, never a log line. The server that runs it binds nothing at all and stops itself with `SHUTDOWN`. `--initialize-insecure` creates only `root@localhost`, so MariaDB's `skip-name-resolve` cannot travel to this template. And a modern MySQL opens a second listener on 33060 that no allocation handed out, which `loose-mysqlx = OFF` closes in a spelling 5.6 also accepts. The space-free view both installers need moves up into `recipes`, because `mysql_install_db` is the ancestor of `mariadb-install-db` and leaves `$basedir` unquoted in the same places.
The suite installs a real 8.4.10 through `package.install`, creates the service, and asserts what only a server can say: the start bootstraps an empty data directory, the service reaches `running` — which is an authenticated `mysqladmin ping` and therefore proof the generated password reached the keyring and came back — root without a password is refused by name, the stop is a clean shutdown in the server's own log, a second start does not bootstrap again, and a data directory MixEngine did not create is refused rather than cleaned. The refusal names `'root'@'localhost'`, which quietly proves the other half of the measurement: the name lookup this template leaves on is what makes that account reachable over TCP at all. CI fetches MySQL on every runner that has one — there is no Windows-on-ARM cell in any line, so that leg skips the step rather than failing a download that could not succeed. The Linux leg runs it from inside the keyring namespace, for MariaDB's reason. T34c is ticked; phase 3 is 13 of 15.
Four links written in the T34c commits: two name their target twice, and two point from a `pub mod` at a `pub(super)` item, which resolves only because the project reads its docs with `--document-private-items`. CI reads them with `-D warnings` as well, so both are errors there. The private two lose the link rather than gain visibility — `Route` and `hold` are internal because nothing outside their module may call them, and widening an item to satisfy a doc link would be the lint deciding the API.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
MySQL — the second database product rather than a second version of the first — and the port
allocation that came with it and now belongs to every service. Roadmap task T34c; phase 3 is
13 of 15.
One allocator decides every service's port
A recipe declares the port it would prefer;
service.createallocates one under a lock held acrossthe
INSERT, so two creates racing cannot be handed the same number. Free means free on themachine, not free in the table — the test is a bind, so a port an XAMPP is already holding is not
handed out and is reported with that program's name rather than renumbered in silence. The number is
written once and never recomputed.
services::pools::free_portwent into it: a php-fpm pool asks for its 9000 by the same rulemariadb@mainasks for 3306.ServiceSummarycarries the port now, andservice.createanswers aServiceCreation— the service, plus why it is not on the port it asked for — because a port aperson did not choose is one they have to be told about.
The MySQL recipe
Most of the machinery is T33's, reused rather than rebuilt:
Recipe::ritual,ReadyCheck::Commandas an authenticated
mysqladmin ping,StopBehaviour::Commandasmysqladmin shutdown, and themarkers that let a half-finished data directory be cleaned without ever clearing a database
MixEngine did not create.
The bootstrap is a table of three routes and not a version test, and the route is an argument
rather than a
cfg!— so all three are exercised wherever the tests run, where two of them wouldotherwise be unreachable on any one machine:
mysqld --initialize-insecurefrom 5.7 on;mysql_install_dbfor 5.6 on Unix, run by the interpreter its own first line names; and 5.6 onWindows copying the
data/directory upstream's zip ships built.What the task did not expect to add is
Step::secret_file. MySQL removed--bootstrapat5.7.6, so the statement setting the root password cannot travel on standard input the way MariaDB's
does —
--init-filetakes a path. The three ways to get a generated password into that server area file, an argument list every process can read, or a temporary server on a port anybody can connect
to; only the first has an exposure MixEngine bounds. So a step may declare a file, the daemon writes
it inside owner-only
run/and removes it whether the step succeeded, failed or timed out, and itscontent never reaches a
Debugline.Two measurements changed the template.
--initialize-insecurecreates onlyroot@localhostwhere MariaDB's installer creates four root rows, so
skip-name-resolvecould not travel from onemy.cnfto the other — and the suite's refusal assertion, which reads back'root'@'localhost', iswhat proves the lookup is still on. And a modern MySQL opens a second listener nobody asked for, the
X Protocol on 33060, which no allocation handed out and no
servicesrow records;loose-mysqlx = OFFcloses it on 8.0 and newer and is a warning rather than a refusal on the two 5.x lines.Judged against a real server
crates/mixengine-cli/tests/mysql.rsinstalls a real 8.4.10 and asserts what only a server can say:the first start bootstraps an empty data directory, the service reaches
running— an authenticatedping, and therefore proof the generated password reached the keyring and came back — root without a
password is refused by name, the stop is a clean shutdown in the server's own log, a second start
does not bootstrap again, and a data directory MixEngine did not create is refused rather than
cleaned.
CI fetches MySQL on every runner that has one. There is no Windows-on-ARM cell in any MySQL line, so
that leg skips the step rather than failing a download that could not succeed; the Linux leg runs
inside the keyring namespace, for MariaDB's reason.
CI on this branch is green on all seven jobs, real-server suites included.