Skip to main content
A plugin is a YAML file with one document of kind Plugin. Its spec can hold a place in the sidebar, for a tool whose kinds belong together on one page, and views: under views:, a view tells Lumovi how to show a kind. This page lists everything a plugin can say. For a guided introduction, see Write a plugin and Plugins.
certificates.yaml

Files

A file is one plugin: one document. It’s used whole or not at all: if anything in it is wrong, none of it is used, and everything wrong with it is listed as a problem. Files are read on their own: one with a problem, or one that can’t be read, like a link to nothing, doesn’t stop the others loading.

Whose a kind is

A kind is one plugin’s. Each kind gets one view, from the one plugin that shows it:
  • Among Lumovi’s plugins, no two show the same kind.
  • A plugin of yours shows the kinds no other plugin has. If it names a kind one of Lumovi’s plugins shows, it isn’t used, and the problem says whose kind it is and what to do.
  • To show one of Lumovi’s kinds your way, take its plugin’s place. A plugin of yours with the same metadata.name as one of Lumovi’s, like flux or cert-manager, is used in its place, all of it: Lumovi’s place in the sidebar and every one of its views go, for the kinds yours doesn’t show as well. Those get the API server’s columns. Included plugins gives each plugin’s name.
  • Among your own, the first by file name is used. A second file with the same name isn’t, whatever becomes of the first. Of two that show the same kind, the later isn’t: files with the name of one of Lumovi’s plugins are settled first, among themselves and against Lumovi’s others, and then the rest, each once, in order of their file names.
A group can be shared: three of Lumovi’s plugins have kinds in argoproj.io. What is one plugin’s is the kind. A plugin that shows every kind of a group (kind: '*') has that group to itself, and within a plugin a view for a kind itself wins over one for its whole group. API resources says what shows each kind, under Shown by: the plugin’s name as the sidebar has it, the name of your file, Lumovi, or a dash for a kind nothing shows specially. All plugins lists every plugin, and says on its row when one of yours is in use in place of one of Lumovi’s: In use in place of Lumovi’s Flux.

Kubernetes’ own kinds

A plugin is for a tool’s kinds, not Kubernetes’ own:
  • A kind Lumovi has a page for, like Pods, Deployments, Secrets or Roles (see Resource kinds), can’t be in a plugin at all.
  • A kind Lumovi shows itself, like CustomResourceDefinitions, can’t either. Lumovi has views of its own for a few of Kubernetes’ kinds that have no page. They aren’t plugins and aren’t among the included ones; Shown by says Lumovi for them.
  • Any other kind of Kubernetes’, like a Lease or a LimitRange, a plugin can show, and only show. It names the kind under shows, and its view of it has columns, status, details, links and related lists, but no actions. Such a kind can’t be under the plugin’s place in the sidebar.
limits.yaml

The document

string
required
Always lumovi.dev/v1beta1.
string
required
Always Plugin.
string
required
The plugin’s name: lowercase letters, digits and hyphens, starting with a letter and ending with a letter or a digit, at most 63 characters. It’s the address of its page (plugins/platform). A name is one plugin’s: of two files of yours with the same name, the first by file name is used, and a plugin of yours with the name of one of Lumovi’s is used in its place. lumovi, a name starting with lumovi-, and kubernetes can’t be a plugin’s.
object
required
What it says: see spec. Any field it doesn’t know is a problem, so typos don’t go unnoticed.
These four are all a document has, and name is all its metadata has. A key Lumovi doesn’t know is a problem wherever it is in the file, so a metadata.labels or a stray key at the top isn’t passed over in silence.

spec

