Comprendre Feint : pourquoi un émulateur plutôt qu'un mock
Les décisions d'architecture qui font qu'un client officiel ne voit pas la différence : un port, un cœur neutre, et une surface d'API mesurée plutôt que suivie.
L’issue s’ouvre déjà remplie avec le titre et l’adresse de cette page.
AWS a LocalStack, Azure a Azurite, les clouds européens n'avaient rien. Leurs
utilisateurs testent contre un compte payant ou ne testent pas.
Feint émule les API de Scaleway, Outscale et
Exoscale pour que les SDK, les CLI et Terraform tournent sur un poste de
travail. Cette page explique les décisions qui font qu'un client officiel ne
voit pas la différence, et pourquoi ces mêmes décisions produisent les limites
documentées ailleurs.
À la fin de cette page, vous saurez pourquoi un émulateur trouve des défauts
qu'un mock ne peut pas trouver, comment ce projet tient face à des API qui
bougent plus vite que quiconque ne peut suivre à la main, et d'où viennent les
limites documentées ailleurs.
Distinguer un émulateur d'un serveur de mocks, sur deux défauts réels.
Comprendre pourquoi la surface est mesurée plutôt que recopiée.
Situer la frontière entre le cœur neutre et les packs de fournisseurs.
Relier chaque limite documentée à la décision qui la produit.
Le nom est un mouvement d'escrime : la feinte, de l'ancien français
feindre, un geste fait pour ressembler au vrai afin que l'adversaire s'engage.
C'est exactement le test qui se joue ici : le client officiel s'engage, et
ne peut pas faire la différence. La marque du projet dessine le même
argument, avec un trait plein pour la surface réellement servie et un trait
pointillé pour ce que le fournisseur annonce et que personne n'a encore piloté.
Un mock renvoie ce que vous lui avez dit de renvoyer. Il ne peut donc pas vous
apprendre que le champ que vous avez inventé n'existe pas, que le CLI interroge
trois autres points d'entrée avant de créer quoi que ce soit, ou que l'API a
renommé une opération le mois dernier.
Deux défauts trouvés dans ce projet rendent la différence concrète, et ils sont
plus parlants qu'une démonstration.
Le premier vient d'un champ inventé. L'opération de création de machines chez
Outscale lisait un champ VmCount que l'API ne possède pas : elle expose
MinVmsCount et MaxVmsCount. Chaque requête créait donc une seule machine
quel que soit le nombre demandé. Un mock configuré avec le même champ erroné
aurait été d'accord avec le défaut.
Le second est plus retors. Le pack Scaleway a servi un jour une adresse
privée inventée, que sa propre suite de tests relisait ensuite. L'émulateur se
prouvait contre lui-même, et rien dans cette boucle ne pouvait signaler
l'erreur. La parade n'est pas un test de plus, c'est un arbitre extérieur :
les réponses sont vérifiées contre la description d'API du fournisseur, et
648 des 655 schémas d'Outscale déclarent additionalProperties: false, ce qui
fait d'un champ non défini une violation que le fournisseur a lui-même
écrite.
La surface d'une API bouge plus vite que n'importe quelle équipe ne la suit à
la main. Le chiffre est mesuré plutôt qu'estimé : sur les douze mois qui
précèdent le 28 juillet 2026, Scaleway a ajouté 363 opérations et en a retiré
25. Le relevé provient de l'exécution du scan de surface du projet sur deux
copies datées du SDK officiel, puis d'une comparaison des listes d'opérations.
Écrire cette émulation à la main, comme le fait l'approche concurrente pour
AWS avec ses 200 000 lignes, revient donc à se tromper en un trimestre sans
savoir lequel. Trois mécanismes remplacent ce travail, et ils priment sur
toute autre considération de conception.
Le scan de surface lit le SDK Go officiel du fournisseur, lequel est
généré depuis leur propre langage de description d'interface et donc exact.
Aucun appel réseau, aucune supposition.
La ligne de base est versionnée. Une opération qui apparaît chez le
fournisseur et que personne n'a triée fait échouer l'intégration continue.
Le statut obtenu n'est pas « pas encore supporté » mais « non tranché », ce
qui est une information différente et bien plus utile.
Les suites de conformité rejouent les vrais clients, à savoir scw, octl,
exo, Terraform et OpenTofu, sur chaque proposition de modification. Un travail
hebdomadaire lance le scan et ouvre une demande de fusion dès que la surface
amont bouge ; le travail humain se réduit au triage.
Les trois fournisseurs n'entrent pas en collision dans l'espace des URL,
et c'est ce qui rend le cas multi-cloud pratique. Scaleway sert
/<produit>/v<N>/…, Outscale répond sur POST /api/v1/<Action>, Exoscale
utilise /v2/<ressource>.
Un seul multiplexeur HTTP héberge donc les trois packs, et le serveur
refuse de démarrer si deux packs revendiquent le même motif de route. Une
collision est un défaut qui doit apparaître au démarrage, jamais sous la
forme d'une requête servie par le mauvais pack.
Pour vous, la conséquence tient en une phrase : un processus, un point
d'entrée, une seule chose à démarrer dans un pipeline.
L'architecture tient en deux répertoires. Le cœur sait comment un cloud émulé
se comporte ; les packs savent comment ce cloud le dit.
La règle est absolue : le cœur ne doit jamais savoir qu'un fournisseur
existe, ni par son nom, ni par un préfixe, ni par un cas particulier. Elle vaut
son prix parce que les violations sont silencieuses. Le surveillant
d'événements de machines a un jour filtré sur trois préfixes de fournisseurs
écrits en dur dans le cœur. Rien n'échouait. Simplement, un quatrième pack
aurait dû modifier le cœur pour que ses propres événements soient rapportés.
Le test à appliquer à n'importe quelle ligne d'un pack tient en une
question : cette ligne pourrait-elle s'écrire à l'identique pour un autre
fournisseur ? Si oui, elle appartient au cœur. Ce qui reste dans le pack
est ce que seul ce fournisseur sait : son catalogue d'images, le compte de
connexion de ses machines, le champ sous lequel son API publie une adresse, ou le
fait qu'elle n'en publie aucune.
Le schéma rassemble les deux sections qui précèdent. Suivez une requête de
gauche à droite : les clients officiels parlent tous au même port, le
pack du fournisseur reconnaît sa forme d'URL et traduit la requête en
champs, puis le cœur neutre applique la même séquence pour les trois
clouds. Le runtime Incus, relié en pointillé, n'intervient que si vous demandez
de vraies machines.
Les formes diffèrent dans les packs, le comportement est écrit une seule fois dans le cœur.Source · SVG
C'est la distinction la plus fine de cette architecture, et la confondre coûte
cher dans les deux sens.
Les formes doivent différer. Scaleway répond un objet server, Outscale un
tableau Vms accompagné d'un contexte de réponse, Exoscale une opération
asynchrone. Aplatir tout cela en une forme unique détruirait l'intérêt même du
projet : chaque client doit retrouver son cloud.
Le comportement, lui, ne doit pas différer. Allumer une machine suit partout
la même séquence : produire la configuration d'amorçage si le client n'en a pas
fourni, nommer et étiqueter la machine, tenir ce nom hors de portée de l'API,
publier l'adresse, la retirer à l'arrêt, et se dégrader sans casser le plan de
contrôle quand aucun runtime n'est configuré. Écrite deux fois, un défaut corrigé
d'un côté survit de l'autre, et c'est arrivé.
La variation prend donc la forme d'un champ plutôt que d'une duplication :
un préfixe, un compte de connexion, une clé d'adresse. Trois packs, une seule
séquence, aucune copie.
Quand un pack ne sert pas une opération, un client rencontre le refus, et il
doit pouvoir distinguer une opération non servie d'une ressource absente.
Sans cette distinction, un refus se lit comme une réponse vide, et une
exécution verte prouve alors quelque chose de faux.
Le problème est que aucun statut et aucun corps ne conviennent aux trois
fournisseurs, et c'est une mesure plutôt qu'une préférence.
Pack
Statut
Pourquoi celui-là
Scaleway
501
leur SDK ne mappe pas ce type, donc il ne peut pas le confondre avec une ressource absente
Outscale
404
leur enveloppe a un champ où loger le marqueur, et un 501 coûte 12 secondes de retries à leur CLI
Exoscale
404
leur enveloppe n'a nulle part où loger un marqueur, et un 501casse la création d'instance
Glissez pour voir
Le cas Exoscale est celui qui tranche : leur CLI appelle une opération de DNS
inverse après chaque création et traite tout ce qui n'est pas un 404 comme
fatal. Le statut sur lequel un programme pourrait brancher est donc exactement
celui qui casse le client. La solution est passée hors bande, avec un
en-tête qu'aucun vrai cloud n'envoie :
X-Feint-Not-Emulated: exoscale
Il est posé une seule fois, dans la couche partagée, avec le nom du pack
lu dans la table de montage du processus et jamais dans le chemin envoyé par
le client. Il ne marque jamais un 404 ordinaire, sinon le marqueur ne
signifierait plus rien.
Aucune dépendance, et c'est un argument de sécurité
Le fichier go.mod fait trois lignes, et un contrôle avant chaque commit le
maintient ainsi. Le routage, le JSON et l'analyse du code Go viennent tous de la
bibliothèque standard.
Ce n'est pas du minimalisme pour lui-même. Un émulateur qui tourne dans
l'intégration continue de tout le monde est une surface de chaîne
d'approvisionnement, et la façon la moins chère de sécuriser une dépendance
reste de ne pas l'avoir. Toute nouvelle dépendance doit être justifiée dans
la demande de fusion qui l'ajoute. C'est la même logique qui gouverne la
vérification des binaires publiés, détaillée dans Installer
Feint.
Vérifiez que l'essentiel de ce guide est acquis. Les questions portent
uniquement sur ce qui vient d'être expliqué ici.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
6 questions
6 min.
70% requis
Informations
Le chronomètre démarre au clic sur Démarrer
Questions à choix multiples, vrai/faux et réponses courtes
Vous pouvez naviguer entre les questions
Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
⏱️--:--
0 / 6
Vérification
(0/0)
--:--
0%
0Correctes
0À revoir
0:00Temps
-Niveau
Score par domaine
Un domaine regroupe plusieurs guides et reçoit plusieurs questions : son score est plus fiable qu'un score par thème, qui porte souvent sur une seule question.
Bilan
Points forts
Aucun sujet réussi à 80 % sur au moins deux questions pour l’instant.