feint est un émulateur local des API cloud européennes : il répond à
la place de Scaleway, Outscale et Exoscale sur 127.0.0.1:4599, et
vos clients officiels ne font pas la différence. Un binaire Go statique, un
port, aucun compte et aucune facture. Ce guide montre comment l'installer en
vérifiant ce que vous exécutez, brancher scw, oapi-cli, exo et
Terraform dessus, puis obtenir de vraies machines derrière l'API. Public
visé : développeurs et équipes plateforme qui testent du code cloud sans vouloir
payer un compte pour chaque exécution.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Installer feint en vérifiant la signature Sigstore et la provenance du binaire.
- Diagnostiquer l'hôte avant de démarrer, avec
feint doctor. - Savoir quand une nouvelle version est publiée, sans appel réseau imposé.
- Lire ce que l'émulateur a servi, sur la page qu'il expose lui-même.
- Mesurer ce qu'un vrai client attend, avec le proxy d'enregistrement.
- Brancher les trois CLI officiels sans copier une variable à la main.
- Appliquer une configuration Terraform contre l'émulateur.
- Faire tourner de vraies machines qui portent l'adresse publiée par l'API.
- Ouvrir une session SSH sur une machine émulée, chez les trois fournisseurs.
- Installer Incus et OVN sur Debian 13, câblage compris.
- Situer la couverture réelle de chaque provider avant de vous appuyer dessus.
Pourquoi les clouds européens n'avaient pas d'émulateur
Section intitulée « Pourquoi les clouds européens n'avaient pas d'émulateur »AWS a LocalStack, Azure a Azurite, et les clouds européens n'avaient rien. Concrètement, une équipe qui écrit du Terraform Scaleway ou du code SDK Outscale teste contre un compte payant, ou ne teste pas. Le premier choix transforme chaque exécution de CI en ligne de facture et chaque développeur en propriétaire de ressources oubliées ; le second laisse les erreurs remonter en production.
Un émulateur répond à ce besoin précis : il rejoue le protocole du fournisseur pour que le client officiel, celui que vous utiliserez vraiment, fonctionne sans quitter votre machine. Le site couvre déjà l'équivalent côté AWS avec Floci : la logique est la même, seul le périmètre change.
feint sert pour le moment trois fournisseurs sur un seul port. Les espaces
d'URL ne se chevauchent pas, ce qui rend la cohabitation possible : Scaleway
sert /<produit>/v<N>/…, Outscale répond en POST /api/v1/<Action>, Exoscale
expose /v2/<ressource>. Un seul multiplexeur HTTP les héberge tous les trois,
et le serveur refuse de démarrer si deux paquets revendiquent la même route.
Prérequis
Section intitulée « Prérequis »- Une machine Linux ou macOS en x86-64 ou ARM64.
cosignetjqpour la vérification d'installation,ghen option.- Les CLI officiels que vous voulez piloter :
scw,oapi-cli,exo, Terraform ou OpenTofu. - Incus 6.0.4 minimum (7.2 recommandé) uniquement pour le mode machines réelles ; la procédure Debian 13, OVN compris, figure dans ce guide.
Rien de tout cela n'est nécessaire pour la partie principale : l'émulateur est un binaire statique sans dépendance, il tient son état en mémoire et n'a besoin d'aucun démon.
Comment installer feint et vérifier ce qu'on exécute
Section intitulée « Comment installer feint et vérifier ce qu'on exécute »Téléchargez le binaire de la version, vérifiez qui l'a publié, puis vérifiez
les octets. L'ordre compte : une somme de contrôle ne prouve rien si vous ne
savez pas qui a produit la liste qui la contient. La release v0.8.0 publie
les binaires, un fichier checksums.txt, sa signature Sigstore et une
attestation de provenance SLSA.
-
Récupérer les artefacts de la version.
Fenêtre de terminal base=https://github.com/stephrobert/feint/releases/download/v0.8.0curl -fsSLO "$base/feint-linux-amd64"curl -fsSLO "$base/checksums.txt"curl -fsSLO "$base/checksums.txt.cosign.bundle" -
Vérifier la signature de la liste de sommes, avant de faire confiance à une seule ligne de son contenu.
Fenêtre de terminal cosign verify-blob --bundle checksums.txt.cosign.bundle \--certificate-identity-regexp '^https://github\.com/stephrobert/feint/\.github/workflows/release\.yml@refs/tags/v' \--certificate-oidc-issuer https://token.actions.githubusercontent.com \checksums.txtLa sortie attendue tient en deux mots :
Verified OK. Toute autre réponse doit arrêter l'installation. Notez la précision du motif d'identité : il nomme le workflow de publication et le préfixe de tag, là où un motif large accepterait n'importe quel workflow du dépôt. Un dépôt compromis dont un workflow secondaire signerait un binaire ne passerait pas ce contrôle. -
Vérifier les octets contre la liste signée.
Fenêtre de terminal sha256sum -c checksums.txt --ignore-missingLe résultat attendu est
feint-linux-amd64: OK. Sans--ignore-missing, la commande échoue sur toutes les plateformes que vous n'avez pas téléchargées, ce qui ressemble à tort à un binaire corrompu. -
Installer le binaire et confirmer la version.
Fenêtre de terminal install -m 0755 feint-linux-amd64 ~/.local/bin/feintfeint versionLa sortie doit afficher
v0.8.0.
Si vous préférez la provenance à la signature, gh vérifie quel workflow et
quel commit ont produit le binaire :
gh attestation verify feint-linux-amd64 --repo stephrobert/feintComment lancer feint en conteneur dans une CI
Section intitulée « Comment lancer feint en conteneur dans une CI »Une image est publiée à chaque version, et elle sert le plan de contrôle seul. C'est la façon la plus courte de brancher l'émulateur sur un pipeline : un service, un port, aucun binaire à installer sur le runner.
docker run --rm -p 127.0.0.1:4599:4599 \ ghcr.io/stephrobert/feint:v0.8.0@sha256:f19c61d60cfbd57e654d530c2c1d06090a4670ad7d26932bb9ff21a06b3f2fc3curl -s http://127.0.0.1:4599/_feint/health | jq -c '{status, machines}'{"status":"ok","machines":"none"}L'image ne fait pas tourner de machines, et elle le dit : elle exécute
feint serve --vm off, parce que les machines réelles restent une propriété du
binaire sur un hôte Incus. Une image qui prétendrait le contraire serait
précisément la demi-vérité que ce projet refuse ailleurs. Pour les vraies
machines, voyez la page machines
réelles.
Dans un pipeline, l'image se déclare comme un service ordinaire :
services: feint: image: ghcr.io/stephrobert/feint:v0.8.0@sha256:f19c61d60cfbd57e654d530c2c1d06090a4670ad7d26932bb9ff21a06b3f2fc3 ports: - 4599:4599Le runner retient les étapes jusqu'à ce que le contrôle de santé de l'image réponde, donc la première étape peut parler à l'émulateur immédiatement.
services: - name: ghcr.io/stephrobert/feint:v0.8.0@sha256:f19c61d60cfbd57e654d530c2c1d06090a4670ad7d26932bb9ff21a06b3f2fc3 alias: feintL'image se vérifie comme les binaires, avec la même identité de workflow :
cosign verify ghcr.io/stephrobert/feint:v0.8.0 \ --certificate-identity-regexp '^https://github\.com/stephrobert/feint/\.github/workflows/release\.yml@refs/tags/v' \ --certificate-oidc-issuer https://token.actions.githubusercontent.comComment vérifier que l'hôte est prêt
Section intitulée « Comment vérifier que l'hôte est prêt »feint doctor inspecte la machine avant que vous ne perdiez du temps. Il
contrôle le port, le runtime de machines disponible et ce qu'il peut
prouver, la présence des clients officiels, et il signale les pièges connus
de l'environnement.
feint doctor 
La lecture est directe : ok valide un point, warn signale quelque
chose qui n'empêche pas de travailler. Sur la capture ci-dessus, deux
avertissements méritent une explication. Le premier, no contracts/ directory here, indique que les réponses ne seront pas confrontées aux descriptions
d'API des fournisseurs, ce qui n'arrive que si vous lancez feint depuis le
dépôt cloné. Le second, le ProxyJump sur 10.*, est un piège réel :
cette plage est celle des réseaux privés émulés, et une règle SSH trop large
fait échouer la connexion avec timed out during banner exchange alors que le
serveur SSH écoute normalement.
Un avertissement ne fait jamais échouer doctor. Seul un élément cassé
produit un code retour non nul, ce qui rend la commande utilisable telle quelle
dans un script d'amorçage.
Comment démarrer l'émulateur
Section intitulée « Comment démarrer l'émulateur »feint start détache le processus lui-même, attend qu'il réponde et indique
où sont les journaux. Aucun &, aucun conteneur, aucun gestionnaire de
services : un binaire Go statique sait se mettre en arrière-plan, là où un
émulateur écrit en Java ou en Python délègue cette tâche à docker run -d.
feint startfeint listening on 127.0.0.1:4599 (pid 1155265) logs: /run/user/1000/feint/127.0.0.1_4599/feint.logL'état se lit avec feint status, qui répond ce qui tourne, ce qui est
monté et ce qu'un client a réellement piloté depuis le démarrage :
feint statusrunning on 127.0.0.1:4599 (pid 2667884, since 2026-08-10T19:35:43Z) resources 12 machines none
provider routes driven by a client outscale 72 3 scaleway 57 7 exoscale 46 3La colonne driven by a client est plus utile qu'elle n'en a l'air : elle
distingue une route montée d'une route exercée, donc elle vous dit ce
que votre test a vraiment traversé. Ici, sept routes Scaleway ont été
traversées par les commandes scw de la section suivante, sur les 57 servies.
Les autres verbes du cycle de vie sont feint stop, feint restart,
feint logs et feint wait. Ce dernier interroge l'émulateur jusqu'à ce qu'il
réponde : c'est le verbe de CI, celui qui remplace la boucle curl que
chaque équipe finissait par écrire.
Quand un runtime de machines est actif, la ligne machines porte en plus ce
que le mode sait prouver, incus-ovn (isolation: true) par exemple, ce qui
évite d'aller lire l'API de santé pour une information qu'on veut d'un coup
d'œil.
Les commandes, en un coup d'œil
Section intitulée « Les commandes, en un coup d'œil »Le binaire porte vingt-et-un verbes, dont la moitié sert au quotidien et l'autre à mesurer l'émulateur lui-même. Le tableau les sépare selon cet usage, pour savoir tout de suite lesquels vous concernent.
| Commande | Ce qu'elle fait | Usage |
|---|---|---|
feint serve | Sert les trois clouds au premier plan | courant |
feint start / stop / restart | Même chose en arrière-plan, et l'arrêt | courant |
feint wait | Interroge jusqu'à ce qu'il réponde | CI |
feint status | Ce qui tourne, ce qui est monté, ce qu'un client a piloté | courant |
feint logs | Le journal de l'exécution détachée | courant |
feint ui | Ouvre la page de l'émulateur, en lecture seule | courant |
feint env <fournisseur> | L'environnement d'un client officiel, pour eval | courant |
feint doctor | Diagnostique l'hôte : port, runtime, clients, piège SSH | courant |
feint snapshot | save, load, list, rm de l'état courant | courant |
feint clean | Retire machines, réseaux et règles créés par l'émulateur | courant |
feint version | Affiche la version, --check compare à la dernière | courant |
feint catalog | Imprime l'inventaire émulé qu'un client lit avant de créer | inspection |
feint probe | Pilote chaque route montée depuis sa description d'API | inspection |
feint coverage | Compare la surface amont à ce que les paquets servent | mesure |
feint proxy | S'intercale entre un client et un cloud, et enregistre | mesure |
feint transcript | Relit un enregistrement par verbes | mesure |
feint shapes | Enregistre et vérifie l'arbre des champs d'un vrai cloud | mesure |
feint evidence | Écrit l'artefact de couverture que la CI conserve | projet |
feint docs | Régénère les tableaux de couverture du dépôt | projet |
Comment brancher le CLI Scaleway
Section intitulée « Comment brancher le CLI Scaleway »feint env scaleway produit l'environnement dont le client officiel a
besoin. La commande n'écrit que des lignes export sur la sortie standard, ce
qui rend eval sûr ; les remarques et avertissements partent sur la sortie
d'erreur.
eval "$(feint env scaleway)"scw instance server create name=web-01 type=DEV1-S image=ubuntu_jammy zone=fr-par-1scw instance server list zone=fr-par-1 
Les variables produites pointent SCW_API_URL sur http://127.0.0.1:4599
et fournissent des identifiants bien formés mais fictifs. C'est suffisant :
les SDK valident la forme des identifiants côté client avant d'émettre
quoi que ce soit, et l'émulateur ne vérifie aucune signature.
Le serveur créé apparaît immédiatement en running dans la liste, alors que
le protocole renvoie bien stopped à la création. L'explication n'est
pas dans l'émulateur : scw instance server create envoie une action de
démarrage juste après la création. Interrogé directement, l'émulateur répond
ce que répondrait Scaleway :
curl -s -X POST "http://127.0.0.1:4599/instance/v1/zones/fr-par-1/servers" \ -H 'Content-Type: application/json' \ -d '{"name":"etat-initial","commercial_type":"DEV1-S","image":"ubuntu_jammy"}' \ | jq -c '{name: .server.name, state: .server.state}'{"name":"etat-initial","state":"stopped"}Le stockage bloc et la séquence d'image dorée
Section intitulée « Le stockage bloc et la séquence d'image dorée »Depuis la 0.8.0, Scaleway sert aussi block, soit les volumes, leurs
instantanés et le catalogue de types. Le volume se crée avec le client officiel,
et deux détails de forme méritent d'être connus parce qu'ils font échouer la
commande avant même d'atteindre l'émulateur.
scw block volume create name=donnees from-empty.size=10G perf-iops=5000 zone=fr-par-1{"name":"donnees","type":"sbs","size":10000000000,"class":"sbs","iops":5000,"status":"available"}La taille se note en 10G, un nombre d'octets étant refusé par le CLI là où
la commande instance l'accepte, et perf-iops est obligatoire. Un détail
d'implémentation vaut d'être signalé pour qui écrit un script : scw interroge
/block/v1alpha1 quand le provider Terraform interroge /block/v1. Les deux
orthographes répondent, ce qui évite d'avoir à choisir entre deux clients
officiels du même cloud.
La séquence d'image dorée est servie de bout en bout : un instantané du volume, une image taillée dans cet instantané, puis la suppression dans l'ordre que l'API impose.
snap=$(scw instance snapshot create name=snap-source volume-id="$vol" zone=fr-par-1 -o json | jq -r .id)img=$(scw instance image create name=image-doree snapshot-id="$snap" arch=x86_64 zone=fr-par-1 -o json | jq -r .id)scw instance image list zone=fr-par-1["image-doree","ubuntu_jammy","debian_bookworm","debian_trixie","alpine","ubuntu_noble"]L'image que vous créez apparaît à côté du catalogue figé, et l'ordre de suppression est celui du vrai cloud : tant que l'image existe, l'instantané dont elle est tirée refuse de partir, avec un message qui nomme le coupable.
{"precondition":"resource_still_in_use","resource":"snapshot", "help_message":"the image 7f1db7e3-… is cut from this snapshot"}C'est exactement l'ordre que Terraform parcourt quand un même plan retire les deux, ce qui rend ce refus utile plutôt que gênant. Une image taillée ici ne démarre toutefois rien : les octets d'un disque sont la seule chose qu'un émulateur ne peut pas fournir, et la limite est signalée au démarrage plutôt qu'à la création.
Comment brancher Outscale et Exoscale
Section intitulée « Comment brancher Outscale et Exoscale »Les deux autres fournisseurs se branchent de la même façon, avec une nuance
par client. feint env la signale sur la sortie d'erreur au lieu de vous
laisser la découvrir.
Le client oapi-cli lit un profil JSON plutôt que l'environnement. La
remarque affichée par feint env outscale le précise : il faut lui passer
--config avec endpoints.api sur http://127.0.0.1:4599, le client
ajoutant /api/v1 de lui-même.
eval "$(feint env outscale)"oapi-cli CreateNet --IpRange 10.0.0.0/16oapi-cli ReadNets{ "Nets":[ { "IpRange":"10.0.0.0/16", "NetId":"vpc-3a31b260", "State":"available", "Tags":[], "Tenancy":"default" } ], "ResponseContext":{"RequestId":"3b25f637-a288-4839-b4aa-c3b1a709f6bb"}}Le CLI exo prend son point d'accès dans son fichier de
configuration, où endpoint doit valoir http://127.0.0.1:4599/v2. Notez le
suffixe /v2, qui fait partie de l'adresse chez ce fournisseur.
eval "$(feint env exoscale)"exo compute instance-type list| ID | FAMILY | SIZE ||--------------------------------------|----------|-------|| 21624abb-764e-4def-81d7-9fc54b5957fb | standard | tiny || b6cd1ff5-3a2f-4e9d-a4d1-8988c1191fe8 | standard | small |Deux types d'instances seulement : c'est le catalogue figé de l'émulateur, pas l'inventaire d'Exoscale. La section sur les limites détaille ce point.
Les quotas répondent aussi, et ils sont plus intéressants qu'ils n'en ont
l'air : la limite est une valeur inventée, comme le catalogue, mais l'usage
est compté depuis le magasin interne. Un exo limits sur un émulateur vierge
annonce zéro instance, et un de plus après chaque création.
exo limits| RESOURCE | USED | MAX ||----------------------------|------|-----|| Compute instances | 0 | 100 || Compute instance snapshots | 0 | 100 || Compute instance templates | 0 | 100 |Comment appliquer une configuration Terraform
Section intitulée « Comment appliquer une configuration Terraform »Terraform et OpenTofu s'appliquent contre l'émulateur sur Scaleway et
Outscale, et le provider Exoscale est refusé volontairement pour éviter un
apply à cheval sur un compte facturé. Scaleway se détourne avec api_url,
Outscale avec un bloc api dont le chemin porte /api/v1, et le cycle complet
passe, second plan vide compris.
Comment voir ce que l'émulateur a réellement servi
Section intitulée « Comment voir ce que l'émulateur a réellement servi »Le binaire sert sa propre page, à http://127.0.0.1:4599/_feint/ui, ouverte
par feint ui. Elle montre côte à côte ce qui est monté, ce qui a été
sondé et ce qu'un vrai client a piloté, sans jamais les additionner,
plus l'inventaire de la session et un journal des appels. Le même anneau
d'événements se lit par script sur /_feint/trace, et feint proxy enregistre
ce qu'un client envoie à un vrai cloud.
Comment obtenir de vraies machines derrière l'API
Section intitulée « Comment obtenir de vraies machines derrière l'API »Avec un runtime Incus, un serveur créé par l'API devient une machine réelle
qui porte l'adresse publiée, applique les groupes de sécurité et accepte une
session SSH. Quatre modes existent et ne délivrent pas la même chose : seul
--vm incus-ovn isole deux VPC, au prix d'une adresse privée que l'hôte ne
joint plus.
Comment savoir qu'une nouvelle version est sortie
Section intitulée « Comment savoir qu'une nouvelle version est sortie »feint version --check demande à GitHub si une version plus récente existe,
et affiche la commande pour l'installer. Deux
principes gouvernent cette commande, et ils méritent d'être connus avant de la
lancer : rien ne part sur le réseau tant que le drapeau n'est pas tapé, et
le binaire ne se met jamais à jour tout seul.
feint version --checkTrois réponses sont possibles selon ce que vous exécutez. Quand une version plus récente est publiée, la sortie donne la commande d'installation épinglée sur cette version précise :
a newer release is available: v0.8.0
base=https://github.com/stephrobert/feint/releases/download/v0.8.0 curl -fsSLO "$base/feint-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/; s/aarch64/arm64/')" curl -fsSLO "$base/checksums.txt" sha256sum -c checksums.txt --ignore-missing
release notes: https://github.com/stephrobert/feint/releases/tag/v0.8.0La commande proposée nomme la version, jamais latest. La raison est la
même que dans la procédure d'installation plus haut : une référence mutable
télécharge ce qui est le plus récent au moment de l'appel, et ce contenu ne peut
plus être confronté à la somme de contrôle écrite juste en dessous.
Si vous êtes déjà à jour, la commande rappelle d'abord votre version, puis conclut en une ligne :
v0.8.0this is the latest releaseLe troisième cas concerne les binaires construits localement :
the latest release is v0.8.0 (this build reports "dev", which is not a released version) https://github.com/stephrobert/feint/releases/tag/v0.8.0Un binaire compilé depuis les sources porte dev, et une installation par
go install porte une pseudo-version horodatée. Ni l'un ni l'autre ne se
compare à une étiquette de version, donc l'outil annonce la dernière release
sans prétendre que votre exemplaire est périmé.
Ce que feint ne fait pas
Section intitulée « Ce que feint ne fait pas »La couverture est partielle, et elle est mesurée plutôt qu'annoncée. En v0.8.0, 220 routes sont montées au total. Le tableau reprend la maturité déclarée par le projet et la façon dont chaque fournisseur découpe la surface que son API publie :
| Fournisseur | Routes montées | Servi | Décliné | Non trié | Maturité | Prouvé par, en CI |
|---|---|---|---|---|---|---|
| Scaleway | 102 | 32 % | 67 % | 0 % | utilisable | Terraform, OpenTofu, scw |
| Outscale | 72 | 27 % | 65 % | 6 % | démarrage | Terraform, OpenTofu, oapi-cli |
| Exoscale | 46 | 12 % | 67 % | 20 % | démarrage | exo |
Les trois colonnes de pourcentage se lisent ensemble, et la troisième est celle qui compte. Décliné est une décision écrite : une opération que personne n'a l'intention d'émuler, avec sa raison dans le code. Non trié désigne ce sur quoi personne n'a encore statué, et Scaleway y est à zéro : chaque opération de sa surface a reçu un verdict. Une opération qui apparaît dans cette colonne fait échouer l'intégration continue tant qu'un humain n'a pas tranché.
Les dénominateurs diffèrent d'un fournisseur à l'autre, 315 opérations publiées côté Scaleway contre 263 côté Outscale et 374 côté Exoscale : comparer les pourcentages entre colonnes d'une même ligne a du sens, les comparer d'une ligne à l'autre beaucoup moins. Servi et non mesuré est l'état le moins défendable pour une route, c'est la logique du projet.
Lisez « prouvé par » au sens strict : ce sont les clients qu'un workflow pilote à chaque proposition de modification. Une suite qui existe dans le dépôt mais que l'intégration continue n'exécute pas n'y figure pas, la colonne étant désormais générée depuis le fichier de workflow lui-même.
Utilisable signifie qu'une configuration réaliste s'applique et se détruit.
Démarrage veut dire que le protocole est juste et qu'un vrai client mène une
charge de travail réelle, mais que la surface reste mince. Concrètement,
Scaleway et Outscale supportent aujourd'hui un cycle Terraform complet, et
Exoscale se pilote au CLI exo, le partage d'appels de son provider
Terraform étant décrit plus haut. Les trois ouvrent une session SSH sur une
machine réelle.
Cinq limites méritent d'être connues avant de vous appuyer sur l'outil. Elles sont toutes vérifiables en quelques commandes.
Les identifiants ne sont validés contre rien. Une création qui nomme une image inexistante réussit, là où le vrai cloud refuserait :
scw instance server create name=fantome type=DEV1-S \ image=00000000-dead-beef-0000-000000000000 zone=fr-par-1C'est délibéré, parce que l'émulateur n'a pas d'inventaire : refuser les identifiants inconnus casserait toute configuration qui référence une image de production. Le coût est réel : une faute de frappe dans un identifiant d'image passera ici et sera rattrapée en production.
En revanche, le démarrage refuse. Avec un runtime de machines, un
identifiant que nul catalogue ne connaît ne fait plus booter une image de
substitution : le serveur reste stopped et le journal nomme l'identifiant en
cause.
level=ERROR msg="refusing to boot: the image identifier resolves to nothing thisemulator can run" provider=scaleway image=00000000-dead-beef-0000-000000000000reason="the identifier is in no catalogue"La distinction est celle qui compte pour un test : la création reste permise pour ne pas casser une configuration réelle, mais l'émulateur refuse de faire passer pour Ubuntu une image que vous n'avez pas demandée.
Le catalogue est une fiction. Types de serveurs, prix, images et zones forment une petite table figée. Elle existe parce que les clients la lisent avant de créer quoi que ce soit, mais toute réponse de capacité, de prix ou de disponibilité est décorative.
L'authentification est acceptée, jamais vérifiée. Aucune signature n'est contrôlée, sur aucun fournisseur :
curl -s -o /dev/null -w '%{http_code}\n' \ "http://127.0.0.1:4599/instance/v1/zones/fr-par-1/servers"La réponse est 200, sans le moindre jeton. feint ne doit donc jamais
être exposé sur un réseau que vous ne maîtrisez pas : c'est un outil de
développement qui accorde tout à tout le monde, par construction.
L'outil ne se contente d'ailleurs pas d'écouter sur 127.0.0.1 par défaut :
feint serve refuse une adresse hors boucle locale tant que
--expose-to-network n'est pas passé explicitement. La raison est mécanique
plutôt que morale : hors loopback, la protection contre le détournement de
DNS local ne peut plus distinguer ce qui est local, donc elle cesse de
protéger quoi que ce soit. Avec un runtime de machines actif, ce qui devient
alors joignable depuis le réseau est un moteur de conteneurs.
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 en revanche préservés : supprimer un serveur démarré est refusé avec
{"type":"transient_state"}, parce que Terraform s'appuie sur cette erreur.
Le stockage objet n'est pas émulé. Le provider Terraform Scaleway construit
l'adresse S3 en dur dans son code, donc la détourner demanderait une
interception DNS et un certificat TLS accepté par le provider. Le CLI et les
SDK, eux, honorent SCW_S3_ENDPOINT et peuvent déjà pointer vers un MinIO
local.
Dépannage
Section intitulée « Dépannage »| Symptôme | Cause | Solution |
|---|---|---|
404 Not Found sur scw instance server-type list | Le CLI interroge /product-catalog/v2alpha1/, une API récente que l'émulateur ne monte pas | Utiliser scw marketplace local-image list, ou consulter curl -s localhost:4599/_feint/routes |
Feint does not serve /marketplace/v2/images | La route demandée n'existe pas dans le paquet ; le message le dit explicitement | Vérifier la route dans /_feint/routes avant d'insister |
feint: no contract under contracts sur feint probe | probe a besoin des descriptions d'API livrées avec le dépôt | Lancer depuis le dépôt cloné, ou passer --contracts <répertoire> |
warn no contracts/ directory here dans doctor | Même cause, en avertissement | Sans effet si vous ne validez pas les réponses contre les contrats |
gh attestation verify ne renvoie rien | Hors terminal interactif, la commande ne s'exprime que par son code retour | Contrôler echo $? ou ajouter --format json |
timed out during banner exchange en SSH vers une machine | Un ProxyJump du fichier ~/.ssh/config capture la plage 10.* des réseaux émulés | Restreindre le motif Host, ou utiliser ssh -F /dev/null |
Multiple variable sources detected avec Terraform | Un profil Scaleway existe déjà sur le poste | Lire la colonne Currently using : le bloc provider l'emporte |
Un mode --vm ne sépare pas deux VPC | Le mode pont ne fournit pas l'isolation | Lire capabilities.isolation dans /_feint/health, et passer en --vm incus-ovn |
the Exoscale Terraform provider only honours… en 400 | Ce provider partage ses appels entre l'émulateur et le vrai cloud | Utiliser le CLI exo, ou assumer le partage avec FEINT_EXOSCALE_ALLOW_TERRAFORM=1 |
| Terraform Outscale réessaie pendant six minutes puis expire | Le endpoint du bloc api ne porte pas le segment /api/v1 | Écrire http://127.0.0.1:4599/api/v1, version comprise |
feint serve refuse l'adresse demandée | Une adresse hors boucle locale est refusée par défaut | Rester sur 127.0.0.1, ou passer --expose-to-network en connaissance de cause |
REMOTE HOST IDENTIFICATION HAS CHANGED en SSH | Les adresses sont réattribuées depuis le début du bloc à chaque lab | Ajouter -o UserKnownHostsFile=/dev/null, ou purger l'entrée avec ssh-keygen -R <adresse> |
| Une adresse privée ne répond pas depuis l'hôte | Le routeur OVN traduit les connexions venues de l'hôte | Lire capabilities.private_from_host, ou passer par l'adresse publique |
La page /_feint/ui répond 404 | Elle n'est montée que sur la boucle locale | L'ouvrir depuis la machine qui exécute l'émulateur |
À retenir
Section intitulée « À retenir »- feint émule Scaleway, Outscale et Exoscale sur un seul port,
127.0.0.1:4599, sans compte ni facture. - Une image de conteneur signée branche l'émulateur sur une CI en trois lignes, plan de contrôle seul.
- Un binaire Go statique qui se détache seul : ni Docker, ni démon, ni dépendance externe.
- Les CLI officiels fonctionnent tels quels :
feint env <fournisseur>produit l'environnement attendu,evalsuffit. - Terraform pilote Scaleway et Outscale de bout en bout,
apply, second plan vide etdestroycompris. - Le provider Terraform Exoscale est refusé en 400 : il partagerait l'apply entre l'émulateur et un compte facturé.
feint uisert une page depuis le binaire : servi contre piloté contre sondé, jamais additionnés, en lecture seule et sur la boucle locale.feint proxyetfeint transcriptmesurent ce qu'un vrai client appelle et la forme exacte des réponses, identifiants caviardés.- Le mode machines est réel : le conteneur porte l'adresse publiée par l'API, et
feint cleanne retire que ce que l'émulateur a créé. - On ouvre une session SSH sur une machine émulée chez les trois fournisseurs, à l'adresse que l'API publie.
- Seul
--vm incus-ovnisole deux VPC, au prix d'une adresse privée que l'hôte ne joint plus ; interrogezcapabilitiesplutôt que de supposer. feint version --checksignale une nouvelle version et donne la commande épinglée ;FEINT_NO_UPDATE_CHECK=1coupe tout appel réseau.- La couverture est partielle et assumée : 220 routes montées, 32 % de la surface Scaleway servie, 27 % chez Outscale, 12 % chez Exoscale.
- La surface non triée est mesurée : 0 % en attente de décision chez Scaleway, 6 % chez Outscale, 20 % chez Exoscale.
- Aucune signature n'est vérifiée, et
feint serverefuse une adresse hors boucle locale sans--expose-to-network.