A plugin’s spec holds a place in the sidebar, views, or both. A file with one view and nothing else is a plugin too, the smallest one.
platform.yaml
string
required
The plugin’s own version: three numbers, like 1.0.0, with no leading zeros and nothing before or after them. 1.0 and v1.0.0 are problems.
string
required
The oldest Lumovi the plugin works with, as three numbers, like 1.22.0. A plugin that needs a newer Lumovi than the one reading it isn’t used, and the problem says both versions.
list of strings
required
The API groups its kinds are in, like [platform.example.com]. Every kind of a tool’s that the plugin names, in its place in the sidebar or in a view, is in one of them. A group is written as Kubernetes writes it: lowercase letters, digits, hyphens and dots. Kubernetes’ own groups, like apps, and lumovi.dev can’t be among them. A plugin that only shows Kubernetes’ kinds has an empty list.
list of kinds
Kinds of Kubernetes’ own that Lumovi has no page for, which the plugin shows and only shows. Each is written out as a view’s kinds are, with its group unless it’s of the core group, and each is shown by one of the plugin’s views.
list
The kinds of its place in the sidebar, in the order of their tabs: an entry in the sidebar leads to a page with all of them, everything in one list and a tab for each. Written as a view’s kinds: kind: '*' is every kind of a group, each with a tab, in order of their names. Kubernetes’ own kinds can’t be among them. See Plugins.
string
Its name in the sidebar, on its page and in the command palette. Required with kinds.
string
One of the icons. Without one, it gets the puzzle piece of custom resources.
string
A section of the sidebar for Kubernetes’ own kinds to sit in, at its end: cluster (Cluster), network (Network), config (Configuration) or storage (Storage). Without one, it’s under Plugins.
list of views
How its kinds are shown: see A view. A plugin needs views, or kinds for a place in the sidebar.
A label, an icon and a category are for a place in the sidebar, so they need kinds. A place only groups kinds: how each kind looks, its columns, status and actions, comes from a view of this plugin’s. One of yours with the same metadata.name as one of Lumovi’s is used in its place, all of it: see Whose a kind is. A few fields are only for plugins whose code draws pages: the ones from Lumovi-plugins, and a plugin of yours in a folder of its own, for Developer mode. A file of yours on its own, or a server’s, with any of them isn’t used, and its problem says which. Each is shown in Lumovi’s words on the plugin’s entry under All plugins, and is all its code may do:

A view

Each item under views::
string
A name of its own, if you like. Nothing depends on it.
list
required
The kinds it’s for, at least one. Each is a kind and its API group, and the group is one of the plugin’s groups. A kind’s name is its own, like GitRepository: letters and digits, starting with a capital, with its group beside it and never in it.
kind: '*' is every kind of a group, like the constraint kinds Gatekeeper makes, one for each of its templates. It needs a group. A view for a kind itself wins over one for its whole group.
A kind of Kubernetes’ own is left without group if it’s of the core group, and has to be under the plugin’s shows: see Kubernetes’ own kinds.
string
The kind’s icon, one of the icons below.
list of fields
List columns, shown after the name and status. They replace the columns the API server prints for the kind. See Fields.
list of rules
How to tell whether an object is healthy. The first rule that applies decides. With no rule that applies, Lumovi reads the status from the usual conventions. See Status rules.
list of fields
Facts in the detail panel’s Details section. See Fields.
Single objects this one points to, listed under Related in the detail panel’s Overview. See Links.
Objects of other kinds that belong to this one, a tab each in the detail panel. See Related.
list of actions
Changes people can make: a patch of the object, or a new object to create. See Actions.
list
How an object of this kind marks the workloads it manages, so a workload says what manages it. See What it manages.

Fields

Columns and details are both fields.
string
required
The column’s header, or the fact’s name.
path
required
Where its value is. See Paths.
string
default:"string"
How it’s shown and sorted:
string
What to show when the path finds nothing.

Paths

