Scribus resolutions are the variants of the browser-snap Mutation

e651996 · gmorell · 2026-11-09 06:17

11 files +27 -25
Message
{commit_body(@commit)}

Files changed

modified apps/room_sanctum/lib/room_sanctum/mutants.ex
+21 −19
@@ -1,15 +1,15 @@
1 1 defmodule RoomSanctum.Mutants do
2 2 @moduledoc """
3 − Scribus resolutions, backed by the browser-ctl MutantDeployment.
3 + Scribus resolutions, backed by the variants of the browser-ctl Mutation.
4 4
5 − Each browser-ctl mutation runs snappers bound to the routing key in its
6 − `SNAP_RES`, and the scribe worker publishes to exactly that key -- so the
7 − mutations *are* the resolutions a Scribus can use. They are read from, and
8 − created and deleted through, the mutant operator's HTTP API rather than
9 − kept in a table that could drift from what is actually running.
5 + Each variant runs snappers bound to the routing key in its `SNAP_RES`, and
6 + the scribe worker publishes to exactly that key -- so the variants *are*
7 + the resolutions a Scribus can use. They are read from, and started and
8 + stopped through, the mutant operator's HTTP API rather than kept in a
9 + table that could drift from what is actually running.
10 10
11 − Mutations declared inline in the MutantDeployment (its manifest, in git)
12 − are listed but read-only: the operator refuses to delete them.
11 + A Mutation synced by Argo CD is listed but read-only: the operator
12 + refuses to change it.
13 13 """
14 14
15 15 require Logger
@@ -17,8 +17,8 @@ defmodule RoomSanctum.Mutants do
17 17 @env "SNAP_RES"
18 18
19 19 defmodule Resolution do
20 − @moduledoc "One running (or starting) browser-ctl mutation."
21 − defstruct [:label, :resolution, :width, :height, :instances, :ready, :state, :source]
20 + @moduledoc "One running (or starting) browser-ctl variant."
21 + defstruct [:label, :resolution, :width, :height, :instances, :ready, :state, :read_only]
22 22
23 23 @type t :: %__MODULE__{
24 24 label: String.t(),
@@ -28,7 +28,7 @@ defmodule RoomSanctum.Mutants do
28 28 instances: integer(),
29 29 ready: integer(),
30 30 state: String.t(),
31 − source: :inline | :resource
31 + read_only: boolean()
32 32 }
33 33
34 34 def display(%__MODULE__{label: label, resolution: res}), do: "#{label} (#{res})"
@@ -37,7 +37,7 @@ defmodule RoomSanctum.Mutants do
37 37 @doc "Every resolution, in label order."
38 38 @spec list_resolutions() :: {:ok, [Resolution.t()]} | {:error, String.t()}
39 39 def list_resolutions do
40 − with {:ok, body} <- request(:get, "/mutations") do
40 + with {:ok, body} <- request(:get, "/variants") do
41 41 {:ok,
42 42 body
43 43 |> Enum.flat_map(&to_resolution/1)
@@ -66,7 +66,7 @@ defmodule RoomSanctum.Mutants do
66 66 end
67 67
68 68 @doc """
69 − Starts a resolution: a new mutation running `instances` snappers at
69 + Starts a resolution: a new variant running `instances` snappers at
70 70 `width`x`height`, labelled from `name`.
71 71 """
72 72 @spec create_resolution(String.t(), integer(), integer(), integer()) ::
@@ -84,18 +84,18 @@ defmodule RoomSanctum.Mutants do
84 84 true ->
85 85 body = %{label: label, env: %{@env => "#{width}x#{height}"}, instances: instances}
86 86
87 − with {:ok, _} <- request(:post, "/mutations", body), do: {:ok, label}
87 + with {:ok, _} <- request(:post, "/variants", body), do: {:ok, label}
88 88 end
89 89 end
90 90
91 91 @doc "Stops a resolution started through `create_resolution/4`."
92 92 @spec delete_resolution(String.t()) :: :ok | {:error, String.t()}
93 93 def delete_resolution(label) do
94 − with {:ok, _} <- request(:delete, "/mutations/" <> URI.encode_www_form(label)), do: :ok
94 + with {:ok, _} <- request(:delete, "/variants/" <> URI.encode_www_form(label)), do: :ok
95 95 end
96 96
97 97 @doc """
98 − The mutation label for a display name: lowercase alphanumerics and '-',
98 + The variant label for a display name: lowercase alphanumerics and '-',
99 99 as the operator requires (it becomes part of a Deployment name).
100 100
101 101 iex> RoomSanctum.Mutants.label_for("InkPad 5 (landscape)")
@@ -110,7 +110,7 @@ defmodule RoomSanctum.Mutants do
110 110 |> String.trim_trailing("-")
111 111 end
112 112
113 − # A mutation without SNAP_RES is not a resolution a Scribus can target.
113 + # A variant without SNAP_RES is not a resolution a Scribus can target.
114 114 defp to_resolution(%{"label" => label, "env" => %{@env => res}} = m) do
115 115 {w, h} = parse(res)
116 116 status = m["status"] || %{}
@@ -124,7 +124,9 @@ defmodule RoomSanctum.Mutants do
124 124 instances: m["instances"],
125 125 ready: status["readyReplicas"] || 0,
126 126 state: status["state"] || "Unknown",
127 − source: if(get_in(m, ["source", "kind"]) == "inline", do: :inline, else: :resource)
127 + # A Mutation Argo CD syncs changes in git; the operator refuses to
128 + # change it here.
129 + read_only: Map.get(m, "readOnly", false)
128 130 }
129 131 ]
130 132 end
@@ -151,7 +153,7 @@ defmodule RoomSanctum.Mutants do
151 153 url ->
152 154 full =
153 155 String.trim_trailing(url, "/") <>
154 − "/api/v1/namespaces/#{cfg[:namespace]}/mutantdeployments/#{cfg[:mutant_deployment]}" <>
156 + "/api/v1/namespaces/#{cfg[:namespace]}/mutations/#{cfg[:mutation]}" <>
155 157 path
156 158
157 159 headers =
modified apps/room_sanctum/lib/room_sanctum_web/live/cfg_scribus_live/index.html.heex
+3 −3
@@ -57,7 +57,7 @@
57 57 </div>
58 58 <p class="text-sm opacity-70">
59 59 The browser-ctl snappers running in the cluster. A Scribus can use any that is Ready.
60 − Ones marked <span class="badge badge-sm badge-ghost">git</span> are set in the MutantDeployment manifest and change there.
60 + Ones marked <span class="badge badge-sm badge-ghost">git</span> are declared in the deployment repo and change there.
61 61 </p>
62 62
63 63 <div :if={@resolutions_error} class="alert alert-warning text-sm">
@@ -78,7 +78,7 @@
78 78 <tr :for={r <- @resolutions} id={"resolution-#{r.label}"}>
79 79 <td>
80 80 <%= r.label %>
81 − <span :if={r.source == :inline} class="badge badge-sm badge-ghost">git</span>
81 + <span :if={r.read_only} class="badge badge-sm badge-ghost">git</span>
82 82 </td>
83 83 <td><%= r.resolution %></td>
84 84 <td><%= r.ready %>/<%= r.instances %></td>
@@ -94,7 +94,7 @@
94 94 </td>
95 95 <td :if={@admin?}>
96 96 <.link
97 − :if={r.source == :resource}
97 + :if={not r.read_only}
98 98 phx-click={JS.push("delete-resolution", value: %{label: r.label})}
99 99 data-confirm={"Stop the #{r.resolution} snappers? Any Scribus using it stops updating."}
100 100 class="text-error"
modified config/runtime.exs
+3 −3
@@ -226,13 +226,13 @@ config :room_sanctum, :basemap,
226 226 subdomains: System.get_env("TILE_SUBDOMAINS"),
227 227 max_zoom: System.get_env("TILE_MAX_ZOOM")
228 228
229 −# Scribus resolutions are the browser-ctl MutantDeployment's mutations,
230 −# read and changed through the mutant operator's HTTP API.
229 +# Scribus resolutions are the variants of the browser-ctl Mutation, read
230 +# and changed through the mutant operator's HTTP API.
231 231 config :room_sanctum, RoomSanctum.Mutants,
232 232 url: System.get_env("MUTANT_API_URL"),
233 233 token: System.get_env("MUTANT_API_TOKEN"),
234 234 namespace: System.get_env("MUTANT_NAMESPACE", "apollos-crib"),
235 − mutant_deployment: System.get_env("MUTANT_DEPLOYMENT", "browser-snap-mutant")
235 + mutation: System.get_env("MUTANT_MUTATION", "browser-snap")
236 236
237 237 # Users who may start and stop Scribus resolutions.
238 238 config :room_sanctum,

Parents: 889f8de