Add plugins pages
This commit is contained in:
parent
6d01d60c10
commit
0c3e81bc0f
4 changed files with 644 additions and 0 deletions
11
content/reference/plugins/_index.en.md
Normal file
11
content/reference/plugins/_index.en.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
date: 2025-06-15T11:38:46+02:00
|
||||
title: Plugins
|
||||
author: nemunaire
|
||||
archetype: chapter
|
||||
weight: 40
|
||||
---
|
||||
|
||||
Plugins are external pieces of code — shared libraries loaded at startup — that extend happyDomain's functionality without recompiling the server. An operator simply drops a `.so` file into a configured directory, and happyDomain picks it up automatically on the next start.
|
||||
|
||||
{{% children %}}
|
||||
11
content/reference/plugins/_index.fr.md
Normal file
11
content/reference/plugins/_index.fr.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
date: 2025-06-15T11:38:46+02:00
|
||||
title: Plugins
|
||||
author: nemunaire
|
||||
archetype: chapter
|
||||
weight: 40
|
||||
---
|
||||
|
||||
Les plugins sont des morceaux de code externes — des bibliothèques partagées chargées au démarrage — qui étendent les fonctionnalités de happyDomain sans recompiler le serveur. Il suffit de déposer un fichier `.so` dans un répertoire configuré pour que happyDomain le charge automatiquement au prochain démarrage.
|
||||
|
||||
{{% children %}}
|
||||
311
content/reference/plugins/tests.en.md
Normal file
311
content/reference/plugins/tests.en.md
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
---
|
||||
title: "Writing a happyDomain Plugin"
|
||||
description: "Technical guide for developing test plugins for happyDomain"
|
||||
---
|
||||
|
||||
happyDomain supports external **test plugins** — shared libraries (`.so` files) that add domain or service health checks to a running instance. Plugins are loaded at startup without recompiling the server; the operator simply drops a `.so` file into a configured directory.
|
||||
|
||||
## How it works
|
||||
|
||||
A plugin receives a set of options assembled from several configuration scopes, runs a check (HTTP call, DNS query, …), and returns a result with a status level and an optional detailed report. Results are stored and displayed in the happyDomain UI alongside the domain or service they concern.
|
||||
|
||||
When happyDomain starts it scans every directory listed in the `plugins-directories` configuration option. For each file it finds, it:
|
||||
|
||||
1. Opens the shared library.
|
||||
2. Looks up the exported symbol `NewTestPlugin`.
|
||||
3. Calls `NewTestPlugin()` to obtain a plugin value.
|
||||
4. Registers the plugin under each name returned by `PluginEnvName()`.
|
||||
|
||||
If the file is not a valid Go plugin, if `NewTestPlugin` is missing, or if it returns an error, a warning is logged and the file is skipped. The server always starts regardless of individual plugin load failures.
|
||||
|
||||
---
|
||||
|
||||
## The `TestPlugin` interface
|
||||
|
||||
Every plugin must implement four methods:
|
||||
|
||||
```go
|
||||
type TestPlugin interface {
|
||||
PluginEnvName() []string
|
||||
Version() PluginVersionInfo
|
||||
AvailableOptions() PluginOptionsDocumentation
|
||||
RunTest(PluginOptions, map[string]string) (*PluginResult, error)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Project structure
|
||||
|
||||
A plugin is a standalone Go module compiled with `-buildmode=plugin`. It must be in `package main` and export exactly one symbol:
|
||||
|
||||
```go
|
||||
func NewTestPlugin() (happydns.TestPlugin, error)
|
||||
```
|
||||
|
||||
Recommended layout:
|
||||
|
||||
```
|
||||
myplugin/
|
||||
├── go.mod
|
||||
├── Makefile
|
||||
└── plugin.go # (or split across multiple .go files)
|
||||
```
|
||||
|
||||
### go.mod
|
||||
|
||||
```
|
||||
module git.happydns.org/happyDomain/plugins/myplugin
|
||||
|
||||
go 1.25
|
||||
|
||||
require git.happydns.org/happyDomain v0.0.0
|
||||
replace git.happydns.org/happyDomain => ../../
|
||||
```
|
||||
|
||||
The `replace` directive points to your local happyDomain checkout, ensuring the plugin is compiled against the exact same types as the server.
|
||||
|
||||
{{< notice style="warning" >}}
|
||||
A Go plugin and the host process share the same runtime. They **must** be compiled with the same Go toolchain version and the same versions of every shared dependency. Any mismatch produces a hard error at load time.
|
||||
{{< /notice >}}
|
||||
|
||||
---
|
||||
|
||||
## Entry point
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import "git.happydns.org/happyDomain/model"
|
||||
|
||||
func NewTestPlugin() (happydns.TestPlugin, error) {
|
||||
return &MyPlugin{}, nil
|
||||
}
|
||||
```
|
||||
|
||||
The constructor is a good place to perform one-time initialisation (open config files, create an HTTP client, …). Return an error if the plugin cannot function.
|
||||
|
||||
---
|
||||
|
||||
## Naming — `PluginEnvName()`
|
||||
|
||||
Returns one or more short, lowercase identifiers. These names are used to look up the plugin via the API and to key its stored configuration.
|
||||
|
||||
```go
|
||||
func (p *MyPlugin) PluginEnvName() []string {
|
||||
return []string{"myplugin"}
|
||||
}
|
||||
```
|
||||
|
||||
Choose names that are unlikely to collide (e.g. `"zonemaster"`, `"matrixim"`) and keep them **stable across versions** because they are persisted alongside user configuration. If two loaded plugins claim the same name, the second one is skipped and a conflict is logged.
|
||||
|
||||
---
|
||||
|
||||
## Version and availability — `Version()`
|
||||
|
||||
Describes the plugin and controls where it appears in the UI:
|
||||
|
||||
```go
|
||||
func (p *MyPlugin) Version() happydns.PluginVersionInfo {
|
||||
return happydns.PluginVersionInfo{
|
||||
Name: "My Plugin",
|
||||
Version: "1.0",
|
||||
AvailableOn: happydns.PluginAvailability{
|
||||
ApplyToDomain: true,
|
||||
ApplyToService: false,
|
||||
LimitToProviders: nil, // nil or empty = all providers
|
||||
LimitToServices: []string{"abstract.MatrixIM"},
|
||||
},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | Description |
|
||||
|---|---|---|
|
||||
| `ApplyToDomain` | `bool` | Plugin can be run against a whole domain |
|
||||
| `ApplyToService` | `bool` | Plugin can be run against a specific DNS service |
|
||||
| `LimitToProviders` | `[]string` | Restrict to certain DNS provider identifiers (empty = no restriction) |
|
||||
| `LimitToServices` | `[]string` | Restrict to certain service type identifiers, e.g. `"abstract.MatrixIM"` (empty = no restriction) |
|
||||
|
||||
Both `ApplyToDomain` and `ApplyToService` may be `true` simultaneously.
|
||||
|
||||
---
|
||||
|
||||
## Options — `AvailableOptions()`
|
||||
|
||||
Options are key/value pairs (`map[string]any`) that configure each test run. They are declared grouped by **scope**, i.e. who sets them and how long they persist:
|
||||
|
||||
```go
|
||||
func (p *MyPlugin) AvailableOptions() happydns.PluginOptionsDocumentation {
|
||||
return happydns.PluginOptionsDocumentation{
|
||||
RunOpts: []happydns.PluginOptionDocumentation{ /* … */ },
|
||||
ServiceOpts: []happydns.PluginOptionDocumentation{ /* … */ },
|
||||
DomainOpts: []happydns.PluginOptionDocumentation{ /* … */ },
|
||||
UserOpts: []happydns.PluginOptionDocumentation{ /* … */ },
|
||||
AdminOpts: []happydns.PluginOptionDocumentation{ /* … */ },
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Option scopes
|
||||
|
||||
| Scope | Who sets it | Storage key | Typical use |
|
||||
|---|---|---|---|
|
||||
| `RunOpts` | User, at test time | _(transient)_ | Per-invocation parameters |
|
||||
| `ServiceOpts` | User | plugin + user + domain + service | Service-level configuration |
|
||||
| `DomainOpts` | User | plugin + user + domain | Domain-level configuration |
|
||||
| `UserOpts` | User | plugin + user | Personal preferences (e.g. language) |
|
||||
| `AdminOpts` | Administrator | plugin | Instance-wide settings, shared credentials |
|
||||
|
||||
Before `RunTest` is called, happyDomain merges all scoped values from least specific (admin) to most specific (run-time). More-specific values silently override less-specific ones. `RunTest` always receives a single flat map and does not need to know which scope each value came from.
|
||||
|
||||
### Option fields
|
||||
|
||||
Each option is a `PluginOptionDocumentation` (an alias for `Field`):
|
||||
|
||||
| Field | Type | Description |
|
||||
|---|---|---|
|
||||
| `Id` | `string` | **Required.** Key used in the `PluginOptions` map inside `RunTest` |
|
||||
| `Type` | `string` | Input type: `"string"`, `"select"` |
|
||||
| `Label` | `string` | Human-readable label shown in the UI |
|
||||
| `Placeholder` | `string` | Placeholder text for the input field |
|
||||
| `Default` | `any` | Default value pre-filled in the form |
|
||||
| `Choices` | `[]string` | Options for `"select"` inputs |
|
||||
| `Required` | `bool` | Whether the field must be filled before running |
|
||||
| `Secret` | `bool` | Marks the field as sensitive (e.g. an API key) |
|
||||
| `Hide` | `bool` | Hides the field from the user entirely |
|
||||
| `Textarea` | `bool` | Renders a multiline text area |
|
||||
| `Description` | `string` | Help text displayed below the field |
|
||||
| `AutoFill` | `string` | Populate the field automatically from context (see below) |
|
||||
|
||||
### Auto-fill
|
||||
|
||||
When `AutoFill` is set, happyDomain populates the field from the test context; the user is not prompted:
|
||||
|
||||
| Constant | String value | Populated with |
|
||||
|---|---|---|
|
||||
| `happydns.AutoFillDomainName` | `"domain_name"` | FQDN of the domain under test, e.g. `"example.com."` |
|
||||
| `happydns.AutoFillSubdomain` | `"subdomain"` | Subdomain relative to the zone, e.g. `"www"` — service-scoped tests only |
|
||||
| `happydns.AutoFillServiceType` | `"service_type"` | Service type identifier, e.g. `"abstract.MatrixIM"` — service-scoped tests only |
|
||||
|
||||
```go
|
||||
{
|
||||
Id: "domainName",
|
||||
Type: "string",
|
||||
Label: "Domain name",
|
||||
AutoFill: happydns.AutoFillDomainName,
|
||||
Required: true,
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Running the check — `RunTest()`
|
||||
|
||||
`RunTest` receives the merged option map and a metadata map (reserved for future use), performs the check, and returns a `PluginResult`.
|
||||
|
||||
Always assert option values to a concrete type before use — the map holds `any`:
|
||||
|
||||
```go
|
||||
func (p *MyPlugin) RunTest(opts happydns.PluginOptions, _ map[string]string) (*happydns.PluginResult, error) {
|
||||
domain, ok := opts["domainName"].(string)
|
||||
if !ok || domain == "" {
|
||||
return nil, fmt.Errorf("domainName option is required")
|
||||
}
|
||||
|
||||
// … perform the check …
|
||||
|
||||
return &happydns.PluginResult{
|
||||
Status: happydns.PluginResultStatusOK,
|
||||
StatusLine: "All good",
|
||||
Report: myStructuredReport,
|
||||
}, nil
|
||||
}
|
||||
```
|
||||
|
||||
Return a **non-nil error** only for unexpected failures (network errors, invalid configuration). For expected check failures — the monitored service is down, DNS records are wrong — return a `PluginResult` with an appropriate status and a human-readable `StatusLine`.
|
||||
|
||||
### Result fields
|
||||
|
||||
| Field | Type | Description |
|
||||
|---|---|---|
|
||||
| `Status` | `PluginResultStatus` | Overall result level (see below) |
|
||||
| `StatusLine` | `string` | Short summary displayed in the UI |
|
||||
| `Report` | `any` | Any JSON-serialisable value stored as structured diagnostic data |
|
||||
|
||||
### Status levels (worst → best)
|
||||
|
||||
| Constant | Meaning |
|
||||
|---|---|
|
||||
| `PluginResultStatusKO` | Check failed |
|
||||
| `PluginResultStatusWarn` | Check passed with warnings |
|
||||
| `PluginResultStatusInfo` | Informational, no action required |
|
||||
| `PluginResultStatusOK` | Check fully passed |
|
||||
|
||||
---
|
||||
|
||||
## Building
|
||||
|
||||
```bash
|
||||
go build -buildmode=plugin -o happydomain-plugin-test-myplugin.so \
|
||||
git.happydns.org/happyDomain/plugins/myplugin
|
||||
```
|
||||
|
||||
Minimal `Makefile`:
|
||||
|
||||
```makefile
|
||||
PLUGIN_NAME=myplugin
|
||||
TARGET=../happydomain-plugin-test-$(PLUGIN_NAME).so
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): *.go
|
||||
go build -buildmode=plugin -o $@ git.happydns.org/happyDomain/plugins/$(PLUGIN_NAME)
|
||||
```
|
||||
|
||||
The prefix `happydomain-plugin-test-` is a convention; happyDomain loads every file in the plugin directories regardless of its name.
|
||||
|
||||
---
|
||||
|
||||
## Deployment
|
||||
|
||||
### 1. Copy the `.so` file
|
||||
|
||||
```bash
|
||||
cp happydomain-plugin-test-myplugin.so /usr/lib/happydomain/plugins/
|
||||
```
|
||||
|
||||
### 2. Point happyDomain at the directory
|
||||
|
||||
`happydomain.conf`:
|
||||
|
||||
```
|
||||
plugins-directories=/usr/lib/happydomain/plugins
|
||||
```
|
||||
|
||||
Environment variable:
|
||||
|
||||
```bash
|
||||
HAPPYDOMAIN_PLUGINS_DIRECTORIES=/usr/lib/happydomain/plugins
|
||||
```
|
||||
|
||||
Multiple directories may be listed as a comma-separated value.
|
||||
|
||||
### 3. Check the logs
|
||||
|
||||
On a successful load:
|
||||
|
||||
```
|
||||
Plugin My Plugin loaded (version 1.0)
|
||||
```
|
||||
|
||||
On a name conflict or load error a warning is logged with the filename and reason.
|
||||
|
||||
---
|
||||
|
||||
## Reference implementations
|
||||
|
||||
Two plugins are bundled in this directory:
|
||||
|
||||
- **`matrix/`** — queries the Matrix federation tester API. Demonstrates `ApplyToService` with `LimitToServices` and `AdminOpts` for the backend URL.
|
||||
- **`zonemaster/`** — drives the Zonemaster JSON-RPC API, polls for completion, and maps results to severity levels. Demonstrates `AutoFillDomainName`, `UserOpts` for language selection, and multi-level status mapping.
|
||||
311
content/reference/plugins/tests.fr.md
Normal file
311
content/reference/plugins/tests.fr.md
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
---
|
||||
title: "Écrire un plugin happyDomain"
|
||||
description: "Guide technique pour développer des plugins de test pour happyDomain"
|
||||
---
|
||||
|
||||
happyDomain prend en charge des **plugins de test** externes — des bibliothèques partagées (fichiers `.so`) qui ajoutent des vérifications de santé sur les domaines ou les services d'une instance en cours d'exécution. Les plugins sont chargés au démarrage sans recompiler le serveur ; l'opérateur dépose simplement un fichier `.so` dans un répertoire configuré.
|
||||
|
||||
## Fonctionnement
|
||||
|
||||
Un plugin reçoit un ensemble d'options assemblées depuis plusieurs portées de configuration, exécute une vérification (appel HTTP, requête DNS, …) et renvoie un résultat avec un niveau de statut et un rapport détaillé optionnel. Les résultats sont stockés et affichés dans l'interface happyDomain aux côtés du domaine ou du service concerné.
|
||||
|
||||
Au démarrage, happyDomain parcourt chaque répertoire listé dans l'option de configuration `plugins-directories`. Pour chaque fichier trouvé, il :
|
||||
|
||||
1. Ouvre la bibliothèque partagée.
|
||||
2. Recherche le symbole exporté `NewTestPlugin`.
|
||||
3. Appelle `NewTestPlugin()` pour obtenir une valeur de plugin.
|
||||
4. Enregistre le plugin sous chaque nom renvoyé par `PluginEnvName()`.
|
||||
|
||||
Si le fichier n'est pas un plugin Go valide, si `NewTestPlugin` est absent ou s'il retourne une erreur, un avertissement est journalisé et le fichier est ignoré. Le serveur démarre toujours, quels que soient les échecs de chargement individuels.
|
||||
|
||||
---
|
||||
|
||||
## L'interface `TestPlugin`
|
||||
|
||||
Tout plugin doit implémenter quatre méthodes :
|
||||
|
||||
```go
|
||||
type TestPlugin interface {
|
||||
PluginEnvName() []string
|
||||
Version() PluginVersionInfo
|
||||
AvailableOptions() PluginOptionsDocumentation
|
||||
RunTest(PluginOptions, map[string]string) (*PluginResult, error)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Structure du projet
|
||||
|
||||
Un plugin est un module Go autonome compilé avec `-buildmode=plugin`. Il doit être dans `package main` et exporter exactement un symbole :
|
||||
|
||||
```go
|
||||
func NewTestPlugin() (happydns.TestPlugin, error)
|
||||
```
|
||||
|
||||
Organisation recommandée :
|
||||
|
||||
```
|
||||
myplugin/
|
||||
├── go.mod
|
||||
├── Makefile
|
||||
└── plugin.go # (ou réparti sur plusieurs fichiers .go)
|
||||
```
|
||||
|
||||
### go.mod
|
||||
|
||||
```
|
||||
module git.happydns.org/happyDomain/plugins/myplugin
|
||||
|
||||
go 1.25
|
||||
|
||||
require git.happydns.org/happyDomain v0.0.0
|
||||
replace git.happydns.org/happyDomain => ../../
|
||||
```
|
||||
|
||||
La directive `replace` pointe vers votre dépôt local happyDomain, garantissant que le plugin est compilé avec exactement les mêmes types que le serveur.
|
||||
|
||||
{{< notice style="warning" >}}
|
||||
Un plugin Go et le processus hôte partagent le même environnement d'exécution. Ils **doivent** être compilés avec la même version de la chaîne d'outils Go et les mêmes versions de toutes les dépendances partagées. Tout écart provoque une erreur fatale au chargement.
|
||||
{{< /notice >}}
|
||||
|
||||
---
|
||||
|
||||
## Point d'entrée
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import "git.happydns.org/happyDomain/model"
|
||||
|
||||
func NewTestPlugin() (happydns.TestPlugin, error) {
|
||||
return &MyPlugin{}, nil
|
||||
}
|
||||
```
|
||||
|
||||
Le constructeur est l'endroit idéal pour effectuer une initialisation unique (ouvrir des fichiers de configuration, créer un client HTTP, …). Retournez une erreur si le plugin ne peut pas fonctionner.
|
||||
|
||||
---
|
||||
|
||||
## Nommage — `PluginEnvName()`
|
||||
|
||||
Renvoie un ou plusieurs identifiants courts en minuscules. Ces noms sont utilisés pour retrouver le plugin via l'API et pour indexer sa configuration stockée.
|
||||
|
||||
```go
|
||||
func (p *MyPlugin) PluginEnvName() []string {
|
||||
return []string{"myplugin"}
|
||||
}
|
||||
```
|
||||
|
||||
Choisissez des noms peu susceptibles d'entrer en conflit (ex. `"zonemaster"`, `"matrixim"`) et gardez-les **stables entre les versions**, car ils sont persistés avec la configuration utilisateur. Si deux plugins chargés revendiquent le même nom, le second est ignoré et un conflit est journalisé.
|
||||
|
||||
---
|
||||
|
||||
## Version et disponibilité — `Version()`
|
||||
|
||||
Décrit le plugin et contrôle l'endroit où il apparaît dans l'interface :
|
||||
|
||||
```go
|
||||
func (p *MyPlugin) Version() happydns.PluginVersionInfo {
|
||||
return happydns.PluginVersionInfo{
|
||||
Name: "My Plugin",
|
||||
Version: "1.0",
|
||||
AvailableOn: happydns.PluginAvailability{
|
||||
ApplyToDomain: true,
|
||||
ApplyToService: false,
|
||||
LimitToProviders: nil, // nil ou vide = tous les fournisseurs
|
||||
LimitToServices: []string{"abstract.MatrixIM"},
|
||||
},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Champ | Type | Description |
|
||||
|---|---|---|
|
||||
| `ApplyToDomain` | `bool` | Le plugin peut être exécuté sur un domaine entier |
|
||||
| `ApplyToService` | `bool` | Le plugin peut être exécuté sur un service DNS spécifique |
|
||||
| `LimitToProviders` | `[]string` | Restreint à certains identifiants de fournisseurs DNS (vide = aucune restriction) |
|
||||
| `LimitToServices` | `[]string` | Restreint à certains types de services, ex. `"abstract.MatrixIM"` (vide = aucune restriction) |
|
||||
|
||||
`ApplyToDomain` et `ApplyToService` peuvent être tous les deux `true` simultanément.
|
||||
|
||||
---
|
||||
|
||||
## Options — `AvailableOptions()`
|
||||
|
||||
Les options sont des paires clé/valeur (`map[string]any`) qui configurent chaque exécution de test. Elles sont déclarées regroupées par **portée**, c'est-à-dire qui les définit et combien de temps elles persistent :
|
||||
|
||||
```go
|
||||
func (p *MyPlugin) AvailableOptions() happydns.PluginOptionsDocumentation {
|
||||
return happydns.PluginOptionsDocumentation{
|
||||
RunOpts: []happydns.PluginOptionDocumentation{ /* … */ },
|
||||
ServiceOpts: []happydns.PluginOptionDocumentation{ /* … */ },
|
||||
DomainOpts: []happydns.PluginOptionDocumentation{ /* … */ },
|
||||
UserOpts: []happydns.PluginOptionDocumentation{ /* … */ },
|
||||
AdminOpts: []happydns.PluginOptionDocumentation{ /* … */ },
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Portées des options
|
||||
|
||||
| Portée | Qui la définit | Clé de stockage | Usage typique |
|
||||
|---|---|---|---|
|
||||
| `RunOpts` | L'utilisateur, au moment du test | _(transitoire)_ | Paramètres propres à l'exécution |
|
||||
| `ServiceOpts` | L'utilisateur | plugin + utilisateur + domaine + service | Configuration au niveau du service |
|
||||
| `DomainOpts` | L'utilisateur | plugin + utilisateur + domaine | Configuration au niveau du domaine |
|
||||
| `UserOpts` | L'utilisateur | plugin + utilisateur | Préférences personnelles (ex. langue) |
|
||||
| `AdminOpts` | L'administrateur | plugin | Paramètres d'instance, identifiants partagés |
|
||||
|
||||
Avant l'appel à `RunTest`, happyDomain fusionne toutes les valeurs par portée, de la moins spécifique (admin) à la plus spécifique (exécution). Les valeurs plus spécifiques écrasent silencieusement les moins spécifiques. `RunTest` reçoit toujours une map plate unique et n'a pas besoin de savoir de quelle portée provient chaque valeur.
|
||||
|
||||
### Champs d'une option
|
||||
|
||||
Chaque option est un `PluginOptionDocumentation` (un alias pour `Field`) :
|
||||
|
||||
| Champ | Type | Description |
|
||||
|---|---|---|
|
||||
| `Id` | `string` | **Obligatoire.** Clé utilisée dans la map `PluginOptions` dans `RunTest` |
|
||||
| `Type` | `string` | Type de saisie : `"string"`, `"select"` |
|
||||
| `Label` | `string` | Libellé lisible affiché dans l'interface |
|
||||
| `Placeholder` | `string` | Texte indicatif du champ de saisie |
|
||||
| `Default` | `any` | Valeur par défaut pré-remplie dans le formulaire |
|
||||
| `Choices` | `[]string` | Options pour les saisies de type `"select"` |
|
||||
| `Required` | `bool` | Indique si le champ doit être rempli avant l'exécution |
|
||||
| `Secret` | `bool` | Marque le champ comme sensible (ex. une clé API) |
|
||||
| `Hide` | `bool` | Masque entièrement le champ à l'utilisateur |
|
||||
| `Textarea` | `bool` | Affiche une zone de texte multiligne |
|
||||
| `Description` | `string` | Texte d'aide affiché sous le champ |
|
||||
| `AutoFill` | `string` | Remplit le champ automatiquement depuis le contexte (voir ci-dessous) |
|
||||
|
||||
### Remplissage automatique
|
||||
|
||||
Lorsque `AutoFill` est défini, happyDomain remplit le champ à partir du contexte du test ; l'utilisateur n'est pas sollicité :
|
||||
|
||||
| Constante | Valeur chaîne | Rempli avec |
|
||||
|---|---|---|
|
||||
| `happydns.AutoFillDomainName` | `"domain_name"` | FQDN du domaine testé, ex. `"example.com."` |
|
||||
| `happydns.AutoFillSubdomain` | `"subdomain"` | Sous-domaine relatif à la zone, ex. `"www"` — tests à portée service uniquement |
|
||||
| `happydns.AutoFillServiceType` | `"service_type"` | Identifiant du type de service, ex. `"abstract.MatrixIM"` — tests à portée service uniquement |
|
||||
|
||||
```go
|
||||
{
|
||||
Id: "domainName",
|
||||
Type: "string",
|
||||
Label: "Nom de domaine",
|
||||
AutoFill: happydns.AutoFillDomainName,
|
||||
Required: true,
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Exécuter la vérification — `RunTest()`
|
||||
|
||||
`RunTest` reçoit la map d'options fusionnée et une map de métadonnées (réservée à un usage futur), effectue la vérification et renvoie un `PluginResult`.
|
||||
|
||||
Convertissez toujours les valeurs d'options vers un type concret avant de les utiliser — la map contient des valeurs de type `any` :
|
||||
|
||||
```go
|
||||
func (p *MyPlugin) RunTest(opts happydns.PluginOptions, _ map[string]string) (*happydns.PluginResult, error) {
|
||||
domain, ok := opts["domainName"].(string)
|
||||
if !ok || domain == "" {
|
||||
return nil, fmt.Errorf("l'option domainName est obligatoire")
|
||||
}
|
||||
|
||||
// … effectuer la vérification …
|
||||
|
||||
return &happydns.PluginResult{
|
||||
Status: happydns.PluginResultStatusOK,
|
||||
StatusLine: "Tout est bon",
|
||||
Report: myStructuredReport,
|
||||
}, nil
|
||||
}
|
||||
```
|
||||
|
||||
Retournez une **erreur non nulle** uniquement pour les échecs inattendus (erreurs réseau, configuration invalide). Pour les échecs de vérification attendus — le service surveillé est indisponible, les enregistrements DNS sont incorrects — retournez un `PluginResult` avec un statut approprié et un `StatusLine` lisible par un humain.
|
||||
|
||||
### Champs du résultat
|
||||
|
||||
| Champ | Type | Description |
|
||||
|---|---|---|
|
||||
| `Status` | `PluginResultStatus` | Niveau de résultat global (voir ci-dessous) |
|
||||
| `StatusLine` | `string` | Résumé court affiché dans l'interface |
|
||||
| `Report` | `any` | Toute valeur sérialisable en JSON, stockée comme données de diagnostic structurées |
|
||||
|
||||
### Niveaux de statut (du pire au meilleur)
|
||||
|
||||
| Constante | Signification |
|
||||
|---|---|
|
||||
| `PluginResultStatusKO` | La vérification a échoué |
|
||||
| `PluginResultStatusWarn` | La vérification a réussi avec des avertissements |
|
||||
| `PluginResultStatusInfo` | Informatif, aucune action requise |
|
||||
| `PluginResultStatusOK` | La vérification a entièrement réussi |
|
||||
|
||||
---
|
||||
|
||||
## Compilation
|
||||
|
||||
```bash
|
||||
go build -buildmode=plugin -o happydomain-plugin-test-myplugin.so \
|
||||
git.happydns.org/happyDomain/plugins/myplugin
|
||||
```
|
||||
|
||||
`Makefile` minimal :
|
||||
|
||||
```makefile
|
||||
PLUGIN_NAME=myplugin
|
||||
TARGET=../happydomain-plugin-test-$(PLUGIN_NAME).so
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): *.go
|
||||
go build -buildmode=plugin -o $@ git.happydns.org/happyDomain/plugins/$(PLUGIN_NAME)
|
||||
```
|
||||
|
||||
Le préfixe `happydomain-plugin-test-` est une convention ; happyDomain charge tous les fichiers présents dans les répertoires de plugins, quel que soit leur nom.
|
||||
|
||||
---
|
||||
|
||||
## Déploiement
|
||||
|
||||
### 1. Copier le fichier `.so`
|
||||
|
||||
```bash
|
||||
cp happydomain-plugin-test-myplugin.so /usr/lib/happydomain/plugins/
|
||||
```
|
||||
|
||||
### 2. Indiquer le répertoire à happyDomain
|
||||
|
||||
`happydomain.conf` :
|
||||
|
||||
```
|
||||
plugins-directories=/usr/lib/happydomain/plugins
|
||||
```
|
||||
|
||||
Variable d'environnement :
|
||||
|
||||
```bash
|
||||
HAPPYDOMAIN_PLUGINS_DIRECTORIES=/usr/lib/happydomain/plugins
|
||||
```
|
||||
|
||||
Plusieurs répertoires peuvent être listés en les séparant par des virgules.
|
||||
|
||||
### 3. Vérifier les journaux
|
||||
|
||||
En cas de chargement réussi :
|
||||
|
||||
```
|
||||
Plugin My Plugin loaded (version 1.0)
|
||||
```
|
||||
|
||||
En cas de conflit de nom ou d'erreur de chargement, un avertissement est journalisé avec le nom du fichier et la raison.
|
||||
|
||||
---
|
||||
|
||||
## Implémentations de référence
|
||||
|
||||
Deux plugins sont fournis dans ce répertoire :
|
||||
|
||||
- **`matrix/`** — interroge l'API de test de fédération Matrix. Illustre `ApplyToService` avec `LimitToServices` et `AdminOpts` pour l'URL du serveur tiers.
|
||||
- **`zonemaster/`** — pilote l'API JSON-RPC de Zonemaster, attend la fin du test et agrège les résultats par niveau de sévérité. Illustre `AutoFillDomainName`, `UserOpts` pour la sélection de la langue et la gestion de statuts multi-niveaux.
|
||||
Loading…
Add table
Add a link
Reference in a new issue