Paths are the part of kubectl’s JSONPath that CRD printer columns use, starting with a dot. A path can also be written {.spec.x} or $.spec.x. When a path finds several values, they’re shown joined with commas.
In YAML, quote paths that contain brackets or double quotes, and anything that starts with {: '.status.conditions[?(@.type=="Ready")].status'.

Status rules

condition
When the rule applies. See Conditions. A rule without one always applies, which makes it a good last rule.
string
required
One of healthy, progressing, warning, critical or neutral. It decides the color, the icon, where the object sorts, and which filter chip counts it.
template
required
What the status says, like Ready or '{{ .status.phase }}'.
template
More about it, shown on hover, and in a plugin’s Message column.

Conditions

A condition reads one value at path, and compares it:
Comparisons ignore case, so equals: True matches Kubernetes’ "True" even though YAML reads an unquoted True as a boolean. When a path finds several values, the first is compared. A condition with more than one operator uses the first of exists, equals, notEquals, in and matches that it has. Conditions combine with all and any, nested as deep as you need:
A condition has exactly one of path, all or any.

Templates

A status rule’s label and detail, links, related lists, and actions’ texts, patches and new objects can include values from the object.

In patches and new objects

In a patch, an undo or an object to create, a value that’s a template and nothing else stands for the value itself, not its text:
  • A number stays a number, and a list or an object is copied whole: params: '{{ .spec.params }}' copies the object’s parameters.
  • When the template finds nothing, the field is left out (and a list item is dropped), rather than set to an empty string.
  • {{ now }} is always text, and so is everything under labels and annotations, which Kubernetes keeps as text.
A value with other text around its template, like '{{ .metadata.name }}-copy', is always text. Templates in undo are filled in from the object as it was before the action ran. So an undo can put back the value an action replaces: undo: { spec: { mode: '{{ .spec.mode }}' } }. Links are listed under Related in the detail panel’s Overview. Click one to open the object.
string
required
What the object is to this one, like Secret or Issuer.
template
required
How Lumovi names its kind: a built-in kind (Secret, Pod, Node…), or a kind and its API group (ClusterIssuer.cert-manager.io).
template
required
Its name.
template
Its namespace. This object’s unless set, and none for cluster-wide kinds.
A link whose kind or name comes out empty isn’t shown. Related lists are the objects of another kind that belong to this one: a node pool’s nodes, a database’s instances, a pipeline’s runs. Each is a tab of the detail panel, after Metrics, listing them with their kind’s usual columns. They’re also on the object’s Map.
string
required
The tab’s name, like Instances or Nodes.
template
required
Their kind, named as for links: Pod, NodeClaim.karpenter.sh.
map of templates
The labels they have, each value a template: cnpg.io/cluster: '{{ .metadata.name }}'.
template
A field selector they match, like 'spec.nodeName={{ .status.nodeName }}'.
template
Where to look. This object’s namespace unless set. Kinds without namespaces are looked for across the cluster, and so is everything related to an object that has no namespace.
A related list needs labels or a fieldSelector: without one, it would be every object of the kind. A list whose kind, label values or field selector values come out empty isn’t shown, since it would find the wrong objects. Like any list, it needs list on the kind. The first list of Pods is special: it becomes the panel’s Pods tab, under the list’s name (CloudNativePG’s Instances). It brings a Logs tab with their logs, merged, and a Metrics tab with their usage history.

What it manages

A tool that deploys workloads, like a GitOps tool, marks each one it deployed with labels or annotations of its own. A view’s manages says which, so Lumovi can tell a workload’s manager: workloads’ lists get a Managed by column, and a workload’s Overview starts with a line for each manager, like “Kustomization flux-system/apps manages this deployment, and may undo changes made to it any other way.”, which opens it.
Each item holds labels, annotations or both: the keys a managed workload carries, each with a template of the manager’s. A workload is managed by an object of this kind when every key of one item is on it, with exactly the value the template gives for that object. A template may also name the managed workload itself, as {{ object.group }}, {{ object.kind }}, {{ object.namespace }} and {{ object.name }}, for a tool that writes a workload’s own name into its mark:
  • At most 4 items, and 8 keys in one.
  • Each key is under the group of the view’s kinds, or one under it: kustomize.toolkit.fluxcd.io/name for a Kustomization, argocd.argoproj.io/tracking-id for an Argo CD Application (argoproj.io). Never one of Kubernetes’ own (kubernetes.io, k8s.io and every name under them), nor a key with no group: any chart can set those, so they can’t tell one tool’s workloads from another’s.
  • Only for kinds of its own, named one by one: a view of one of Kubernetes’ own kinds only shows it, and kind: '*' can’t say what it manages.
  • The workloads are Deployments, StatefulSets, DaemonSets, Jobs and CronJobs.
To find managers, Lumovi lists each such kind in the whole cluster where you may list it, or else in the namespaces you’re looking at, as you. The Plugins page says so for each plugin. Where no plugin says what it manages, nothing more is read.

Actions

Actions change the object with a patch, like kubectl patch, or create another object, like kubectl create. Each has a patch or a create, not both.
string
required
The action’s name, in menus and on its button.
object or list
A merge patch (an object), or, with type: json, a list of JSON patch operations. Templates work inside it, within what a patch can’t change.
object
An object to create instead, with templates. See Creating objects.
list of inputs
Values to ask for before it runs, at least one. See Inputs.
string
default:"merge"
merge or json. A merge patch is an object, and a JSON patch is a list; anything else is a problem.
string
status, to patch the object’s status subresource.
object or list
A patch that takes the change back, offered as Undo in the notification. Same type as patch, and filled in from the object as it was before. Actions that create have no undo.
template
Asks first, with this text.
template
The dialog’s question, in place of Lumovi’s ” ?”: Terminate {{ .metadata.name }}’s sync?. One line, 80 characters at most, and only on an action that asks first. Lumovi still names the object under it.
template
The dialog’s button, in place of the action’s name. One line, 24 characters at most, and only on an action that asks first.
string
at-once, on an action that asks nothing first. See When an action asks first.
template
The notification once it’s done. Without it, the notification is the action’s name and the object’s.
condition
Offer the action only when this holds. Just before it’s sent, Lumovi reads the object again and judges this on it again, and sends what you read with the version it read then (metadata.resourceVersion, or a JSON patch’s first test), so a change in between is refused by the cluster. Where it no longer holds, nothing is sent: “storefront has changed since you looked at it, so Terminate sync wasn’t sent and nothing changed. Look at it again.” Where what’s sent would come out different from what you read, or the cluster refuses the version: “storefront changed while you looked at it, so nothing was changed. Look at it again.”
list of paths
Up to four paths that must hold, as it’s sent, what they held in the object you were shown, or nothing is sent, with the line above. Argo CD’s Terminate sync names .status.operationState.startedAt, so it never stops a sync other than the one you saw.
list
Up to four { when, word, since }: while one holds (the first that does), the action is drawn busy where it was, in place of being offered or hidden, with Lumovi’s turning mark, word (24 characters at most), and how long since the date at the path since, where it’s given. It can’t be pressed. Argo CD’s Sync says Syncing while a sync runs.
boolean
Also show it as a button in the detail panel, not only in its menu.
boolean
It’s destructive: it’s shown in red, and its confirmation starts on Cancel.
string
One of the icons. Without one, an action gets a lightning bolt.
boolean
Offered in Lumovi’s own bar for rows a person selects on a plugin’s page, a patch done to each of them. Its inputs are asked once for all, those that say bulk: false filled in with their defaults. Lumovi reads each object again as it’s sent, judges when and same on it, and sends it with the version it read; what’s left out is said, and why. Where the patch reads anything of the object, the dialog says the command is the first’s and “each is filled in from its own object”. Only a patch: never a create.
object
How its work ends, once its busy no longer holds: a path on its own object, the values it ends on, each with a word and a level (Failed, critical), and where a message beside it is. Lumovi follows each change it sent until then, says how it ended in these words, and nothing else of the object, the message cut at 500 characters.

When an action asks first

An action with a confirm, inputs or a create opens a dialog first, and its name ends in ”…” in menus, like Back up now…. The dialog shows the confirm text, the inputs, what it would create, and the equivalent command. Its button has the action’s name. An action with none of the three runs at once, and has to say so: runs: at-once. That way nobody reading the file takes a change that asks nothing for one that asks. An action that asks first can’t say it. One done to several (bulk) may still say runs: at-once with inputs: pressed for one object it runs at once, filled in with its inputs’ defaults (each needs one), and for several its inputs are asked once.

What a change harms

A kind under changes may list what in a change of it does harm, up to 8. Lumovi checks every change of that kind against it as it’s sent, the page’s proposals and the file’s own actions alike, and for several objects each one’s own: each harm that holds is drawn in red in Lumovi’s dialog, and its verb is named on the button, like Sync, prune and force, whatever the plugin’s code says.
  • path: where in the change, as names with dots between.
  • One of is, set or contains: the value that harms, set: true for its being there at all, or a value a list there holds.
  • says: what it does, up to 160 characters, and verb: the word on the button, up to 24.
  • unless: a path and the value at it that makes the change harmless, like a dry run. It quiets the harm only where the person set that value with a switch or a check of their own: never a value the plugin wrote, one read off the object, or a default filled in where it isn’t asked.
A JSON patch is judged failing closed: an operation that copies, moves, adds or replaces onto or into a harm’s path counts as harming, whatever it carries. An action whose patch may write a harm’s path has to ask first.

What a patch can’t change

Some of an object’s metadata is the cluster’s to set, or its owner’s, and no plugin’s:
  • In a patch or an undo: ownerReferences, finalizers, managedFields, namespace, name, uid, resourceVersion, generation, creationTimestamp and deletionTimestamp.
  • In an object to create: ownerReferences, finalizers and managedFields. A new object has its name, and can have a namespace.
So that nothing filled in later can get round this, a few things are written out and never come from a template:
  • metadata, in a patch or an object to create, is a map written in the file, not one placeholder.
  • Each operation of a JSON patch is written out, and so are its path and from, as text with no {{ }} in them.
  • A JSON patch operation can’t name /metadata itself or the whole object, and can’t name one of the fields above in its path or from, whatever the operation is.
Labels and annotations are yours to set, and their values can be templates. The file is checked when it’s read. The change is checked again as it’s sent, filled in: one that would change any of these isn’t sent, and the notification says “Lumovi didn’t send this: it changes metadata.finalizers, which a plugin can’t change.”

Inputs

Inputs are values an action asks for, used in its templates as {{ input.name }}.
string
required
How templates name it: letters, digits and _, not starting with a digit, like replicas.
string
required
What the dialog calls it.
string
default:"text"
  • text: a text field.
  • number: a whole number from 0 to 1,000. In a patch, a template that’s only this input gives a number (except under labels and annotations).
  • choice: one of a few options, picked from a list.
  • switch: yes or no, filled in as true or false. Its default is true or false.
list
A choice’s options: [Off, Initial, Recreate].
list
A choice’s options as labels the person picks among, each filling in its value as it is, any value JSON can hold: [{ label: Apply, value: { apply: {} } }]. Up to 20.
boolean
false: not asked where the action is done to several at once; its default fills it in for each, so it needs one.
path
Where to read a choice’s options from instead, like '.status.instanceNames[*]'. When it finds nothing, the dialog says There’s nothing to choose from.
template
The value it starts with. Without one, a number starts at 0, and a choice on its first option.
A choice has one of options, choices or from, and other inputs have none of them. Every input needs a value before the action can run. Templates in patch, create, confirm and done can only name inputs the action has.

Creating objects

create is an object to create, written as you’d write its YAML, with templates in it. It needs an apiVersion, a kind, and a metadata.name or metadata.generateName as text. What it creates is one of the plugin’s own kinds: one under its place in the sidebar, or one a view of it shows. So its apiVersion and kind are written out, not templates.
  • Its name. With generateName, Lumovi picks the random end of the name itself, the way the API server would, so the dialog shows the name it will get.
  • Its namespace. The object’s own, unless metadata.namespace says otherwise. Kinds without namespaces get none.
  • Copying. A template that’s a whole value copies it, lists and objects included, and leaves the field out when it finds nothing. Tekton’s Run again copies a run’s pipeline, parameters and workspaces this way: params: '{{ .spec.params }}'.
  • Before and after. The dialog shows the object as YAML first, under Creates with its kind and name. Once it’s created, Open in the notification opens it.
Creating something can’t be undone from the notification: delete what it made instead.

Permissions and commands

An action is enabled only when the cluster says your account may make the change: patch on the kind (or on its status, with subresource: status) for a patch, and create on the kind it creates for a create. Like every change, it shows the equivalent command, kubectl patch … or kubectl create -f <name>.yaml, and is refused in a read-only cluster.

Texts

A plugin’s own texts are plain text, and short enough to show:
  • 80 characters at most for a name, a label and an input’s default.
  • 500 characters at most for a confirm, a detail and a done, and for a status rule’s label, which is a template.
  • No characters that can’t be seen, in any text or key of the file: the ones that turn a text’s direction, the ones with no width, and control characters. A name, a label and a default can’t hold a line break or a tab either. The problem names the character by its code point, like U+202E.
What a patch or a created object holds is the cluster’s to limit, so the two lengths don’t apply inside patch, undo and create.

Icons

Plugins can use these Lucide icons, for their place in the sidebar, their views’ kinds and their actions: activity, archive, bell, box, boxes, bug, camera, cloud, database, file-check, flame, gauge, git-branch, git-merge, globe, hexagon, key-round, layers, lock, network, package, play, puzzle, radar, refresh-cw, rocket, route, scaling, server, server-cog, shield-check, signpost, square, timer, waves, waypoints, workflow

Problems

Lumovi checks every plugin before using it. One with a problem isn’t used at all. All plugins lists its file as a row, Not in use. 2 problems to fix in the file., with everything wrong with it underneath, each line saying where in the file it is, from the top. The rest are about a file beside another plugin: What a problem quotes from a file is cut at 40 characters, and a character that can’t be seen in it is shown as its code point. A file that isn’t valid YAML shows the parser’s message. One that can’t be read as YAML for any other reason is listed as one that couldn’t be read, with the reason, and the others load. When a plugin of yours with a problem has the name of one of Lumovi’s, Lumovi’s is what’s shown, and the file’s row says so: Lumovi’s Flux is shown instead. It’s said only where the file’s name for itself could be read. API resources says only that there are problems, A plugin couldn’t be used. or how many, with See Plugins; and at its foot how many plugins are Lumovi’s and how many are yours, and where yours go, with How to write a plugin.