Un émulateur qui laisserait croire à ce qu'il ne vérifie pas serait pire qu'inutile. Cette page répond à une seule question, avant que vous n'installiez quoi que ce soit : que puis-je raisonnablement tester contre feint ? En résumé, le contrat d'API, le cycle de vie Terraform et le comportement de votre client sont testables ; les prix, les quotas, la capacité réelle et les permissions IAM ne le sont pas.
Ce que vous allez obtenir
Section intitulée « Ce que vous allez obtenir »À la fin de cette page, vous saurez décider si un test donné a un sens ici, dire ce qui établit chaque verdict plutôt que de vous fier à une promesse, et reconnaître la limite qui peut coûter de l'argent.
- Lire la matrice ligne par ligne, dans votre vocabulaire.
- Distinguer un « oui » d'un « oui, avec un runtime ».
- Identifier la limite la plus dangereuse, celle qui laisse fuir du trafic.
- Comprendre pourquoi aucun pourcentage de couverture n'est publié.
La matrice des verdicts
Section intitulée « La matrice des verdicts »Chaque ligne porte son verdict et ce qui l'établit. Un « non » n'est pas un trou en attente de comblement : c'est une décision assumée, avec une raison écrite et une date.
| Ce que vous voulez valider | Verdict | Ce qui l'établit, ou la limite |
|---|---|---|
| Syntaxe, plan et cycle de vie Terraform ou OpenTofu | oui | la suite de conformité : apply, second plan vide, destroy |
Un parcours complet avec scw, octl ou exo | oui | la même exécution pilote les trois clients sur un seul émulateur |
| La forme des requêtes et des réponses, champ par champ | oui, avec un plafond énoncé | chaque réponse est vérifiée contre la description d'API du fournisseur |
| Que votre client lit un champ que le vrai cloud renvoie | oui, là où un enregistrement existe | les enregistrements de formes arbitrent ; l'angle mort est compté |
| L'ordre des dépendances : ce qui refuse d'être supprimé | oui, tant que la relation est synchrone | les assertions de refus de chaque suite |
| Que votre code décode un refus | oui | chaque suite exige des refus et échoue s'il n'y en a pas |
| Cloud-init, une connexion SSH, un pare-feu qui filtre | avec un runtime | dépend de la capacité firewall déclarée par l'hôte |
| Deux VPC qui ne peuvent pas se joindre | OVN seulement | dépend de la capacité isolation, jamais d'un nom de mode |
| Un répartiteur de charge qui distribue vraiment | OVN, et selon le pack | il faut que le runtime sache et que le pack délègue |
Qu'une machine annoncée running existe sur l'hôte | OVN, par fournisseur | une suite lit les affirmations de l'API puis les vérifie avec incus |
| Atteindre une adresse privée depuis l'hôte | selon le mode | dépend de la capacité private_from_host |
| Un test au niveau du noyau : sysctl, modules, démarrage | avec un runtime VM | un conteneur partage le noyau de l'hôte |
| Le retry et le backoff face à un 429, un 5xx ou une panne | oui, sur les opérations que vous armez | l'injection de fautes, déterministe et éteinte par défaut |
| Qu'un identifiant d'image ou de type erroné soit rejeté | oui, sur demande | --strict-catalog refuse ce qui sort du catalogue que vous déclarez |
| Les quotas, la capacité réelle, les prix | non | le catalogue est une liste blanche mesurée |
| L'authentification et les permissions IAM | non | l'authentification est acceptée, jamais vérifiée |
Une ressource qui reste en provisioning un moment | oui, sur demande | --consistency eventual fait avancer les états, une transition par lecture |
Le stockage objet, et tout ce qui s'adresse en s3.<région> | non | non émulé, et le trafic part vraiment |
| Terraform contre Exoscale | oui, depuis le provider 0.71.0 | les versions antérieures sont refusées par agent utilisateur |
| Le multi-zone ou le multi-région chez Exoscale | non | une zone par processus, et la raison vient du client |
| Du trafic qui traverse réellement une passerelle ou du NAT | non | les enregistrements bougent, les paquets non |
Comment lire un verdict
Section intitulée « Comment lire un verdict »« oui » signifie qu'un vrai client a piloté cette opération dans l'exécution de référence, et que la suite a affirmé quelque chose de la réponse. Cela ne veut pas dire que chaque champ de chaque réponse est correct : deux défauts sont restés des mois derrière un axe pourtant vert, et c'est exactement pourquoi le projet publie sept axes indépendants sans jamais les additionner.
« avec un runtime » signifie que le plan de contrôle répond sans lui, et que l'affirmation ne tient que si les machines sont réelles. La bonne façon de savoir est de demander à l'émulateur plutôt que de deviner :
curl -s localhost:4599/_feint/health | jq .capabilities{ "machines": false, "addresses": false, "firewall": false, "isolation": false, "own_kernel": false, "balancing": false, "private_from_host": false}Une capacité que personne ne déclare est lue comme absente, délibérément : un contrôle se saute lui-même plutôt que d'affirmer ce qu'aucun pilote n'a promis. Ce que chaque mode livre est détaillé dans Faire tourner de vraies machines.
« non » est une décision avec une raison, pas un oubli. Plusieurs de ces lignes changeraient si quelqu'un faisait le travail correspondant, et ce sont alors des tickets ouverts, pas des omissions.
La limite la plus importante : une exécution locale peut joindre le vrai cloud
Section intitulée « La limite la plus importante : une exécution locale peut joindre le vrai cloud »C'est la seule limite de cette page qui peut vous coûter de l'argent. feint sert des API en local ; un client peut composer lui-même l'adresse d'un produit hors de ce périmètre, et ses requêtes repartent alors là où elles allaient.
Le cas mesuré est le stockage objet. Sur une configuration réelle, le
même apply a créé son adresse IP sur l'émulateur puis a poursuivi vers
s3.fr-par.scw.cloud, parce que le provider Terraform code cette adresse en
dur pour ce produit. Seule une réponse 403 sur des identifiants factices a
rendu l'opération inoffensive ce jour-là.
Les cinq refus, et leurs raisons
Section intitulée « Les cinq refus, et leurs raisons »Ces cinq lignes reviennent le plus souvent, et chacune est un arbitrage explicite plutôt qu'un travail non fait.
Les identifiants ne sont vérifiés contre rien, sauf si vous le demandez. Par
défaut, une création qui nomme une image ou un type de machine inexistant
réussit : Scaleway répond 201 pour un UUID d'image qui n'existe nulle part,
Outscale accepte ami-99999999. Les vrais clouds refusent les trois. Ce défaut
n'est pas une négligence : l'émulateur n'a pas d'inventaire, donc les seuls
identifiants qu'il pourrait reconnaître sont ceux qu'il invente, et une
configuration qui code en dur un identifiant de production échouerait alors
sur la seule chose qui n'a rien à voir avec ce qu'elle teste.
Le coût était réel, et la 0.13.0 donne de quoi le supprimer quand il gêne :
--strict-catalog prend un fichier JSON où vous déclarez, par fournisseur,
les images, gabarits et types de machines que votre projet autorise.
{ "scaleway": {"images": ["ubuntu_jammy"], "types": ["DEV1-S"]}, "outscale": {"images": ["ami-fe1a7001"], "types": ["tinav6.c1r1p2"]}, "exoscale": {"templates": ["Linux Ubuntu 22.04 LTS 64-bit"], "types": ["standard.medium"]}}Une création qui en sort est alors refusée dans la forme d'erreur propre à chaque cloud, pas dans un format maison : votre client rend son message habituel de ressource introuvable.
{"Errors":[{"Code":"5023","Details":"The ImageId 'ami-99999999' doesn't exist.","Type":"InvalidResource"}]}Sans l'option, rien ne bouge : le mode de compatibilité est identique octet pour octet, et la phrase du dessus reste vraie mot pour mot. Un fournisseur que le fichier ne mentionne pas n'est pas contrôlé.
L'authentification est acceptée, jamais vérifiée. Aucune signature n'est contrôlée, sur aucun fournisseur. Les identifiants doivent seulement être bien formés, parce que les SDK en valident la forme côté client avant d'envoyer quoi que ce soit. La conséquence est directe : n'exposez jamais feint sur un réseau que vous ne contrôlez pas. C'est un outil de développement qui accorde tout à tout le monde, par construction.
Le catalogue est une liste blanche mesurée. Les types de machines, les images et leurs attributs viennent de valeurs relevées chez le fournisseur, pas d'un inventaire vivant. Les quotas, la capacité réelle et les prix n'y figurent donc pas, et aucun test de dépassement de quota n'a de sens ici.
Les transitions de cycle de vie sont immédiates. Un serveur passe de
stopped à running pendant l'appel. Les états que les clients vérifient
sont préservés, par exemple le refus de supprimer un serveur en cours de
transition dont Terraform dépend. Mais un refus qui n'existerait que pendant
un état transitoire ne peut pas se produire : sur un vrai compte Outscale, un
instantané demandé avant qu'un volume ne se stabilise est refusé, alors qu'ici le
volume est disponible tout de suite. Un script qui enchaîne les deux réussit en
local et peut échouer sur le vrai cloud.
Le trafic ne traverse pas les passerelles. Chez Outscale, une passerelle ou du NAT déplacent des enregistrements, pas des paquets. La configuration s'applique, se replanifie à vide et se détruit ; ce qui n'existe pas, c'est le chemin réseau derrière.
Le plancher de version qui vous protège : Terraform et Exoscale
Section intitulée « Le plancher de version qui vous protège : Terraform et Exoscale »Terraform pilote Exoscale depuis la version 0.71.0 du provider, et les
versions antérieures sont refusées. Ce n'est pas une lubie : jusqu'à cette
version, le provider publié construisait deux clients et un seul honorait la
variable EXOSCALE_API_ENDPOINT, si bien qu'un apply ou un destroy
se scindait entre l'émulateur et un compte facturé.
Ce n'était pas une crainte théorique. Un feint down lancé dans le répertoire
de la stack d'exemple a envoyé cinq requêtes signées vers les serveurs
d'Exoscale. L'émulateur a donc refusé ce client pendant dix jours, du 26 août au
5 septembre 2026, le temps que le correctif arrive en amont.
Depuis, le refus s'est transformé en plancher. Un provider plus ancien que
0.71.0 est reconnu à son agent utilisateur et reçoit un 400 qui nomme la
version à épingler ; à partir de 0.71.0, l'apply passe. Deux conséquences
concrètes pour qui suivait l'ancienne procédure : feint up ne s'arrête plus
au seuil, et la variable FEINT_EXOSCALE_ALLOW_TERRAFORM a disparu, faute
d'avoir encore quelque chose à lever. Le CLI exo, lui, n'a jamais été
concerné et pilote ce fournisseur de bout en bout.
Pourquoi aucun pourcentage n'est publié
Section intitulée « Pourquoi aucun pourcentage n'est publié »C'est un choix de méthode, et il explique la forme de toute cette page. Un chiffre unique laisse une affirmation faible profiter d'une forte. Dire « 94 % de couverture » mélangerait des opérations dont le comportement est démontré avec d'autres qui répondent seulement quelque chose de bien formé.
Le projet publie donc, pour la 0.13.0, deux nombres qui ne s'additionnent pas : 395 opérations montées, dont 375 pilotées par un vrai client dans l'exécution de référence. Les 20 restantes déclarent, à leur route, pourquoi aucun client officiel ne les atteint. La différence entre « monté », « sondé » et « piloté » est développée dans Mesurer la fidélité.
À retenir
Section intitulée « À retenir »- Le contrat d'API et le cycle de vie sont testables ; les prix, quotas et permissions ne le sont pas.
- Un « non » est une décision datée, avec une raison écrite, jamais un oubli.
- Une exécution locale peut joindre le vrai cloud : le stockage objet en est le cas mesuré.
- Les identifiants ne sont pas vérifiés : une faute de frappe passe ici et casse en production.
- L'authentification n'est jamais contrôlée, donc l'émulateur ne s'expose pas sur un réseau ouvert.
- Les transitions sont immédiates, donc un refus propre à un état transitoire ne peut pas se reproduire.
- Aucun pourcentage n'est publié, parce qu'un chiffre unique masquerait les affirmations faibles.