Skip to content

Latest commit

 

History

History
326 lines (285 loc) · 17.6 KB

File metadata and controls

326 lines (285 loc) · 17.6 KB

Instance

The Instance menu is a thin client of the keel command. Every entry collects at most one answer, runs keel with an argument list (never a shell string), and shows what came back: the command line, its output and one line for the exit code. No check lives in the dialog; the same command run from a terminal gives the same result and the same code, which is what makes a headless run and a menu run equivalent.

The spec file is /etc/keel/instance.yaml, or $KEEL_SPEC when that variable is set, the same default the command uses.

Which screens a machine shows

The menu offers a screen only where what it configures is part of the appliance (handbook decision 0041). keelmenu.py asks keel to resolve the appliance the spec names (appliance.name) along its chain of manifests under /usr/share/keel, the same resolution as keel manifest show NAME --resolved, and reads installation.mode from the spec.

Entry Offered when
View, Apply, Show drift, Export spec always
Database mode a mariadb, postgresql or redis data service is in the chain (an overlay that provides the engine, or a service the application consumes), or the spec declares database.server. Not on Keel Core or Keel Web. The engines are one set, keelmenu.DATA_ENGINES
Database mode > Cloud only for an engine whose replication keel applies, MariaDB today (keelmenu.REPLICATING_ENGINES). keel validates a Redis or PostgreSQL primary and replica but converges neither, so those offer Standalone only, and the first boot asks them no role
Overlay network the wireguard overlay is in the chain. In the menu in cloud_simple and cloud_advanced; otherwise behind Advanced, configured or not, so it never moves once an address or a peer is applied
Keel Cloud only once Keel Cloud exists: /etc/keel/cloud- endpoint holds the service's endpoint. Hidden by default, and the first boot (keelfirstboot.py cloud, run by inithooks' 80keel-cloud) asks no key either. Writing that file turns both on

/etc/keel/cloud-endpoint holds one URL and nothing else (surrounding whitespace and a final newline are ignored):

https://cloud.example.org
https://[2001:db8::10]:8443/keel

It must be https with a host, a bracketed IPv6 literal allowed and a port optional, in a regular file owned by root and writable by neither group nor others (install -m 0644 -o root). A missing file is the default and is quiet; any other failure keeps Keel Cloud hidden and is logged as Keel Cloud stays hidden: /etc/keel/cloud-endpoint: <why>.

When the chain cannot be read (keel or the manifests missing, as on a machine of before 0041, or a spec that names no appliance) the screens are offered as before, the overlay behind Advanced.

Every menu is as wide as its widest line, up to what the terminal leaves (keelfit.py), and no box is taller than the terminal; a description is shortened with an ellipsis only when even the full width is too narrow. The Keel screens' own descriptions fit an 80 column console.

Entries and their headless equivalents

Entry Headless equivalent
View spec cat /etc/keel/instance.yaml keel spec validate --no-secret-files
Apply spec keel spec apply --spec /etc/keel/instance.yaml --non-interactive
Show drift keel diff --format json (--format text for the same content as lines)
Export spec keel inspect --output /root/instance.yaml --report /root/instance.report.txt
View spec
Shows the spec file as it is on disk, then the report of keel spec validate --no-secret-files. Secrets are references in the file (a path, or generate: true), so no value is ever on screen; --no-secret-files checks the shape of every reference without requiring the files to exist, so the screen works on a machine that does not hold the secrets.
Apply spec
Asks for confirmation, showing the exact command, then runs keel spec apply --non-interactive and shows its output. Exit 0 means the spec was applied (or, as the output says, an existing non empty conf was left alone); 1 is a usage error; 2 an unreadable spec; 3 an invalid spec, every error listed; 4 a missing or badly protected secret; 5 a conf file that could not be written.
Show drift
Runs keel diff --format json and renders one row per field with four columns: field, status (same, drift, unknown, not declared, not compared), declared and observed. Where nothing was observed the reason takes the place of the value. A declared or observed cell longer than 40 characters (a list of SSH keys, say) is cut with an ellipsis so the table fits the dialog; keel diff on a terminal shows the full values. The summary line follows, then the verdict: exit 0 is clean, 13 means no drift but a declared field could not be observed, 14 means drift was found.
Export spec
Asks for the path to write (default /root/instance.yaml), runs keel inspect --output PATH --report PATH.report.txt and shows the report. Exit 13 means the spec was written but a required field could not be inferred, so the file needs editing before it can be applied; the report names the field and why.

Overlay network (WireGuard)

The WireGuard overlay the nodes of a replicated appliance share (handbook decision 0020), network.overlay.wireguard in the instance description (docs/spec.md of keel). The screen configures THIS node's side of it only; each node adds the others from its own console.

It opens on this node's public key, overlay address, listen port and peers. The key comes from keel network wireguard key, which makes the key pair the first time, on this machine, and prints only the public key. Then:

Address
This node's address on Keel's private mesh, not an address on the LAN, and the UDP port the other nodes reach it on. The first time, the field holds what keel network wireguard suggest-address prints: a randomly generated unique local address (fd00::/8), ::1 on its /64. The first node keeps it; the other nodes take ::2, ::3 on the same /64. The other entries appear once there is an address.
Add peer
Another node, as its own screen shows it: its public key, its overlay address (routed as one host, /128), its endpoint (host:port, an IPv6 address in brackets, [2001:db8::20]:51820; blank when that node reaches this one) and a keepalive in seconds (25 by default, blank for none). A peer with a key already there replaces it. This node's own public key, and one of this node's own mesh addresses, are refused; an address outside this node's prefix is asked about (a peer is routed as one host, so it still works). Either way the form comes back with what was typed.
Confirm now
First, while a network change waits for its confirmation; the screen's first line then says the time it reverts at, in UTC. It runs keel network confirm from this session and shows keel's verdict: keel accepts it from the machine's console (or a process attached from a container's host) and from an SSH session opened after the change over the new configuration, and refuses it from a session opened before. The screen does not judge the session itself.
Remove peer
Pick the peer by its key; the screen asks before removing it.

Every change is written the way the database screens write theirs: staged beside the description, checked by keel spec validate --no-secret-files, committed only when valid (otherwise the description is left exactly as it was and keel's errors are shown), then applied with keel spec apply --system-only --non-interactive --defer-certificate --skip-uplink. Unlike the database screens it does not pass --skip-network: bringing the overlay up is what it is for. It passes --skip-uplink instead, so adding or removing a peer never moves network.interfaces, the interface the operator may have come in on, even when the description declares a change there. keel brings the overlay up under the confirmation window of decision 0018, and the screen says what that means: the change reverts by itself when the window ends (120 seconds) unless it is confirmed with keel network confirm from a NEW session, over the overlay from the other node (which also tests the overlay) or over this node's usual address. The screen says so whenever a network change waits after apply: one this run brought up, even if a later step failed; one that failed and could not be rolled back either, which keel leaves to its revert timer; or one an earlier run left, which keel names when it refuses another. It needs keel 0.11.0 or later, the first with --skip-uplink, which the package recommends. It then offers to confirm from here, Yes by default: keel accepts that from the machine's own console, and refuses it, changing nothing, from an SSH session opened before the change. When the change still waits after that (No, or a refusal), the screen gives the time it reverts at, in UTC, read from keel's marker (/var/lib/keel/network/pending.json: the window starts when the interface comes up), and the command, keel network confirm, to run from a new session.

Headless equivalent: edit network.overlay.wireguard in the description, keel spec apply --system-only --skip-uplink, then keel network confirm from a new session.

Database mode

Handbook decision 0013. Replication is MariaDB's only for now: keel validates a Redis or PostgreSQL primary and replica but applies neither, so for those engines the menu offers Standalone alone. Every screen configures THIS node and nothing else, writes database.server of the instance description, checks it with keel spec validate before it replaces the file, and runs keel spec apply --system-only --non-interactive --skip-network --defer-certificate: saving a database mode never touches the network or asks for a certificate. A fresh appliance with no description gets one started (version: 1 plus the database section). The console sends no SQL; what a role means, and every refusal, is keel's. Every Cloud screen says that this replication has no automatic failover.

Database mode
  Standalone              one server, what the appliance is today
  Cloud
    Primary               other nodes replicate from this one
    Replica               this node replicates from another
    Promote this replica  an explicit act, never automatic
Standalone
One field, the addresses the server answers on. No second screen.
Primary

Asks for the addresses the server answers on (a loopback only answer is prefilled with this node's own addresses in front, IPv6 first), the origins allowed to replicate (each replica's address; an empty field is prefilled with the overlay peers' addresses, fd3d:80b2:d0d7::2, fd3d:80b2:d0d7::3; a name is accepted and fragile) and the password file (/etc/keel/secrets/replication_password). No prefix is offered: MariaDB matches the text of a replica's address, which can leave out a zero group of the prefix (fd3d:80b2:d0d7::2 is not fd3d:80b2:d0d7:0:...), so keel refuses such a prefix, the overlay /64 among them (docs/spec.md of keel). The peers offered are every overlay peer, replica or not. An origin the description already holds that keel refuses is named above the form and replaced by the peers' addresses. An empty origin list authorizes nobody: keel drops every replication account, and the handout says so first. When the password file holds nothing the screen offers to generate a password; No lets the operator type one. After the apply it shows what each replica needs:

Replicate from (address), IPv6 first:
  2001:db8:1::10
  (with a port it is written [2001:db8:1::10]:3306; type the bare address)
Allowed to replicate: fd3d:80b2:d0d7::2, fd3d:80b2:d0d7::3
Port: 3306 (leave the field blank)
Replication account: repl (keel names it; both ends use it)
Password kept in: /etc/keel/secrets/replication_password

followed by a generated password, shown this once. If the apply failed the handout starts with THIS NODE IS NOT READY and still shows the password, which is already in its file. A password already in the file is kept and never shown.

Replica
Asks for the primary's literal address, a port (blank for the default) and the addresses this node answers on, then for the replication password, hidden (a blank keeps the one already in the file). Before anything changes it warns that becoming a replica replaces the data on this node with a copy of the primary; No leaves everything as it was. If keel then refuses because the server holds databases of its own, its refusal is shown word for word and only a second Yes adds --destroy-local-database. No to that question puts the description and the password file back as they were and, when the old description declares a database server, applies it again, because keel had already rewritten the server's configuration before it refused. keel converges only what a description declares, so when the old one declares no server the screen says the replica configuration stays until a database mode is applied. A pasted [address] is stored bare.
Promote this replica
Asks first, saying that nothing stops the old primary, and runs keel database promote. The description then still says replica, which keel diff reports as drift until the Primary screen is used.

The password is written to its file (root, 0600, directory 0700) all at once, a new file replacing the old, after the description validated and before it is committed, so a refused description leaves no credential behind. It never appears in an argument list: keel reads it from the file, and the handout that shows it is a dialog textbox reading a file in a private 0700 directory removed when the box closes, not a msgbox, whose text dialog would receive as an argument readable by anyone in /proc/PID/cmdline. The password box runs with that private directory as TMPDIR, so a temporary file of pythondialog's does not outlive a dropped session in /tmp.

When keel is not installed

Every entry shows one message, keel is not installed; install the keel package, and returns to the menu. Nothing else happens.

Where the code is

keelcli.py at the root of the package (installed as /usr/lib/confconsole/keelcli.py, importable from the plugins as ifutil is from confconsole.py) holds the client: call runs the command and is the only function with a side effect; describe_exit maps a command and an exit code to a message; render_diff turns the JSON document into the table; view_text, apply_text, drift_text and export_text compose each screen. The four entries under plugins.d/Instance each fit in a screen and are loaded by the plugin manager like every other entry. tests/test_keelcli.py covers the client with subprocess.run replaced, tests/test_instance_menu.py loads each entry through plugin.Plugin with a scripted console.

The overlay screen is wgcli.py (what it builds and says, pure) and wgscreen.py (the dialog flow), beside keelcli.py for the same reason; it uses dbscreen.call and dbscreen.format_fields of the database screens. tests/test_overlay_screen.py covers both with keelcli.call replaced, and hands the descriptions the screen builds to a real keel spec validate when a keel 0.11 or later is on PATH or named by KEEL.